From 8288da587aadfd7a001ff9a3ac2d1eae26e3e0e5 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 6 Apr 2018 12:51:20 +0200 Subject: [PATCH 001/122] initial checkin --- .gitignore | 76 +++ core/pom.xml | 102 ++++ .../aecu/core/models/HelloWorldModel.java | 48 ++ .../de/valtech/aecu/core/package-info.java | 19 + .../aecu/core/models/TestHelloWorldModel.java | 60 ++ pom.xml | 553 ++++++++++++++++++ ui.apps/pom.xml | 157 +++++ .../main/content/META-INF/vault/filter.xml | 5 + .../content/jcr_root/META-INF/MANIFEST.MF | 3 + .../main/content/jcr_root/apps/.content.xml | 4 + .../clientlibs/clientlib-base/.content.xml | 6 + .../aecu/clientlibs/clientlib-base/css.txt | 15 + .../aecu/clientlibs/clientlib-base/js.txt | 15 + .../content/breadcrumb/.content.xml | 6 + .../aecu.xml | 5 + 15 files changed, 1074 insertions(+) create mode 100644 .gitignore create mode 100644 core/pom.xml create mode 100644 core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java create mode 100644 core/src/main/java/de/valtech/aecu/core/package-info.java create mode 100644 core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java create mode 100644 pom.xml create mode 100644 ui.apps/pom.xml create mode 100644 ui.apps/src/main/content/META-INF/vault/filter.xml create mode 100644 ui.apps/src/main/content/jcr_root/META-INF/MANIFEST.MF create mode 100644 ui.apps/src/main/content/jcr_root/apps/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/breadcrumb/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4c231e47 --- /dev/null +++ b/.gitignore @@ -0,0 +1,76 @@ +# Created by https://www.gitignore.io/api/eclipse,java,maven + +### Eclipse ### +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# Eclipse Core +.project + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse + + +### Java ### +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +### Vault ### +.vlt + +### IntelliJ ### +.idea/ +*.iml diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 00000000..9431a325 --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,102 @@ + + + + 4.0.0 + + de.valtech.aecu + aecu + 1.0-SNAPSHOT + ../pom.xml + + aecu.core + bundle + aecu - Core + Core bundle for aecu + + + + org.apache.sling + maven-sling-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + + javax.inject;version=0.0.0,* + + de.valtech.aecu.core + + + + + + + + + + + org.osgi + osgi.core + + + org.osgi + osgi.cmpn + + + org.osgi + osgi.annotation + + + + org.slf4j + slf4j-api + + + javax.jcr + jcr + + + javax.servlet + servlet-api + + + com.adobe.aem + uber-jar + apis + + + org.apache.sling + org.apache.sling.models.api + + + junit + junit + + + org.mockito + mockito-core + + + junit-addons + junit-addons + + + diff --git a/core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java b/core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java new file mode 100644 index 00000000..a01cb88c --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015 Adobe Systems Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.valtech.aecu.core.models; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.Default; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.settings.SlingSettingsService; + +@Model(adaptables=Resource.class) +public class HelloWorldModel { + + @Inject + private SlingSettingsService settings; + + @Inject @Named("sling:resourceType") @Default(values="No resourceType") + protected String resourceType; + + private String message; + + @PostConstruct + protected void init() { + message = "\tHello World!\n"; + message += "\tThis is instance: " + settings.getSlingId() + "\n"; + message += "\tResource type is: " + resourceType + "\n"; + } + + public String getMessage() { + return message; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/package-info.java b/core/src/main/java/de/valtech/aecu/core/package-info.java new file mode 100644 index 00000000..eed3dc70 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/package-info.java @@ -0,0 +1,19 @@ +/* + * Copyright 2015 Adobe Systems Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@Version("1.0") +package de.valtech.aecu.core; + +import org.osgi.annotation.versioning.Version; \ No newline at end of file diff --git a/core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java b/core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java new file mode 100644 index 00000000..73cbf5e4 --- /dev/null +++ b/core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java @@ -0,0 +1,60 @@ +/* + * Copyright 2015 Adobe Systems Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.valtech.aecu.core.models; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.UUID; + +import junitx.util.PrivateAccessor; + +import org.apache.sling.settings.SlingSettingsService; +import org.junit.Before; +import org.junit.Test; + +/** + * Simple JUnit test verifying the HelloWorldModel + */ +public class TestHelloWorldModel { + + //@Inject + private HelloWorldModel hello; + + private String slingId; + + @Before + public void setup() throws Exception { + SlingSettingsService settings = mock(SlingSettingsService.class); + slingId = UUID.randomUUID().toString(); + when(settings.getSlingId()).thenReturn(slingId); + + hello = new HelloWorldModel(); + PrivateAccessor.setField(hello, "settings", settings); + hello.init(); + } + + @Test + public void testGetMessage() throws Exception { + // some very basic junit tests + String msg = hello.getMessage(); + assertNotNull(msg); + assertTrue(msg.length() > 0); + } + +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..a225c661 --- /dev/null +++ b/pom.xml @@ -0,0 +1,553 @@ + + + + 4.0.0 + de.valtech.aecu + aecu + pom + 1.0-SNAPSHOT + aecu + + + core + ui.apps + + + + localhost + 4502 + localhost + 4503 + admin + admin + admin + admin + + UTF-8 + UTF-8 + + + + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + [maven-scm] : + clean install + install + release + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + true + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven + + enforce + + + + + [3.3.9,) + + + Project must be compiled with Java 8 or higher + 1.8.0 + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-idea-plugin + 2.2.1 + + 1.8 + true + true + + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.10 + + true + + + + + + + + org.apache.maven.plugins + maven-clean-plugin + 3.0.0 + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.2 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.2 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.20 + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + + org.apache.sling + maven-sling-plugin + 2.2.0 + + http://${aem.host}:${aem.port}/system/console + WebConsole + + + + + org.apache.sling + htl-maven-plugin + 1.0.6 + + true + + + + + validate + + + + + + + com.day.jcr.vault + content-package-maven-plugin + 0.5.1 + + http://${aem.host}:${aem.port}/crx/packmgr/service.jsp + true + true + ${vault.user} + ${vault.password} + + + + + org.apache.felix + maven-bundle-plugin + 3.3.0 + true + + + + org.apache.maven.plugins + maven-enforcer-plugin + 1.4.1 + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.0.0 + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.0.0 + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + [1.0.0,) + + enforce + + + + + + + + + + org.apache.maven.plugins + + + maven-dependency-plugin + + + [2.2,) + + + copy-dependencies + unpack + + + + + + + + + + org.codehaus.mojo + + + build-helper-maven-plugin + + + [1.5,) + + + + reserve-network-port + + + + + + + + + + + + + + + + + + + + + adobe-public + + + true + + + + adobe-public-releases + Adobe Public Releases + https://repo.adobe.com/nexus/content/groups/public + + + + + adobe-public-releases + Adobe Public Repository + https://repo.adobe.com/nexus/content/groups/public + + true + never + + + false + + + + + + + adobe-public-releases + Adobe Public Repository + https://repo.adobe.com/nexus/content/groups/public + + true + never + + + false + + + + + + + + autoInstallBundle + + + false + + + + + + org.apache.sling + maven-sling-plugin + + + install-bundle + + install + + + + + + + + + + + autoInstallPackage + + false + + + + + + com.day.jcr.vault + content-package-maven-plugin + + + install-package + + install + + + http://${aem.host}:${aem.port}/crx/packmgr/service.jsp + + + + + + + + + + + autoInstallPackagePublish + + false + + + + + + com.day.jcr.vault + content-package-maven-plugin + + + install-package-publish + + install + + + http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp + + + + + + + + + + + + + + + + + + + + org.osgi + osgi.core + 6.0.0 + provided + + + org.osgi + osgi.cmpn + 6.0.0 + provided + + + org.osgi + osgi.annotation + 6.0.1 + provided + + + + org.slf4j + slf4j-api + 1.5.11 + provided + + + + com.adobe.aem + uber-jar + 6.3.0 + apis + provided + + + com.adobe.cq + core.wcm.components.all + zip + 1.0.6 + + + + org.apache.sling + org.apache.sling.models.api + 1.0.0 + provided + + + + javax.servlet + servlet-api + 2.5 + provided + + + javax.servlet.jsp + jsp-api + 2.1 + provided + + + + javax.jcr + jcr + 2.0 + provided + + + + com.day.cq.wcm + cq-wcm-taglib + 5.7.4 + provided + + + + + junit + junit + 4.12 + test + + + org.slf4j + slf4j-simple + 1.5.11 + test + + + org.mockito + mockito-core + 2.7.22 + test + + + junit-addons + junit-addons + 1.4 + test + + + + + diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml new file mode 100644 index 00000000..6753ac41 --- /dev/null +++ b/ui.apps/pom.xml @@ -0,0 +1,157 @@ + + + + 4.0.0 + + + + + + de.valtech.aecu + aecu + 1.0-SNAPSHOT + ../pom.xml + + + + + + aecu.ui.apps + content-package + aecu - UI apps + UI apps package for aecu + + + + + + + + src/main/content/jcr_root + + + + ${basedir}/src/main/content/jcr_root + + + **/.vlt + **/.vltignore + **/.gitignore + **/*.iml + **/.classpath + **/.project + **/.settings + **/.DS_Store + **/target/** + **/pom.xml + + + + + + + maven-resources-plugin + + + true + + + + + + + + com.day.jcr.vault + content-package-maven-plugin + true + + src/main/content/META-INF/vault/filter.xml + true + true + Valtech + + + de.valtech.aecu + aecu.core + /apps/valtech/aecu/install + + + + + com.adobe.cq + core.wcm.components.all + true + + + + + + + org.apache.sling + htl-maven-plugin + + + + + + + + + + de.valtech.aecu + aecu.core + 1.0-SNAPSHOT + + + + com.adobe.aem + uber-jar + apis + + + + com.adobe.cq + core.wcm.components.all + zip + + + + javax.jcr + jcr + + + + javax.servlet + servlet-api + + + + com.day.cq.wcm + cq-wcm-taglib + + + diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml new file mode 100644 index 00000000..29c1fc72 --- /dev/null +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/ui.apps/src/main/content/jcr_root/META-INF/MANIFEST.MF b/ui.apps/src/main/content/jcr_root/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5e949512 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/ui.apps/src/main/content/jcr_root/apps/.content.xml b/ui.apps/src/main/content/jcr_root/apps/.content.xml new file mode 100644 index 00000000..792d2ead --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/.content.xml @@ -0,0 +1,4 @@ + + diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml new file mode 100644 index 00000000..085da325 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml @@ -0,0 +1,6 @@ + + diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt new file mode 100644 index 00000000..51f69f74 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt @@ -0,0 +1,15 @@ +############################################################################### +# Copyright 2017 Adobe Systems Incorporated +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt new file mode 100644 index 00000000..51f69f74 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt @@ -0,0 +1,15 @@ +############################################################################### +# Copyright 2017 Adobe Systems Incorporated +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/breadcrumb/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/breadcrumb/.content.xml new file mode 100644 index 00000000..4806da23 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/breadcrumb/.content.xml @@ -0,0 +1,6 @@ + + diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml new file mode 100644 index 00000000..b999d6e1 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml @@ -0,0 +1,5 @@ + + From 30c53a74ba53d9dc49ce261998c2d7c527e84ec5 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Mon, 30 Apr 2018 15:46:59 +0200 Subject: [PATCH 002/122] added initial JMX bean and service interface --- .gitignore | 2 + LICENSE | 674 ++++++++++++++++++ api/pom.xml | 81 +++ .../de/valtech/aecu/service/AecuService.java | 33 + .../de/valtech/aecu/service/package-info.java | 21 + core/pom.xml | 27 +- .../aecu/core/jmx/AecuServiceMBean.java | 31 + .../aecu/core/jmx/AecuServiceMBeanImpl.java | 51 ++ .../de/valtech/aecu/core/package-info.java | 19 - .../aecu/core/service/AecuServiceImpl.java | 37 + pom.xml | 115 +-- ui.apps/pom.xml | 91 +-- 12 files changed, 954 insertions(+), 228 deletions(-) create mode 100644 LICENSE create mode 100644 api/pom.xml create mode 100644 api/src/main/java/de/valtech/aecu/service/AecuService.java create mode 100644 api/src/main/java/de/valtech/aecu/service/package-info.java create mode 100644 core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java create mode 100644 core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java delete mode 100644 core/src/main/java/de/valtech/aecu/core/package-info.java create mode 100644 core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java diff --git a/.gitignore b/.gitignore index 4c231e47..1c45fb5d 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,5 @@ buildNumber.properties ### IntelliJ ### .idea/ *.iml + +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/api/pom.xml b/api/pom.xml new file mode 100644 index 00000000..104823a8 --- /dev/null +++ b/api/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + de.valtech.aecu + aecu + 1.0-SNAPSHOT + + aecu.api + bundle + AECU - API + Api bundle for AECU + + + + org.apache.sling + maven-sling-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + + javax.inject;version=0.0.0,* + + + + + + + + + org.osgi + osgi.core + + + org.osgi + osgi.cmpn + + + org.osgi + osgi.annotation + + + org.slf4j + slf4j-api + + + javax.jcr + jcr + + + javax.servlet + servlet-api + + + com.adobe.aem + uber-jar + apis + + + org.apache.sling + org.apache.sling.models.api + + + junit + junit + + + org.mockito + mockito-core + + + junit-addons + junit-addons + + + diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java new file mode 100644 index 00000000..0cf8b5bf --- /dev/null +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.service; + +/** + * Service interface for AECU. + * + * @author Roland Gruber + */ +public interface AecuService { + + /** + * Returns the AECU version. + * + * @return version + */ + String getVersion(); + +} diff --git a/api/src/main/java/de/valtech/aecu/service/package-info.java b/api/src/main/java/de/valtech/aecu/service/package-info.java new file mode 100644 index 00000000..ebcb0d61 --- /dev/null +++ b/api/src/main/java/de/valtech/aecu/service/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +@Version("1.0") +package de.valtech.aecu.service; + +import org.osgi.annotation.versioning.Version; diff --git a/core/pom.xml b/core/pom.xml index 9431a325..a38bc11e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -1,19 +1,4 @@ - 4.0.0 @@ -21,12 +6,11 @@ de.valtech.aecu aecu 1.0-SNAPSHOT - ../pom.xml aecu.core bundle - aecu - Core - Core bundle for aecu + AECU - Core + Core bundle for AECU @@ -51,7 +35,11 @@ - + + de.valtech.aecu + aecu.api + ${project.version} + org.osgi osgi.core @@ -64,7 +52,6 @@ org.osgi osgi.annotation - org.slf4j slf4j-api diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java new file mode 100644 index 00000000..30538588 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.jmx; + +import com.adobe.granite.jmx.annotation.Description; + +/** + * JMX service interface. + * + * @author Roland Gruber + */ +public interface AecuServiceMBean { + + @Description("Version") + public String getVersion(); + +} diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java new file mode 100644 index 00000000..35049985 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.jmx; + +import javax.management.NotCompliantMBeanException; + +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean; + +import de.valtech.aecu.service.AecuService; + +@Component(service = {AecuServiceMBean.class}, immediate = true, property = { + "jmx.objectname=de.valtech:type=AECU", + "pattern=/.*" +}) +public class AecuServiceMBeanImpl extends AnnotatedStandardMBean implements AecuServiceMBean { + + @Reference + AecuService aecuService; + + /** + * Constructor + * + * @throws NotCompliantMBeanException + */ + public AecuServiceMBeanImpl() throws NotCompliantMBeanException { + super(AecuServiceMBean.class); + } + + @Override + public String getVersion() { + return aecuService.getVersion(); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/package-info.java b/core/src/main/java/de/valtech/aecu/core/package-info.java deleted file mode 100644 index eed3dc70..00000000 --- a/core/src/main/java/de/valtech/aecu/core/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2015 Adobe Systems Incorporated - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -@Version("1.0") -package de.valtech.aecu.core; - -import org.osgi.annotation.versioning.Version; \ No newline at end of file diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java new file mode 100644 index 00000000..31f381f6 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.service; + +import org.osgi.framework.FrameworkUtil; +import org.osgi.service.component.annotations.Component; + +import de.valtech.aecu.service.AecuService; + +/** + * AECU service. + * + * @author Roland Gruber + */ +@Component(service=AecuService.class) +public class AecuServiceImpl implements AecuService { + + @Override + public String getVersion() { + return FrameworkUtil.getBundle(AecuServiceImpl.class).getVersion().toString(); + } + +} diff --git a/pom.xml b/pom.xml index a225c661..d69aba27 100644 --- a/pom.xml +++ b/pom.xml @@ -1,37 +1,24 @@ - 4.0.0 de.valtech.aecu aecu pom 1.0-SNAPSHOT - aecu + AECU + AEM Easy COntent Upgrade + api core ui.apps localhost - 4502 + 5702 localhost - 4503 + 5703 admin admin admin @@ -43,7 +30,6 @@ - org.apache.maven.plugins maven-release-plugin @@ -55,20 +41,17 @@ release - org.apache.maven.plugins maven-source-plugin 3.0.1 true - org.apache.maven.plugins maven-jar-plugin 3.0.2 - org.apache.maven.plugins maven-enforcer-plugin @@ -92,7 +75,6 @@ - org.apache.maven.plugins maven-compiler-plugin @@ -101,7 +83,6 @@ 1.8 - org.apache.maven.plugins maven-idea-plugin @@ -112,7 +93,6 @@ true - org.apache.maven.plugins maven-eclipse-plugin @@ -124,49 +104,41 @@ - org.apache.maven.plugins maven-clean-plugin 3.0.0 - org.apache.maven.plugins maven-resources-plugin 3.0.2 - org.apache.maven.plugins maven-compiler-plugin 3.6.1 - org.apache.maven.plugins maven-install-plugin 2.5.2 - org.apache.maven.plugins maven-surefire-plugin 2.20 - org.apache.maven.plugins maven-failsafe-plugin 2.20 - org.apache.maven.plugins maven-deploy-plugin 2.8.2 - org.apache.sling maven-sling-plugin @@ -176,7 +148,6 @@ WebConsole - org.apache.sling htl-maven-plugin @@ -192,7 +163,6 @@ - com.day.jcr.vault content-package-maven-plugin @@ -205,32 +175,27 @@ ${vault.password} - org.apache.felix maven-bundle-plugin - 3.3.0 + 3.5.0 true - org.apache.maven.plugins maven-enforcer-plugin 1.4.1 - org.apache.maven.plugins maven-dependency-plugin 3.0.0 - org.codehaus.mojo build-helper-maven-plugin 3.0.0 - org.eclipse.m2e lifecycle-mapping @@ -301,65 +266,8 @@ - - - - - adobe-public - - - true - - - - adobe-public-releases - Adobe Public Releases - https://repo.adobe.com/nexus/content/groups/public - - - - - adobe-public-releases - Adobe Public Repository - https://repo.adobe.com/nexus/content/groups/public - - true - never - - - false - - - - - - - adobe-public-releases - Adobe Public Repository - https://repo.adobe.com/nexus/content/groups/public - - true - never - - - false - - - - - - autoInstallBundle - false @@ -442,12 +350,8 @@ - - - - org.osgi osgi.core @@ -466,14 +370,12 @@ 6.0.1 provided - org.slf4j slf4j-api 1.5.11 provided - com.adobe.aem uber-jar @@ -487,14 +389,12 @@ zip 1.0.6 - org.apache.sling org.apache.sling.models.api 1.0.0 provided - javax.servlet servlet-api @@ -507,14 +407,12 @@ 2.1 provided - javax.jcr jcr 2.0 provided - com.day.cq.wcm cq-wcm-taglib @@ -522,7 +420,6 @@ provided - junit junit diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index 6753ac41..81c9dabc 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -1,50 +1,18 @@ - 4.0.0 - - - de.valtech.aecu aecu 1.0-SNAPSHOT - ../pom.xml - - - aecu.ui.apps content-package - aecu - UI apps - UI apps package for aecu + AECU - UI apps + UI apps package for AECU - - - - - src/main/content/jcr_root @@ -67,23 +35,13 @@ - maven-resources-plugin - true - - - com.day.jcr.vault content-package-maven-plugin @@ -94,19 +52,17 @@ true Valtech + + de.valtech.aecu + aecu.api + /apps/valtech/aecu/install + de.valtech.aecu aecu.core /apps/valtech/aecu/install - - - com.adobe.cq - core.wcm.components.all - true - - @@ -117,41 +73,16 @@ - - - de.valtech.aecu aecu.core - 1.0-SNAPSHOT - - - - com.adobe.aem - uber-jar - apis - - - - com.adobe.cq - core.wcm.components.all - zip - - - - javax.jcr - jcr + ${project.version} - - javax.servlet - servlet-api - - - - com.day.cq.wcm - cq-wcm-taglib + de.valtech.aecu + aecu.api + ${project.version} From d079432f22891a8b3254dbf41637791fcccd870d Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Thu, 3 May 2018 15:22:49 +0200 Subject: [PATCH 003/122] added example scripts and bundle with Groovy Console --- bundle/pom.xml | 78 +++++++++++++++++++ examples/pom.xml | 64 +++++++++++++++ .../main/content/META-INF/vault/filter.xml | 4 + .../content/jcr_root/META-INF/MANIFEST.MF | 3 + .../project1/migrations.author/script1.groovy | 1 + .../migrations.author/script2.fallback.groovy | 1 + .../project1/migrations.author/script2.groovy | 2 + .../aecu-examples/project2/script1.groovy | 1 + .../project2/script2.always.groovy | 1 + pom.xml | 2 + .../main/content/META-INF/vault/filter.xml | 1 - 11 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 bundle/pom.xml create mode 100644 examples/pom.xml create mode 100644 examples/src/main/content/META-INF/vault/filter.xml create mode 100644 examples/src/main/content/jcr_root/META-INF/MANIFEST.MF create mode 100644 examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy create mode 100644 examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy create mode 100644 examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy create mode 100644 examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy create mode 100644 examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy diff --git a/bundle/pom.xml b/bundle/pom.xml new file mode 100644 index 00000000..b84bd34a --- /dev/null +++ b/bundle/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + + + de.valtech.aecu + aecu + 1.0-SNAPSHOT + + + aecu.bundle + content-package + AECU - Bundle + Bundle package for AECU that includes Groovy Console + + + src/main/content/jcr_root + + + + ${basedir}/src/main/content/jcr_root + + + **/.vlt + **/.vltignore + **/.gitignore + **/*.iml + **/.classpath + **/.project + **/.settings + **/.DS_Store + **/target/** + **/pom.xml + + + + + + maven-resources-plugin + + true + + + + + com.day.jcr.vault + content-package-maven-plugin + true + + src/main/content/META-INF/vault/filter.xml + true + true + Valtech + + + com.icfolson.aem.groovy.console + aem-groovy-console + + + + + + + org.apache.sling + htl-maven-plugin + + + + + + + com.icfolson.aem.groovy.console + aem-groovy-console + 11.3.0 + zip + + + diff --git a/examples/pom.xml b/examples/pom.xml new file mode 100644 index 00000000..0e24555f --- /dev/null +++ b/examples/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + + de.valtech.aecu + aecu + 1.0-SNAPSHOT + + + aecu.examples + content-package + AECU - Examples + Examples package for AECU + + + src/main/content/jcr_root + + + + ${basedir}/src/main/content/jcr_root + + + **/.vlt + **/.vltignore + **/.gitignore + **/*.iml + **/.classpath + **/.project + **/.settings + **/.DS_Store + **/target/** + **/pom.xml + + + + + + maven-resources-plugin + + true + + + + + com.day.jcr.vault + content-package-maven-plugin + true + + src/main/content/META-INF/vault/filter.xml + true + true + Valtech + + + + + org.apache.sling + htl-maven-plugin + + + + + diff --git a/examples/src/main/content/META-INF/vault/filter.xml b/examples/src/main/content/META-INF/vault/filter.xml new file mode 100644 index 00000000..85e3bc87 --- /dev/null +++ b/examples/src/main/content/META-INF/vault/filter.xml @@ -0,0 +1,4 @@ + + + + diff --git a/examples/src/main/content/jcr_root/META-INF/MANIFEST.MF b/examples/src/main/content/jcr_root/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5e949512 --- /dev/null +++ b/examples/src/main/content/jcr_root/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy new file mode 100644 index 00000000..1dd6b740 --- /dev/null +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy @@ -0,0 +1 @@ +println "Executing project1 - script1" \ No newline at end of file diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy new file mode 100644 index 00000000..9afe049e --- /dev/null +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy @@ -0,0 +1 @@ +println "Executing fallback project1 - script2" \ No newline at end of file diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy new file mode 100644 index 00000000..7dd6cfd2 --- /dev/null +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy @@ -0,0 +1,2 @@ +println "Executing project1 - script2" +This is a syntax error \ No newline at end of file diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy new file mode 100644 index 00000000..b5b89ba4 --- /dev/null +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy @@ -0,0 +1 @@ +println "Executing project2 - script1" \ No newline at end of file diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy new file mode 100644 index 00000000..ba5a3d0f --- /dev/null +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy @@ -0,0 +1 @@ +println "Executing project2 - script2" \ No newline at end of file diff --git a/pom.xml b/pom.xml index d69aba27..f94cf6bd 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,8 @@ api core ui.apps + bundle + examples diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index 29c1fc72..719c14d2 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -1,5 +1,4 @@ - From 20a3636d6465fcbefe520da2422f0abf28c52073 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Mon, 7 May 2018 14:48:23 +0200 Subject: [PATCH 004/122] added service user --- .../valtech/aecu/service/AecuException.java | 47 +++++++++++++++ .../de/valtech/aecu/service/AecuService.java | 11 ++++ .../healthcheck/ServiceUserHealthCheck.java | 59 +++++++++++++++++++ .../aecu/core/jmx/AecuServiceMBean.java | 20 +++++++ .../aecu/core/jmx/AecuServiceMBeanImpl.java | 8 +++ .../aecu/core/service/AecuServiceImpl.java | 20 +++++++ .../ServiceResourceResolverService.java | 53 +++++++++++++++++ ui.apps/pom.xml | 3 + .../main/content/META-INF/vault/filter.xml | 2 + .../aecu.xml | 5 -- ...rImpl.amended-valtechAecuSystemUser.config | 1 + .../scripts/aecu/_rep_policy.xml | 8 +++ .../home/users/system/aecu/.content.xml | 3 + .../system/aecu/aecu-service/.content.xml | 7 +++ 14 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 api/src/main/java/de/valtech/aecu/service/AecuException.java create mode 100644 core/src/main/java/de/valtech/aecu/core/healthcheck/ServiceUserHealthCheck.java create mode 100644 core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java delete mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuSystemUser.config create mode 100644 ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/_rep_policy.xml create mode 100644 ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml diff --git a/api/src/main/java/de/valtech/aecu/service/AecuException.java b/api/src/main/java/de/valtech/aecu/service/AecuException.java new file mode 100644 index 00000000..e9c378ee --- /dev/null +++ b/api/src/main/java/de/valtech/aecu/service/AecuException.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.service; + +/** + * Thrown when the AECU service faces an error. + * + * @author Roland Gruber + */ +public class AecuException extends Exception { + + private static final long serialVersionUID = 1L; + + /** + * Constructor + * + * @param message error message + * @param e original exception + */ + public AecuException(String message, Throwable e) { + super(message, e); + } + + /** + * Constructor + * + * @param message error message + */ + public AecuException(String message) { + super(message); + } + +} diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 0cf8b5bf..1210c1e7 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -16,6 +16,8 @@ */ package de.valtech.aecu.service; +import java.util.List; + /** * Service interface for AECU. * @@ -29,5 +31,14 @@ public interface AecuService { * @return version */ String getVersion(); + + /** + * Returns a list of files that can be executed in the given path. + * + * @param path file or folder + * @return list of files that are executable + * @throws AecuException error finding files (e.g. invalid path) + */ + List getFiles(String path) throws AecuException; } diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/ServiceUserHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/ServiceUserHealthCheck.java new file mode 100644 index 00000000..3a322a7e --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/ServiceUserHealthCheck.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.healthcheck; + +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.hc.api.HealthCheck; +import org.apache.sling.hc.api.Result; +import org.apache.sling.hc.util.FormattingResultLog; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; + +/** + * Checks if the internal service user is ok. + * + * @author Roland Gruber + */ +@Component( + immediate = true, + service = HealthCheck.class, + property = { + HealthCheck.TAGS + "=aecu", + HealthCheck.NAME + "=AECU Service User", + HealthCheck.MBEAN_NAME + "=aecuServiceUserHCmBean" + } +) +public class ServiceUserHealthCheck implements HealthCheck { + + @Reference + private ServiceResourceResolverService resolverService; + + @Override + public Result execute() { + final FormattingResultLog resultLog = new FormattingResultLog(); + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + resultLog.info("Ok"); + } catch (LoginException e) { + resultLog.critical("Unable to open service resource resolver {}", e.getMessage()); + } + return new Result(resultLog); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index 30538588..c62871d2 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -16,7 +16,12 @@ */ package de.valtech.aecu.core.jmx; +import java.util.List; + import com.adobe.granite.jmx.annotation.Description; +import com.adobe.granite.jmx.annotation.Name; + +import de.valtech.aecu.service.AecuException; /** * JMX service interface. @@ -25,7 +30,22 @@ */ public interface AecuServiceMBean { + /** + * Returns the AECU version. + * + * @return version + */ @Description("Version") public String getVersion(); + /** + * Returns a list of files that can be executed in the given path. + * + * @param path file or folder + * @return list of files that are executable + * @throws AecuException error finding files (e.g. invalid path) + */ + @Description("Returns a list of files that can be executed in the given path") + List getFiles(@Name("Path") @Description("File or folder") String path) throws AecuException; + } diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 35049985..f3361f7a 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -16,6 +16,8 @@ */ package de.valtech.aecu.core.jmx; +import java.util.List; + import javax.management.NotCompliantMBeanException; import org.osgi.service.component.annotations.Component; @@ -23,6 +25,7 @@ import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean; +import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; @Component(service = {AecuServiceMBean.class}, immediate = true, property = { @@ -48,4 +51,9 @@ public String getVersion() { return aecuService.getVersion(); } + @Override + public List getFiles(String path) throws AecuException { + return aecuService.getFiles(path); + } + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 31f381f6..8b6672d3 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -16,9 +16,16 @@ */ package de.valtech.aecu.core.service; +import java.util.List; + +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.ResourceResolver; import org.osgi.framework.FrameworkUtil; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; +import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; /** @@ -28,10 +35,23 @@ */ @Component(service=AecuService.class) public class AecuServiceImpl implements AecuService { + + @Reference + ServiceResourceResolverService resolverService; @Override public String getVersion() { return FrameworkUtil.getBundle(AecuServiceImpl.class).getVersion().toString(); } + @Override + public List getFiles(String path) throws AecuException { + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + return null; + } + catch (LoginException e) { + throw new AecuException("Unable to get service resource resolver", e); + } + } + } diff --git a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java new file mode 100644 index 00000000..c3107c40 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.serviceuser; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceResolverFactory; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * Provides the service resource resolver. + * + * @author Roland Gruber + */ +@Component(service=ServiceResourceResolverService.class) +public class ServiceResourceResolverService { + + private static final String SUBSERVICE_AECU = "aecu"; + + @Reference + ResourceResolverFactory resolverFactory; + + /** + * Returns a resource resolver of the AECU service user. + * + * @return service resource resolver + * @throws LoginException error opening resource resolver + */ + public ResourceResolver getServiceResourceResolver() throws LoginException { + final Map authenticationInfo = new HashMap<>(); + authenticationInfo.put(ResourceResolverFactory.SUBSERVICE, SUBSERVICE_AECU); + return resolverFactory.getServiceResourceResolver(authenticationInfo); + } + +} diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index 81c9dabc..0eb079c0 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -51,6 +51,9 @@ true true Valtech + + merge_preserve + de.valtech.aecu diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index 719c14d2..0e702da8 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -1,4 +1,6 @@ + + diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml deleted file mode 100644 index b999d6e1..00000000 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config.author/com.day.cq.wcm.mobile.core.impl.MobileEmulatorProvider-valtech/aecu.xml +++ /dev/null @@ -1,5 +0,0 @@ - - diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuSystemUser.config b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuSystemUser.config new file mode 100644 index 00000000..cc15e955 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuSystemUser.config @@ -0,0 +1 @@ +user.mapping=["de.valtech.aecu.core:aecu\=aecu-service"] \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/_rep_policy.xml b/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/_rep_policy.xml new file mode 100644 index 00000000..70150516 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/_rep_policy.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml new file mode 100644 index 00000000..44a6008e --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml new file mode 100644 index 00000000..13021631 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml @@ -0,0 +1,7 @@ + + From dbbf4ab3811b4c79cb5a3e28b9dc5f02971faeef Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Mon, 7 May 2018 16:12:16 +0200 Subject: [PATCH 005/122] find script candidates --- .../aecu/core/service/AecuServiceImpl.java | 95 +++++++++++++++- .../aecu/core/models/TestHelloWorldModel.java | 60 ---------- .../core/service/AecuServiceImplTest.java | 103 ++++++++++++++++++ 3 files changed, 196 insertions(+), 62 deletions(-) delete mode 100644 core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java create mode 100644 core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 8b6672d3..b4579018 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -16,10 +16,18 @@ */ package de.valtech.aecu.core.service; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; +import java.util.Set; +import org.apache.jackrabbit.JcrConstants; import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.jcr.resource.api.JcrResourceConstants; +import org.apache.sling.settings.SlingSettingsService; import org.osgi.framework.FrameworkUtil; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -37,7 +45,10 @@ public class AecuServiceImpl implements AecuService { @Reference - ServiceResourceResolverService resolverService; + private ServiceResourceResolverService resolverService; + + @Reference + private SlingSettingsService slingSettings; @Override public String getVersion() { @@ -47,11 +58,91 @@ public String getVersion() { @Override public List getFiles(String path) throws AecuException { try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { - return null; + return findCandidates(resolver, path); } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); } } + /** + * Finds all candidates for scripts to run. + * + * @param resolver service resource resolver + * @param path starting path + * @return candidate list + * @throws AecuException error finding candidates + */ + private List findCandidates(ResourceResolver resolver, String path) throws AecuException { + if (path == null) { + throw new AecuException("Path is null"); + } + Resource resource = resolver.getResource(path); + if (resource == null) { + throw new AecuException("Path is invalid"); + } + List candidates = new ArrayList<>(); + if (isFolder(resource) && matchesRunmodes(resource.getName())) { + Iterator childIterator = resource.listChildren(); + for (Resource child : resource.getChildren()) { + candidates.addAll(findCandidates(resolver, child.getPath())); + } + } + else if (isValidScriptName(resource.getName())) { + candidates.add(path); + } + return candidates; + } + + /** + * Checks if the resource is a folder. + * + * @param resource resource + * @return is folder + */ + private boolean isFolder(Resource resource) { + String type = resource.getValueMap().get(JcrConstants.JCR_PRIMARYTYPE, String.class); + return JcrResourceConstants.NT_SLING_FOLDER.equals(type) + || JcrResourceConstants.NT_SLING_ORDERED_FOLDER.equals(type) + || JcrConstants.NT_FOLDER.equals(type); + } + + /** + * Checks if the folder matches the system's run modes if specified in folder name. + * + * @param name resource name + * @return matches run modes + */ + protected boolean matchesRunmodes(String name) { + if (!name.contains(".")) { + return true; + } + Set runModes = slingSettings.getRunModes(); + String runModeString = name.substring(name.indexOf(".") + 1); + String[] combinations = runModeString.split(";"); + for (String combination : combinations) { + String[] modes = combination.split("\\."); + if (runModes.containsAll(Arrays.asList(modes))) { + return true; + } + } + return false; + } + + /** + * Checks if the name is a valid script. + * + * @param name file name + * @return is valid + */ + protected boolean isValidScriptName(String name) { + if (!name.endsWith(".groovy")) { + return false; + } + if (name.contains(".fallback.")) { + return false; + } + return true; + } + } diff --git a/core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java b/core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java deleted file mode 100644 index 73cbf5e4..00000000 --- a/core/src/test/java/de/valtech/aecu/core/models/TestHelloWorldModel.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 Adobe Systems Incorporated - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.valtech.aecu.core.models; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.UUID; - -import junitx.util.PrivateAccessor; - -import org.apache.sling.settings.SlingSettingsService; -import org.junit.Before; -import org.junit.Test; - -/** - * Simple JUnit test verifying the HelloWorldModel - */ -public class TestHelloWorldModel { - - //@Inject - private HelloWorldModel hello; - - private String slingId; - - @Before - public void setup() throws Exception { - SlingSettingsService settings = mock(SlingSettingsService.class); - slingId = UUID.randomUUID().toString(); - when(settings.getSlingId()).thenReturn(slingId); - - hello = new HelloWorldModel(); - PrivateAccessor.setField(hello, "settings", settings); - hello.init(); - } - - @Test - public void testGetMessage() throws Exception { - // some very basic junit tests - String msg = hello.getMessage(); - assertNotNull(msg); - assertTrue(msg.length() > 0); - } - -} diff --git a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java new file mode 100644 index 00000000..ffa9ed82 --- /dev/null +++ b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.service; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.sling.settings.SlingSettingsService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * Tests AecuServiceImpl + * + * @author Roland Gruber + */ +@RunWith(value=MockitoJUnitRunner.class) +public class AecuServiceImplTest { + + @InjectMocks + private AecuServiceImpl service; + + @Mock + private SlingSettingsService settingsService; + + @Before + public void setup() { + Set runModes = new HashSet<>(); + runModes.add("author"); + runModes.add("test"); + runModes.add("test2"); + runModes.add("test3"); + when(settingsService.getRunModes()).thenReturn(runModes); + } + + @Test + public void matchesRunmodes_noMode() { + assertTrue(service.matchesRunmodes("name")); + } + + @Test + public void matchesRunmodes_nonMatching() { + assertFalse(service.matchesRunmodes("name.publish")); + } + + @Test + public void matchesRunmodes_matching() { + assertTrue(service.matchesRunmodes("name.author")); + assertTrue(service.matchesRunmodes("name.test")); + } + + @Test + public void matchesRunmodes_matchingMulti() { + assertTrue(service.matchesRunmodes("name.author.test")); + assertTrue(service.matchesRunmodes("name.author.test;testNO")); + assertTrue(service.matchesRunmodes("name.authorNO.test;test2.author")); + } + + @Test + public void matchesRunmodes_nonMatchingMulti() { + assertFalse(service.matchesRunmodes("name.author.testNO")); + assertFalse(service.matchesRunmodes("name.author.testNO;testNO")); + assertFalse(service.matchesRunmodes("name.author.testNO;test2NO.author")); + } + + @Test + public void isValidScriptName_ok() { + assertTrue(service.isValidScriptName("test.groovy")); + } + + @Test + public void isValidScriptName_invalidExtension() { + assertFalse(service.isValidScriptName("test.txt")); + } + + @Test + public void isValidScriptName_fallback() { + assertFalse(service.isValidScriptName("test.fallback.groovy")); + } + +} From 20b59b5f45fe3139dec538141376cb222bc6c59a Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Tue, 8 May 2018 13:11:14 +0200 Subject: [PATCH 006/122] added composite health check and dashboard entry --- ui.apps/src/main/content/META-INF/vault/filter.xml | 1 + .../src/main/content/jcr_root/apps/settings/.content.xml | 4 ++++ .../apps/settings/granite/operations/.content.xml | 4 ++++ .../apps/settings/granite/operations/hc/.content.xml | 4 ++++ .../apps/settings/granite/operations/hc/aecu/.content.xml | 6 ++++++ ...pache.sling.hc.core.impl.CompositeHealthCheck-aecu.xml | 8 ++++++++ 6 files changed, 27 insertions(+) create mode 100644 ui.apps/src/main/content/jcr_root/apps/settings/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.hc.core.impl.CompositeHealthCheck-aecu.xml diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index 0e702da8..ce5b9877 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -3,4 +3,5 @@ + diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/.content.xml new file mode 100644 index 00000000..1db66005 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/.content.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml new file mode 100644 index 00000000..5c9a5d2b --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml new file mode 100644 index 00000000..c6ad70be --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml new file mode 100644 index 00000000..00e94271 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.hc.core.impl.CompositeHealthCheck-aecu.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.hc.core.impl.CompositeHealthCheck-aecu.xml new file mode 100644 index 00000000..f45a726e --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.hc.core.impl.CompositeHealthCheck-aecu.xml @@ -0,0 +1,8 @@ + + From 325fa88c1d273a247d8990a69c676f245c1dd03a Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Tue, 8 May 2018 13:57:51 +0200 Subject: [PATCH 007/122] added execution --- .../de/valtech/aecu/service/AecuService.java | 9 +++ .../valtech/aecu/service/ExecutionResult.java | 65 +++++++++++++++++++ .../aecu/core/jmx/AecuServiceMBean.java | 10 +++ .../aecu/core/jmx/AecuServiceMBeanImpl.java | 5 ++ .../aecu/core/service/AecuServiceImpl.java | 32 ++++++++- 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/de/valtech/aecu/service/ExecutionResult.java diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 1210c1e7..d7436102 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -40,5 +40,14 @@ public interface AecuService { * @throws AecuException error finding files (e.g. invalid path) */ List getFiles(String path) throws AecuException; + + /** + * Executes the script at the given position. + * + * @param path path of script + * @return execution result + * @throws AecuException error during execution + */ + ExecutionResult execute(String path) throws AecuException; } diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java new file mode 100644 index 00000000..d8139ebd --- /dev/null +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.service; + +/** + * Result of a script execution. + * + * @author Roland Gruber + */ +public class ExecutionResult { + + private boolean success; + + private String output; + + /** + * Constructor + * + * @param success execution was successful + * @param output script output + */ + public ExecutionResult(boolean success, String output) { + this.success = success; + this.output = output; + } + + /** + * Returns if execution was successful. + * + * @return successful + */ + public boolean isSuccess() { + return success; + } + + /** + * Returns the script output. + * + * @return output + */ + public String getOutput() { + return output; + } + + @Override + public String toString() { + return "Successful: " + Boolean.toString(success) + "\n" + + "Output: " + output; + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index c62871d2..2068d3c9 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -28,6 +28,7 @@ * * @author Roland Gruber */ +@Description("AEM Easy Content Upgrade") public interface AecuServiceMBean { /** @@ -48,4 +49,13 @@ public interface AecuServiceMBean { @Description("Returns a list of files that can be executed in the given path") List getFiles(@Name("Path") @Description("File or folder") String path) throws AecuException; + /** + * Executes the script at the given position. + * + * @param path path of script + * @return execution result + * @throws AecuException error during execution + */ + String execute(@Name("Path") @Description("Path to file that should be executed") String path) throws AecuException; + } diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index f3361f7a..331213f4 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -56,4 +56,9 @@ public List getFiles(String path) throws AecuException { return aecuService.getFiles(path); } + @Override + public String execute(String path) throws AecuException { + return aecuService.execute(path).toString(); + } + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index b4579018..388bd191 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -18,7 +18,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -35,6 +34,7 @@ import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.ExecutionResult; /** * AECU service. @@ -83,7 +83,6 @@ private List findCandidates(ResourceResolver resolver, String path) thro } List candidates = new ArrayList<>(); if (isFolder(resource) && matchesRunmodes(resource.getName())) { - Iterator childIterator = resource.listChildren(); for (Resource child : resource.getChildren()) { candidates.addAll(findCandidates(resolver, child.getPath())); } @@ -145,4 +144,33 @@ protected boolean isValidScriptName(String name) { return true; } + @Override + public ExecutionResult execute(String path) throws AecuException { + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + Resource resource = resolver.getResource(path); + if (resource == null) { + throw new AecuException("Path is invalid"); + } + if (!isValidScriptName(resource.getName())) { + throw new AecuException("Invalid script name"); + } + ExecutionResult result = executeScript(path); + return result; + } + catch (LoginException e) { + throw new AecuException("Unable to get service resource resolver", e); + } + } + + /** + * Executes the script. + * + * @param path path + * @return result + */ + private ExecutionResult executeScript(String path) { + // TODO + return new ExecutionResult(true, ""); + } + } From 6059753efb7ed856c571d8be66d2b61eb3cab2f3 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Tue, 8 May 2018 15:03:58 +0200 Subject: [PATCH 008/122] run script with Groovy Console --- .../valtech/aecu/service/ExecutionResult.java | 20 +- bundle/pom.xml | 1 - core/pom.xml | 12 + .../aecu/core/service/AecuServiceImpl.java | 18 +- .../core/service/GroovyConsoleRequest.java | 413 ++++++++++++++++++ pom.xml | 37 ++ .../main/content/META-INF/vault/filter.xml | 2 + .../scripts/aecu => }/_rep_policy.xml | 0 .../groovyconsole/scripts/aecu/.content.xml | 4 + 9 files changed, 498 insertions(+), 9 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java rename ui.apps/src/main/content/jcr_root/{etc/groovyconsole/scripts/aecu => }/_rep_policy.xml (100%) create mode 100644 ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java index d8139ebd..69dd0937 100644 --- a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -24,18 +24,20 @@ public class ExecutionResult { private boolean success; - private String output; + private String time; /** * Constructor * * @param success execution was successful + * @param time execution time * @param output script output */ - public ExecutionResult(boolean success, String output) { + public ExecutionResult(boolean success, String time, String output) { this.success = success; this.output = output; + this.time = time; } /** @@ -56,10 +58,20 @@ public String getOutput() { return output; } + /** + * Returns the execution time. + * + * @return time + */ + public String getTime() { + return time; + } + @Override public String toString() { - return "Successful: " + Boolean.toString(success) + "\n" - + "Output: " + output; + return "Successful: " + Boolean.toString(success) + + "\n" + "Execution time: " + time + + "\n" + "Output: " + output; } } diff --git a/bundle/pom.xml b/bundle/pom.xml index b84bd34a..c90d6196 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -71,7 +71,6 @@ com.icfolson.aem.groovy.console aem-groovy-console - 11.3.0 zip diff --git a/core/pom.xml b/core/pom.xml index a38bc11e..f36f7d85 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -40,6 +40,14 @@ aecu.api ${project.version} + + org.codehaus.groovy + groovy-all + + + com.icfolson.aem.groovy.console + aem-groovy-console + org.osgi osgi.core @@ -73,6 +81,10 @@ org.apache.sling org.apache.sling.models.api + + org.apache.commons + commons-lang3 + junit junit diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 388bd191..ed9b3301 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Set; +import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.JcrConstants; import org.apache.sling.api.resource.LoginException; import org.apache.sling.api.resource.Resource; @@ -31,6 +32,9 @@ import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import com.icfolson.aem.groovy.console.GroovyConsoleService; +import com.icfolson.aem.groovy.console.response.RunScriptResponse; + import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; @@ -49,6 +53,9 @@ public class AecuServiceImpl implements AecuService { @Reference private SlingSettingsService slingSettings; + + @Reference + private GroovyConsoleService groovyConsoleService; @Override public String getVersion() { @@ -154,7 +161,7 @@ public ExecutionResult execute(String path) throws AecuException { if (!isValidScriptName(resource.getName())) { throw new AecuException("Invalid script name"); } - ExecutionResult result = executeScript(path); + ExecutionResult result = executeScript(resolver, path); return result; } catch (LoginException e) { @@ -165,12 +172,15 @@ public ExecutionResult execute(String path) throws AecuException { /** * Executes the script. * + * @param resolver resource resolver * @param path path * @return result */ - private ExecutionResult executeScript(String path) { - // TODO - return new ExecutionResult(true, ""); + private ExecutionResult executeScript(ResourceResolver resolver, String path) { + GroovyConsoleRequest request = new GroovyConsoleRequest(resolver); + RunScriptResponse response = groovyConsoleService.runScript(request, path); + boolean success = StringUtils.isBlank(response.getExceptionStackTrace()); + return new ExecutionResult(success, response.getRunningTime(), response.getOutput() + response.getExceptionStackTrace()); } } diff --git a/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java new file mode 100644 index 00000000..b168b919 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java @@ -0,0 +1,413 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletInputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpSession; + +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.request.RequestDispatcherOptions; +import org.apache.sling.api.request.RequestParameter; +import org.apache.sling.api.request.RequestParameterMap; +import org.apache.sling.api.request.RequestPathInfo; +import org.apache.sling.api.request.RequestProgressTracker; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +/** + * Dummy request that is used to execute the script. + * + * @author Roland Gruber + */ +public class GroovyConsoleRequest implements SlingHttpServletRequest { + + private ResourceResolver resolver; + + /** + * Constructor + * + * @param resolver resource resolver + */ + public GroovyConsoleRequest(ResourceResolver resolver) { + this.resolver = resolver; + } + + @Override + public String getAuthType() { + return null; + } + + @Override + public String getContextPath() { + return null; + } + + @Override + public Cookie[] getCookies() { + return null; + } + + @Override + public long getDateHeader(String arg0) { + return 0; + } + + @Override + public String getHeader(String arg0) { + return null; + } + + @Override + public Enumeration getHeaderNames() { + return null; + } + + @Override + public Enumeration getHeaders(String arg0) { + return null; + } + + @Override + public int getIntHeader(String arg0) { + return 0; + } + + @Override + public String getMethod() { + return null; + } + + @Override + public String getPathInfo() { + return null; + } + + @Override + public String getPathTranslated() { + return null; + } + + @Override + public String getQueryString() { + return null; + } + + @Override + public String getRemoteUser() { + return null; + } + + @Override + public String getRequestURI() { + return null; + } + + @Override + public StringBuffer getRequestURL() { + return null; + } + + @Override + public String getRequestedSessionId() { + return null; + } + + @Override + public String getServletPath() { + return null; + } + + @Override + public HttpSession getSession() { + return null; + } + + @Override + public HttpSession getSession(boolean arg0) { + return null; + } + + @Override + public Principal getUserPrincipal() { + return null; + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + return false; + } + + @Override + public boolean isRequestedSessionIdValid() { + return false; + } + + @Override + public boolean isUserInRole(String arg0) { + return false; + } + + @Override + public Object getAttribute(String arg0) { + return null; + } + + @Override + public Enumeration getAttributeNames() { + return null; + } + + @Override + public String getCharacterEncoding() { + return null; + } + + @Override + public int getContentLength() { + return 0; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return null; + } + + @Override + public String getLocalAddr() { + return null; + } + + @Override + public String getLocalName() { + return null; + } + + @Override + public int getLocalPort() { + return 0; + } + + @Override + public Locale getLocale() { + return null; + } + + @Override + public Enumeration getLocales() { + return null; + } + + @Override + public String getParameter(String arg0) { + return null; + } + + @Override + public Map getParameterMap() { + return null; + } + + @Override + public Enumeration getParameterNames() { + return null; + } + + @Override + public String[] getParameterValues(String arg0) { + return null; + } + + @Override + public String getProtocol() { + return null; + } + + @Override + public BufferedReader getReader() throws IOException { + return null; + } + + @Override + public String getRealPath(String arg0) { + return null; + } + + @Override + public String getRemoteAddr() { + return null; + } + + @Override + public String getRemoteHost() { + return null; + } + + @Override + public int getRemotePort() { + return 0; + } + + @Override + public RequestDispatcher getRequestDispatcher(String arg0) { + return null; + } + + @Override + public String getScheme() { + return null; + } + + @Override + public String getServerName() { + return null; + } + + @Override + public int getServerPort() { + return 0; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public void removeAttribute(String arg0) { + } + + @Override + public void setAttribute(String arg0, Object arg1) { + } + + @Override + public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException { + } + + @Override + public AdapterType adaptTo(Class arg0) { + return null; + } + + @Override + public Cookie getCookie(String arg0) { + return null; + } + + @Override + public RequestDispatcher getRequestDispatcher(Resource arg0) { + return null; + } + + @Override + public RequestDispatcher getRequestDispatcher(String arg0, RequestDispatcherOptions arg1) { + return null; + } + + @Override + public RequestDispatcher getRequestDispatcher(Resource arg0, RequestDispatcherOptions arg1) { + return null; + } + + @Override + public RequestParameter getRequestParameter(String arg0) { + return null; + } + + @Override + public List getRequestParameterList() { + return null; + } + + @Override + public RequestParameterMap getRequestParameterMap() { + return null; + } + + @Override + public RequestParameter[] getRequestParameters(String arg0) { + return null; + } + + @Override + public RequestPathInfo getRequestPathInfo() { + return null; + } + + @Override + public RequestProgressTracker getRequestProgressTracker() { + return null; + } + + @Override + public Resource getResource() { + return null; + } + + @Override + public ResourceBundle getResourceBundle(Locale arg0) { + return null; + } + + @Override + public ResourceBundle getResourceBundle(String arg0, Locale arg1) { + return null; + } + + @Override + public ResourceResolver getResourceResolver() { + return resolver; + } + + @Override + public String getResponseContentType() { + return null; + } + + @Override + public Enumeration getResponseContentTypes() { + return null; + } + +} diff --git a/pom.xml b/pom.xml index f94cf6bd..96f7e3fd 100644 --- a/pom.xml +++ b/pom.xml @@ -421,6 +421,43 @@ 5.7.4 provided + + org.codehaus.groovy + groovy-all + 2.4.10 + provided + + + com.icfolson.aem.groovy.console + aem-groovy-console + 11.3.0 + provided + + + + * + * + + + + + com.icfolson.aem.groovy.console + aem-groovy-console + 11.3.0 + zip + + + + * + * + + + + + org.apache.commons + commons-lang3 + 3.0.1 + junit diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index ce5b9877..f8d1b003 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -4,4 +4,6 @@ + + diff --git a/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/_rep_policy.xml b/ui.apps/src/main/content/jcr_root/_rep_policy.xml similarity index 100% rename from ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/_rep_policy.xml rename to ui.apps/src/main/content/jcr_root/_rep_policy.xml diff --git a/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml new file mode 100644 index 00000000..1db66005 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file From b410a7220d8f05d325d1766333a2e7d5aa807e50 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Wed, 9 May 2018 14:57:16 +0200 Subject: [PATCH 009/122] execute multiple files via JMX --- .../main/java/de/valtech/aecu/service/AecuService.java | 3 +++ .../de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index d7436102..373eeb74 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -18,11 +18,14 @@ import java.util.List; +import org.osgi.annotation.versioning.ProviderType; + /** * Service interface for AECU. * * @author Roland Gruber */ +@ProviderType public interface AecuService { /** diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 331213f4..7e45967c 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -58,7 +58,14 @@ public List getFiles(String path) throws AecuException { @Override public String execute(String path) throws AecuException { - return aecuService.execute(path).toString(); + List files = aecuService.getFiles(path); + StringBuilder result = new StringBuilder("Found " + files.size() + " files to execute\n\n"); + for (String file : files) { + result.append(file + "\n"); + result.append(aecuService.execute(file).toString()); + result.append("\n\n"); + } + return result.toString(); } } From e476780c5737b5d72ae87d2200a9e5b5af39e20b Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Wed, 9 May 2018 15:12:49 +0200 Subject: [PATCH 010/122] save execution result --- api/pom.xml | 4 +++ .../valtech/aecu/service/ExecutionResult.java | 28 ++++++++++++++++--- .../aecu/core/service/AecuServiceImpl.java | 3 +- .../aecu-examples/project2/script1.groovy | 3 +- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 104823a8..d0729cdf 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -65,6 +65,10 @@ org.apache.sling org.apache.sling.models.api + + org.apache.commons + commons-lang3 + junit junit diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java index 69dd0937..085eabb7 100644 --- a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -16,6 +16,8 @@ */ package de.valtech.aecu.service; +import org.apache.commons.lang3.StringUtils; + /** * Result of a script execution. * @@ -26,18 +28,21 @@ public class ExecutionResult { private boolean success; private String output; private String time; + private String result; /** * Constructor * * @param success execution was successful * @param time execution time + * @param result result * @param output script output */ - public ExecutionResult(boolean success, String time, String output) { + public ExecutionResult(boolean success, String time, String result, String output) { this.success = success; this.output = output; this.time = time; + this.result = result; } /** @@ -49,6 +54,15 @@ public boolean isSuccess() { return success; } + /** + * Returns the script result. + * + * @return output + */ + public String getResult() { + return result; + } + /** * Returns the script output. * @@ -69,9 +83,15 @@ public String getTime() { @Override public String toString() { - return "Successful: " + Boolean.toString(success) - + "\n" + "Execution time: " + time - + "\n" + "Output: " + output; + StringBuilder stringVal = new StringBuilder("Successful: " + Boolean.toString(success)); + if (StringUtils.isNotBlank(time)) { + stringVal.append("\n" + "Execution time: " + time); + } + if (StringUtils.isNotBlank(result)) { + stringVal.append("\n" + "Result: " + result); + } + stringVal.append("\n" + "Output: " + output); + return stringVal.toString(); } } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index ed9b3301..dde0421f 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -180,7 +180,8 @@ private ExecutionResult executeScript(ResourceResolver resolver, String path) { GroovyConsoleRequest request = new GroovyConsoleRequest(resolver); RunScriptResponse response = groovyConsoleService.runScript(request, path); boolean success = StringUtils.isBlank(response.getExceptionStackTrace()); - return new ExecutionResult(success, response.getRunningTime(), response.getOutput() + response.getExceptionStackTrace()); + String result = response.getResult(); + return new ExecutionResult(success, response.getRunningTime(), result, response.getOutput() + response.getExceptionStackTrace()); } } diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy index b5b89ba4..dc9ea89f 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy @@ -1 +1,2 @@ -println "Executing project2 - script1" \ No newline at end of file +println "Executing project2 - script1" +return "Done" From 5b41200a2adf4750d5afc7ed16d842809712b46e Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Wed, 9 May 2018 15:34:30 +0200 Subject: [PATCH 011/122] added fallback script --- .../valtech/aecu/service/ExecutionResult.java | 17 +++++++++- .../aecu/core/service/AecuServiceImpl.java | 27 +++++++++++++++- .../core/service/AecuServiceImplTest.java | 31 +++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java index 085eabb7..42404969 100644 --- a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -29,6 +29,7 @@ public class ExecutionResult { private String output; private String time; private String result; + private ExecutionResult fallbackResult; /** * Constructor @@ -37,12 +38,14 @@ public class ExecutionResult { * @param time execution time * @param result result * @param output script output + * @param fallbackResult fallback script result */ - public ExecutionResult(boolean success, String time, String result, String output) { + public ExecutionResult(boolean success, String time, String result, String output, ExecutionResult fallbackResult) { this.success = success; this.output = output; this.time = time; this.result = result; + this.fallbackResult = fallbackResult; } /** @@ -81,6 +84,15 @@ public String getTime() { return time; } + /** + * Returns the fallback script result if any. + * + * @return result + */ + public ExecutionResult getFallbackResult() { + return fallbackResult; + } + @Override public String toString() { StringBuilder stringVal = new StringBuilder("Successful: " + Boolean.toString(success)); @@ -91,6 +103,9 @@ public String toString() { stringVal.append("\n" + "Result: " + result); } stringVal.append("\n" + "Output: " + output); + if (fallbackResult != null) { + stringVal.append("Fallback script executed:\n" + fallbackResult.toString()); + } return stringVal.toString(); } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index dde0421f..3d77c783 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -181,7 +181,32 @@ private ExecutionResult executeScript(ResourceResolver resolver, String path) { RunScriptResponse response = groovyConsoleService.runScript(request, path); boolean success = StringUtils.isBlank(response.getExceptionStackTrace()); String result = response.getResult(); - return new ExecutionResult(success, response.getRunningTime(), result, response.getOutput() + response.getExceptionStackTrace()); + ExecutionResult fallbackResult = null; + if (!success && (getFallbackScript(resolver, path) != null)) { + fallbackResult = executeScript(resolver, getFallbackScript(resolver, path)); + } + return new ExecutionResult(success, response.getRunningTime(), result, response.getOutput() + response.getExceptionStackTrace(), fallbackResult); + } + + /** + * Returns the fallback script name if any exists. + * + * @param resolver resource resolver + * @param path original script path + * @return fallback script path + */ + protected String getFallbackScript(ResourceResolver resolver, String path) { + String name = path.substring(path.lastIndexOf("/") + 1); + if (name.contains(".fallback.")) { + // skip if script is a fallback script itself + return null; + } + String baseName = name.substring(0, name.indexOf(".")); + String fallbackPath = path.substring(0, path.lastIndexOf("/") + 1) + baseName + ".fallback.groovy"; + if (resolver.getResource(fallbackPath) != null) { + return fallbackPath; + } + return null; } } diff --git a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java index ffa9ed82..ab6557f8 100644 --- a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java +++ b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java @@ -16,13 +16,20 @@ */ package de.valtech.aecu.core.service; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.HashSet; import java.util.Set; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.settings.SlingSettingsService; import org.junit.Before; import org.junit.Test; @@ -45,6 +52,9 @@ public class AecuServiceImplTest { @Mock private SlingSettingsService settingsService; + @Mock + private ResourceResolver resolver; + @Before public void setup() { Set runModes = new HashSet<>(); @@ -99,5 +109,26 @@ public void isValidScriptName_invalidExtension() { public void isValidScriptName_fallback() { assertFalse(service.isValidScriptName("test.fallback.groovy")); } + + @Test + public void getFallbackScript_Exists() { + when(resolver.getResource("/path/to/script.fallback.groovy")).thenReturn(mock(Resource.class)); + + assertEquals("/path/to/script.fallback.groovy", service.getFallbackScript(resolver, "/path/to/script.always.groovy")); + assertEquals("/path/to/script.fallback.groovy", service.getFallbackScript(resolver, "/path/to/script.groovy")); + } + + @Test + public void getFallbackScript_NotExists() { + assertNull(service.getFallbackScript(resolver, "/path/to/script.always.groovy")); + assertNull(service.getFallbackScript(resolver, "/path/to/script.groovy")); + } + + @Test + public void getFallbackScript_Fallback() { + verify(resolver, never()).getResource("/path/to/script.fallback.groovy"); + + assertNull(service.getFallbackScript(resolver, "/path/to/script.fallback.groovy")); + } } From cb9d88ef9293f7dff27c78ba23741ce6858f2d23 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 11 May 2018 09:06:39 +0200 Subject: [PATCH 012/122] added logo --- bundle/pom.xml | 4 ++++ .../META-INF/vault/definition/thumbnail.png | Bin 0 -> 1874 bytes bundle/src/main/content/jcr_root/.gitignore | 1 + examples/pom.xml | 4 ++++ .../META-INF/vault/definition/thumbnail.png | Bin 0 -> 1874 bytes ui.apps/pom.xml | 4 ++++ .../META-INF/vault/definition/thumbnail.png | Bin 0 -> 1874 bytes 7 files changed, 13 insertions(+) create mode 100644 bundle/src/main/content/META-INF/vault/definition/thumbnail.png create mode 100644 bundle/src/main/content/jcr_root/.gitignore create mode 100644 examples/src/main/content/META-INF/vault/definition/thumbnail.png create mode 100644 ui.apps/src/main/content/META-INF/vault/definition/thumbnail.png diff --git a/bundle/pom.xml b/bundle/pom.xml index c90d6196..a1eaa12a 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -33,6 +33,10 @@ **/pom.xml + + src/main/content/META-INF/vault/definition + ../vault-work/META-INF/vault/definition + diff --git a/bundle/src/main/content/META-INF/vault/definition/thumbnail.png b/bundle/src/main/content/META-INF/vault/definition/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..c4548ee8bb2146e82d2f00bbe1c2dfb58b55694d GIT binary patch literal 1874 zcmV-Y2d(&tP)d`tAr5a+P?0i5kN{eOSnacG~T3x7}^KyMFLLW->na?%sA` z8z*`4+-F|T%sKNv|8s7QaVplw$v|D7HJ~pzGt3cOtdH$L2ax34ADlTbmTT0+D<$)9flJ4Ff%b9S-1~udX5W(mf-_hj&j*$PeQH}CocZPv zppdso?o=NAe^SU$@twof(S@@9a)hAP@Ce^;4rDcgkB zZiw}f;7o#=nZTKV(V=bw)&*z!^1h=e{l)izMu(W@vp&8XI7Lo(JMdg^W>2$qv$5~d zjqH%jF9v6NMj>-8lj~eyHn10XAvm+O#XbLLLhIu^;GwK;Juny8kxyiOJP+_dr>eRE z6Py{cKF$H|2Hw?Roj(9K2WK`U0j-Z4fm5?SCjsXavQ*yc#Kx?T6M#+^Y{1TX2jDH-MADr3UDrEg$R*}jXz|2A! z$nx_|{}>puK3)kt(?l5n9|ZnreLSZXYZ>8Yb^t#Ie%e48hy`_7A1^JGF-fFhSp#JN zd=%JXeY~m(tX?OjPpxSG2=KD?@vW^Yq!;*IR@VkxRP<}p0;%i;R_bt<6uu|`cL5Io zI|~+d`v~%E0)7EJUDS60_XEGm>XrbXDEh4t9o?SQO$6>O4(1LWX6~>4sde`ikaU;z z@$?38^#T3fCKT9S%y|Ov)s_?zoH?jCAjj?bg=1@%#ia5w5Uh`v05h`smBE>_1W(rk zbAX<#{rqOa1ZQ3f&fEZeuV{KEICG;QVA%R-E0l3TaOOhbV}id&vbLF$Dfx>li-Y}2 zaOT9|%!g#{>x!|LHxYYLaAp>8QE+C4kRy+o&a^&uw#u@eC}8VC>*G<$Sp%2I(o%Uc zII~aJeMJ`FeK&WOvY5d!pqCW$&I2Z7P2UdAtWA9++t-R4`dPit(;@#imI%(=W__#) z(hdN(0$YLCfY*Ujt&dfV^kLvfiD>Bkje^o2Rmj?$Wl4zL*2k5=%~{*^z*7DGLNV?q z+WbSw2`d$Hw)OEdVjFJ*F-Zl$U$7m*E0-FBVj% zw9Zfk4Sp^kr}nyx`}j@3Z$ zX5!wri4|=L&g`{5UJgtdD}jSE1J=h<$@Ar}YE67mT}*0k(dX!#ipxMdfOljFvL`t6 zkMW4qUl8>?Nsj1Ky5@Q8kt?udA6KWSJcF0EH$d)eo=PdX+yohsw}wbsKDs{>@e!U7Z1^?mzF*;9dK}F z5LhmLpV-Tt*2mSr=HSc$>*GY=YQ;3E^aN+7S|49jtT9>jU$;I!2)tr_90HCNQslS# z*#=I%)x6nAzICv@fP+En<0@dG=vsThJpPufC^*w^ecVwv$=_&mor=!qAL0!u|Ma=o z`nXJ)ft!LeYpsvV6>|(r);|F&B-1SZ_rHo8^?piwxgb;iI??w&;M^jm^NQLIx3mGD z)9o9qFu(!e%T>w6r^UZ#7pd|U;`e#N?3N;WzCsawUCP`nD?UE6lxe}4?h%ClbMbu~ z@Jao?N$+cw_L-BYZwhED$`7P0f;0P-zuN#DqxMO_#~b`ba7}RL^)bqCv;Zcy<9hXoP3-53}+`f-{@SRC4A|PF7mP=m0kcXP#G| zDT1{mR4q8uWqmv$^8q#BRi$zA`HvB)n4+=!gEMO?**/pom.xml + + src/main/content/META-INF/vault/definition + ../vault-work/META-INF/vault/definition + diff --git a/examples/src/main/content/META-INF/vault/definition/thumbnail.png b/examples/src/main/content/META-INF/vault/definition/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..c4548ee8bb2146e82d2f00bbe1c2dfb58b55694d GIT binary patch literal 1874 zcmV-Y2d(&tP)d`tAr5a+P?0i5kN{eOSnacG~T3x7}^KyMFLLW->na?%sA` z8z*`4+-F|T%sKNv|8s7QaVplw$v|D7HJ~pzGt3cOtdH$L2ax34ADlTbmTT0+D<$)9flJ4Ff%b9S-1~udX5W(mf-_hj&j*$PeQH}CocZPv zppdso?o=NAe^SU$@twof(S@@9a)hAP@Ce^;4rDcgkB zZiw}f;7o#=nZTKV(V=bw)&*z!^1h=e{l)izMu(W@vp&8XI7Lo(JMdg^W>2$qv$5~d zjqH%jF9v6NMj>-8lj~eyHn10XAvm+O#XbLLLhIu^;GwK;Juny8kxyiOJP+_dr>eRE z6Py{cKF$H|2Hw?Roj(9K2WK`U0j-Z4fm5?SCjsXavQ*yc#Kx?T6M#+^Y{1TX2jDH-MADr3UDrEg$R*}jXz|2A! z$nx_|{}>puK3)kt(?l5n9|ZnreLSZXYZ>8Yb^t#Ie%e48hy`_7A1^JGF-fFhSp#JN zd=%JXeY~m(tX?OjPpxSG2=KD?@vW^Yq!;*IR@VkxRP<}p0;%i;R_bt<6uu|`cL5Io zI|~+d`v~%E0)7EJUDS60_XEGm>XrbXDEh4t9o?SQO$6>O4(1LWX6~>4sde`ikaU;z z@$?38^#T3fCKT9S%y|Ov)s_?zoH?jCAjj?bg=1@%#ia5w5Uh`v05h`smBE>_1W(rk zbAX<#{rqOa1ZQ3f&fEZeuV{KEICG;QVA%R-E0l3TaOOhbV}id&vbLF$Dfx>li-Y}2 zaOT9|%!g#{>x!|LHxYYLaAp>8QE+C4kRy+o&a^&uw#u@eC}8VC>*G<$Sp%2I(o%Uc zII~aJeMJ`FeK&WOvY5d!pqCW$&I2Z7P2UdAtWA9++t-R4`dPit(;@#imI%(=W__#) z(hdN(0$YLCfY*Ujt&dfV^kLvfiD>Bkje^o2Rmj?$Wl4zL*2k5=%~{*^z*7DGLNV?q z+WbSw2`d$Hw)OEdVjFJ*F-Zl$U$7m*E0-FBVj% zw9Zfk4Sp^kr}nyx`}j@3Z$ zX5!wri4|=L&g`{5UJgtdD}jSE1J=h<$@Ar}YE67mT}*0k(dX!#ipxMdfOljFvL`t6 zkMW4qUl8>?Nsj1Ky5@Q8kt?udA6KWSJcF0EH$d)eo=PdX+yohsw}wbsKDs{>@e!U7Z1^?mzF*;9dK}F z5LhmLpV-Tt*2mSr=HSc$>*GY=YQ;3E^aN+7S|49jtT9>jU$;I!2)tr_90HCNQslS# z*#=I%)x6nAzICv@fP+En<0@dG=vsThJpPufC^*w^ecVwv$=_&mor=!qAL0!u|Ma=o z`nXJ)ft!LeYpsvV6>|(r);|F&B-1SZ_rHo8^?piwxgb;iI??w&;M^jm^NQLIx3mGD z)9o9qFu(!e%T>w6r^UZ#7pd|U;`e#N?3N;WzCsawUCP`nD?UE6lxe}4?h%ClbMbu~ z@Jao?N$+cw_L-BYZwhED$`7P0f;0P-zuN#DqxMO_#~b`ba7}RL^)bqCv;Zcy<9hXoP3-53}+`f-{@SRC4A|PF7mP=m0kcXP#G| zDT1{mR4q8uWqmv$^8q#BRi$zA`HvB)n4+=!gEMO?**/pom.xml + + src/main/content/META-INF/vault/definition + ../vault-work/META-INF/vault/definition + diff --git a/ui.apps/src/main/content/META-INF/vault/definition/thumbnail.png b/ui.apps/src/main/content/META-INF/vault/definition/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..c4548ee8bb2146e82d2f00bbe1c2dfb58b55694d GIT binary patch literal 1874 zcmV-Y2d(&tP)d`tAr5a+P?0i5kN{eOSnacG~T3x7}^KyMFLLW->na?%sA` z8z*`4+-F|T%sKNv|8s7QaVplw$v|D7HJ~pzGt3cOtdH$L2ax34ADlTbmTT0+D<$)9flJ4Ff%b9S-1~udX5W(mf-_hj&j*$PeQH}CocZPv zppdso?o=NAe^SU$@twof(S@@9a)hAP@Ce^;4rDcgkB zZiw}f;7o#=nZTKV(V=bw)&*z!^1h=e{l)izMu(W@vp&8XI7Lo(JMdg^W>2$qv$5~d zjqH%jF9v6NMj>-8lj~eyHn10XAvm+O#XbLLLhIu^;GwK;Juny8kxyiOJP+_dr>eRE z6Py{cKF$H|2Hw?Roj(9K2WK`U0j-Z4fm5?SCjsXavQ*yc#Kx?T6M#+^Y{1TX2jDH-MADr3UDrEg$R*}jXz|2A! z$nx_|{}>puK3)kt(?l5n9|ZnreLSZXYZ>8Yb^t#Ie%e48hy`_7A1^JGF-fFhSp#JN zd=%JXeY~m(tX?OjPpxSG2=KD?@vW^Yq!;*IR@VkxRP<}p0;%i;R_bt<6uu|`cL5Io zI|~+d`v~%E0)7EJUDS60_XEGm>XrbXDEh4t9o?SQO$6>O4(1LWX6~>4sde`ikaU;z z@$?38^#T3fCKT9S%y|Ov)s_?zoH?jCAjj?bg=1@%#ia5w5Uh`v05h`smBE>_1W(rk zbAX<#{rqOa1ZQ3f&fEZeuV{KEICG;QVA%R-E0l3TaOOhbV}id&vbLF$Dfx>li-Y}2 zaOT9|%!g#{>x!|LHxYYLaAp>8QE+C4kRy+o&a^&uw#u@eC}8VC>*G<$Sp%2I(o%Uc zII~aJeMJ`FeK&WOvY5d!pqCW$&I2Z7P2UdAtWA9++t-R4`dPit(;@#imI%(=W__#) z(hdN(0$YLCfY*Ujt&dfV^kLvfiD>Bkje^o2Rmj?$Wl4zL*2k5=%~{*^z*7DGLNV?q z+WbSw2`d$Hw)OEdVjFJ*F-Zl$U$7m*E0-FBVj% zw9Zfk4Sp^kr}nyx`}j@3Z$ zX5!wri4|=L&g`{5UJgtdD}jSE1J=h<$@Ar}YE67mT}*0k(dX!#ipxMdfOljFvL`t6 zkMW4qUl8>?Nsj1Ky5@Q8kt?udA6KWSJcF0EH$d)eo=PdX+yohsw}wbsKDs{>@e!U7Z1^?mzF*;9dK}F z5LhmLpV-Tt*2mSr=HSc$>*GY=YQ;3E^aN+7S|49jtT9>jU$;I!2)tr_90HCNQslS# z*#=I%)x6nAzICv@fP+En<0@dG=vsThJpPufC^*w^ecVwv$=_&mor=!qAL0!u|Ma=o z`nXJ)ft!LeYpsvV6>|(r);|F&B-1SZ_rHo8^?piwxgb;iI??w&;M^jm^NQLIx3mGD z)9o9qFu(!e%T>w6r^UZ#7pd|U;`e#N?3N;WzCsawUCP`nD?UE6lxe}4?h%ClbMbu~ z@Jao?N$+cw_L-BYZwhED$`7P0f;0P-zuN#DqxMO_#~b`ba7}RL^)bqCv;Zcy<9hXoP3-53}+`f-{@SRC4A|PF7mP=m0kcXP#G| zDT1{mR4q8uWqmv$^8q#BRi$zA`HvB)n4+=!gEMO? Date: Fri, 11 May 2018 13:50:57 +0200 Subject: [PATCH 013/122] started history feature --- .../de/valtech/aecu/service/AecuService.java | 7 ++ .../de/valtech/aecu/service/HistoryEntry.java | 83 +++++++++++++++++++ .../aecu/core/service/AecuServiceImpl.java | 7 ++ .../aecu/core/service/HistoryEntryImpl.java | 60 ++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 api/src/main/java/de/valtech/aecu/service/HistoryEntry.java create mode 100644 core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 373eeb74..ac6c1ad3 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -52,5 +52,12 @@ public interface AecuService { * @throws AecuException error during execution */ ExecutionResult execute(String path) throws AecuException; + + /** + * Starts a new history entry. + * + * @return history entry + */ + HistoryEntry createHistoryEntry(); } diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java new file mode 100644 index 00000000..fb3063db --- /dev/null +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -0,0 +1,83 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.service; + +import java.util.Date; +import java.util.List; + +/** + * History entry for an execution run. + * + * @author Roland Gruber + * + */ +public interface HistoryEntry { + + /** + * Execution state (e.g. running) + */ + public enum STATE { + STARTED, + RUNNING, + FINISHED + }; + + /** + * Execution result (e.g. successful) + */ + public enum RESULT { + SUCCESS, + FAILURE, + UNKNOWN + }; + + /** + * Returns the start time of the execution. + * + * @return start + */ + Date getStart(); + + /** + * Returns the end time of the execution. + * + * @return end + */ + Date getEnd(); + + /** + * Returns the single script runs. + * + * @return single results + */ + List getSingleResults(); + + /** + * Returns the current state of the run. + * + * @return state + */ + STATE getState(); + + /** + * Returns the global result of the run. + * + * @return result + */ + RESULT getResult(); + +} diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 3d77c783..2e09d338 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -39,6 +39,7 @@ import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; import de.valtech.aecu.service.ExecutionResult; +import de.valtech.aecu.service.HistoryEntry; /** * AECU service. @@ -209,4 +210,10 @@ protected String getFallbackScript(ResourceResolver resolver, String path) { return null; } + @Override + public HistoryEntry createHistoryEntry() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java new file mode 100644 index 00000000..a352c1a7 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.service; + +import java.util.Date; +import java.util.List; + +import de.valtech.aecu.service.ExecutionResult; +import de.valtech.aecu.service.HistoryEntry; + +/** + * Implementation of history entry. + * + * @author Roland Gruber + */ +public class HistoryEntryImpl implements HistoryEntry { + + private String path; + private Date start; + private Date end; + private List singleResults; + + @Override + public Date getStart() { + return start; + } + @Override + public Date getEnd() { + return end; + } + @Override + public List getSingleResults() { + return singleResults; + } + @Override + public STATE getState() { + // TODO Auto-generated method stub + return STATE.RUNNING; + } + @Override + public RESULT getResult() { + // TODO Auto-generated method stub + return RESULT.UNKNOWN; + } + +} From 783a2115e8ef2037238bd714ba27f9dde7a5566f Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 11 May 2018 13:54:35 +0200 Subject: [PATCH 014/122] added path --- .../main/java/de/valtech/aecu/service/HistoryEntry.java | 7 +++++++ .../de/valtech/aecu/core/service/HistoryEntryImpl.java | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java index fb3063db..31ead3a3 100644 --- a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -80,4 +80,11 @@ public enum RESULT { */ RESULT getResult(); + /** + * Returns the path in repository where the history is stored. + * + * @return path + */ + String getRepositoryPath(); + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index a352c1a7..6bcf740d 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -56,5 +56,10 @@ public RESULT getResult() { // TODO Auto-generated method stub return RESULT.UNKNOWN; } + @Override + public String getRepositoryPath() { + // TODO Auto-generated method stub + return path; + } } From d708158264cd41a8f8e0d4eae1650ab60d5dc4fa Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 11 May 2018 15:59:54 +0200 Subject: [PATCH 015/122] started history creation --- .../de/valtech/aecu/service/AecuService.java | 3 +- .../de/valtech/aecu/service/HistoryEntry.java | 1 - .../aecu/core/jmx/AecuServiceMBeanImpl.java | 2 + .../aecu/core/service/AecuServiceImpl.java | 80 ++++++++++++++++++- .../aecu/core/service/HistoryEntryImpl.java | 27 +++++++ .../core/service/AecuServiceImplTest.java | 30 +++++++ .../main/content/META-INF/vault/filter.xml | 1 + .../content/jcr_root/var/aecu/.content.xml | 4 + .../content/jcr_root/var/aecu/_rep_policy.xml | 8 ++ 9 files changed, 151 insertions(+), 5 deletions(-) create mode 100644 ui.apps/src/main/content/jcr_root/var/aecu/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index ac6c1ad3..de370f6c 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -57,7 +57,8 @@ public interface AecuService { * Starts a new history entry. * * @return history entry + * @throws AecuException error setting up entry */ - HistoryEntry createHistoryEntry(); + HistoryEntry createHistoryEntry() throws AecuException; } diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java index 31ead3a3..d5e989b0 100644 --- a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -31,7 +31,6 @@ public interface HistoryEntry { * Execution state (e.g. running) */ public enum STATE { - STARTED, RUNNING, FINISHED }; diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 7e45967c..21551bcc 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -27,6 +27,7 @@ import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.HistoryEntry; @Component(service = {AecuServiceMBean.class}, immediate = true, property = { "jmx.objectname=de.valtech:type=AECU", @@ -58,6 +59,7 @@ public List getFiles(String path) throws AecuException { @Override public String execute(String path) throws AecuException { + HistoryEntry history = aecuService.createHistoryEntry(); List files = aecuService.getFiles(path); StringBuilder result = new StringBuilder("Found " + files.size() + " files to execute\n\n"); for (String file : files) { diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 2e09d338..722a4f47 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -18,12 +18,19 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Random; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.JcrConstants; import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.jcr.resource.api.JcrResourceConstants; @@ -40,6 +47,8 @@ import de.valtech.aecu.service.AecuService; import de.valtech.aecu.service.ExecutionResult; import de.valtech.aecu.service.HistoryEntry; +import de.valtech.aecu.service.HistoryEntry.RESULT; +import de.valtech.aecu.service.HistoryEntry.STATE; /** * AECU service. @@ -49,6 +58,14 @@ @Component(service=AecuService.class) public class AecuServiceImpl implements AecuService { + private static final String ATTR_RESULT = "result"; + + private static final String ATTR_STATE = "state"; + + private static final String ATTR_START = "start"; + + private static final String HISTORY_BASE = "/var/aecu"; + @Reference private ServiceResourceResolverService resolverService; @@ -211,9 +228,66 @@ protected String getFallbackScript(ResourceResolver resolver, String path) { } @Override - public HistoryEntry createHistoryEntry() { - // TODO Auto-generated method stub - return null; + public HistoryEntry createHistoryEntry() throws AecuException { + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + HistoryEntryImpl history = new HistoryEntryImpl(); + Calendar start = new GregorianCalendar(); + String basePath = HISTORY_BASE + "/" + start.get(Calendar.YEAR) + "/" + (start.get(Calendar.MONTH) + 1) + "/" + start.get(Calendar.DAY_OF_MONTH); + String nodeName = generateHistoryNodeName(); + String nodePath = basePath + "/" + nodeName; + createPath(basePath, resolver, JcrResourceConstants.NT_SLING_FOLDER); + createPath(nodePath, resolver, JcrConstants.NT_UNSTRUCTURED); + Resource resource = resolver.getResource(nodePath); + ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); + values.put(ATTR_START, start); + values.put(ATTR_STATE, STATE.RUNNING.name()); + values.put(ATTR_RESULT, RESULT.UNKNOWN.name()); + try { + resolver.commit(); + } catch (PersistenceException e) { + throw new AecuException("Unable to create " + nodePath, e); + } + return history; + } + catch (LoginException e) { + throw new AecuException("Unable to get service resource resolver", e); + } + } + + /** + * Creates the folder at the given path if not yet existing. + * + * @param path path + * @param resolver resource resolver + * @param primaryType primary type + * @throws AecuException error creating folder + */ + protected void createPath(String path, ResourceResolver resolver, String primaryType) throws AecuException { + Resource folder = resolver.getResource(path); + if (folder == null) { + String parent = path.substring(0, path.lastIndexOf("/")); + String name = path.substring(path.lastIndexOf("/") + 1); + if (resolver.getResource(parent) == null) { + createPath(parent, resolver, primaryType); + } + Map properties = new HashMap<>(); + properties.put(JcrConstants.JCR_PRIMARYTYPE, primaryType); + try { + resolver.create(resolver.getResource(parent), name, properties); + } catch (PersistenceException e) { + throw new AecuException("Unable to create " + path, e); + } + } + } + + /** + * Generates the node name for a history entry. + * + * @return name + */ + private String generateHistoryNodeName() { + Random random = new Random(); + return System.currentTimeMillis() + "" + random.nextInt(100000); } } diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index 6bcf740d..4cb14c2b 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -61,5 +61,32 @@ public String getRepositoryPath() { // TODO Auto-generated method stub return path; } + + /** + * Sets the start date. + * + * @param start start date + */ + protected void setStart(Date start) { + this.start = start; + } + + /** + * Sets the end date. + * + * @param end end date + */ + protected void setEnd(Date end) { + this.end = end; + } + + /** + * Sets the node path. + * + * @param path node path + */ + protected void setPath(String path) { + this.path = path; + } } diff --git a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java index ab6557f8..136a1a74 100644 --- a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java +++ b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java @@ -20,24 +20,33 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.HashSet; import java.util.Set; +import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.jcr.resource.api.JcrResourceConstants; import org.apache.sling.settings.SlingSettingsService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; +import de.valtech.aecu.service.AecuException; + /** * Tests AecuServiceImpl * @@ -47,6 +56,7 @@ public class AecuServiceImplTest { @InjectMocks + @Spy private AecuServiceImpl service; @Mock @@ -130,5 +140,25 @@ public void getFallbackScript_Fallback() { assertNull(service.getFallbackScript(resolver, "/path/to/script.fallback.groovy")); } + + @Test + public void createPath_Existing() throws AecuException { + String path = "/var/aecu/2018/5"; + when(resolver.getResource(path)).thenReturn(mock(Resource.class)); + + service.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); + + verify(service, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); + } + @Test + public void createPath_NotExisting() throws AecuException, PersistenceException { + String path = "/var/aecu/2018/5"; + when(resolver.getResource("/var/aecu/2018")).thenReturn(mock(Resource.class)); + + service.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); + + verify(service, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); + verify(resolver, times(1)).create(any(Resource.class), eq("5"), any()); + } } diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index f8d1b003..4b6c9117 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -6,4 +6,5 @@ + diff --git a/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml new file mode 100644 index 00000000..1db66005 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml b/ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml new file mode 100644 index 00000000..118b223d --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file From 8fc0a4a82cf6300991a45c45599b2c1b9c0cb9bc Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 11 May 2018 16:13:45 +0200 Subject: [PATCH 016/122] close history --- .../de/valtech/aecu/service/AecuService.java | 9 +++++ .../aecu/core/jmx/AecuServiceMBeanImpl.java | 1 + .../aecu/core/service/AecuServiceImpl.java | 34 ++++++++++++++++++- .../aecu/core/service/HistoryEntryImpl.java | 3 +- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index de370f6c..0e9cb6d6 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -60,5 +60,14 @@ public interface AecuService { * @throws AecuException error setting up entry */ HistoryEntry createHistoryEntry() throws AecuException; + + /** + * Finishes the history entry. + * + * @param history open history entry + * @return history entry + * @throws AecuException error saving state + */ + HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuException; } diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 21551bcc..e334894c 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -67,6 +67,7 @@ public String execute(String path) throws AecuException { result.append(aecuService.execute(file).toString()); result.append("\n\n"); } + aecuService.finishHistoryEntry(history); return result.toString(); } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 722a4f47..98a467dc 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -64,6 +64,8 @@ public class AecuServiceImpl implements AecuService { private static final String ATTR_START = "start"; + private static final String ATTR_END = "end"; + private static final String HISTORY_BASE = "/var/aecu"; @Reference @@ -242,10 +244,12 @@ public HistoryEntry createHistoryEntry() throws AecuException { values.put(ATTR_START, start); values.put(ATTR_STATE, STATE.RUNNING.name()); values.put(ATTR_RESULT, RESULT.UNKNOWN.name()); + history.setStart(start.getTime()); + history.setPath(nodePath); try { resolver.commit(); } catch (PersistenceException e) { - throw new AecuException("Unable to create " + nodePath, e); + throw new AecuException("Unable to create history " + nodePath, e); } return history; } @@ -290,4 +294,32 @@ private String generateHistoryNodeName() { return System.currentTimeMillis() + "" + random.nextInt(100000); } + @Override + public HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuException { + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + try { + Resource resource = resolver.getResource(history.getRepositoryPath()); + ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); + Calendar end = new GregorianCalendar(); + values.put(ATTR_END, end); + values.put(ATTR_STATE, STATE.FINISHED.name()); + RESULT result = RESULT.SUCCESS; + for (ExecutionResult singleResult : history.getSingleResults()) { + if (!singleResult.isSuccess()) { + result = RESULT.FAILURE; + break; + } + } + values.put(ATTR_RESULT, result.name()); + resolver.commit(); + } catch (PersistenceException e) { + throw new AecuException("Unable to finish history " + history.getRepositoryPath(), e); + } + return history; + } + catch (LoginException e) { + throw new AecuException("Unable to get service resource resolver", e); + } + } + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index 4cb14c2b..9bf7829e 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -16,6 +16,7 @@ */ package de.valtech.aecu.core.service; +import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -32,7 +33,7 @@ public class HistoryEntryImpl implements HistoryEntry { private String path; private Date start; private Date end; - private List singleResults; + private List singleResults = new ArrayList<>(); @Override public Date getStart() { From 2187118ba9799edfe54257d49077f62696a4b739 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 11 May 2018 16:22:37 +0200 Subject: [PATCH 017/122] refactoring --- .../aecu/core/service/AecuServiceImpl.java | 9 +-------- .../aecu/core/service/HistoryEntryImpl.java | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 98a467dc..a86dc619 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -303,14 +303,7 @@ public HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuExceptio Calendar end = new GregorianCalendar(); values.put(ATTR_END, end); values.put(ATTR_STATE, STATE.FINISHED.name()); - RESULT result = RESULT.SUCCESS; - for (ExecutionResult singleResult : history.getSingleResults()) { - if (!singleResult.isSuccess()) { - result = RESULT.FAILURE; - break; - } - } - values.put(ATTR_RESULT, result.name()); + values.put(ATTR_RESULT, history.getResult().name()); resolver.commit(); } catch (PersistenceException e) { throw new AecuException("Unable to finish history " + history.getRepositoryPath(), e); diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index 9bf7829e..789fd1ef 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -39,27 +39,40 @@ public class HistoryEntryImpl implements HistoryEntry { public Date getStart() { return start; } + @Override public Date getEnd() { return end; } + @Override public List getSingleResults() { return singleResults; } + @Override public STATE getState() { // TODO Auto-generated method stub return STATE.RUNNING; } + @Override public RESULT getResult() { - // TODO Auto-generated method stub - return RESULT.UNKNOWN; + if (singleResults.isEmpty()) { + return RESULT.UNKNOWN; + } + RESULT result = RESULT.SUCCESS; + for (ExecutionResult singleResult : singleResults) { + if (!singleResult.isSuccess()) { + result = RESULT.FAILURE; + break; + } + } + return result; } + @Override public String getRepositoryPath() { - // TODO Auto-generated method stub return path; } From c402161b521f54aea065cadd1b98bb335349074f Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Mon, 14 May 2018 10:53:56 +0200 Subject: [PATCH 018/122] store script execution in history --- .../de/valtech/aecu/service/AecuService.java | 10 +++ .../aecu/core/jmx/AecuServiceMBeanImpl.java | 5 +- .../aecu/core/service/AecuServiceImpl.java | 69 ++++++++++++++++--- 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 0e9cb6d6..0363aa8c 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -61,6 +61,16 @@ public interface AecuService { */ HistoryEntry createHistoryEntry() throws AecuException; + /** + * Stores an execution run in existing history. + * + * @param history history entry + * @param result script execution result + * @return updated history + * @throws AecuException error inserting history entry + */ + HistoryEntry storeExecutionInHistory(HistoryEntry history, ExecutionResult result) throws AecuException; + /** * Finishes the history entry. * diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index e334894c..34cfb970 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -27,6 +27,7 @@ import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.ExecutionResult; import de.valtech.aecu.service.HistoryEntry; @Component(service = {AecuServiceMBean.class}, immediate = true, property = { @@ -64,7 +65,9 @@ public String execute(String path) throws AecuException { StringBuilder result = new StringBuilder("Found " + files.size() + " files to execute\n\n"); for (String file : files) { result.append(file + "\n"); - result.append(aecuService.execute(file).toString()); + ExecutionResult singleResult = aecuService.execute(file); + aecuService.storeExecutionInHistory(history, singleResult); + result.append(singleResult.toString()); result.append("\n\n"); } aecuService.finishHistoryEntry(history); diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index a86dc619..438ef48e 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -58,6 +58,14 @@ @Component(service=AecuService.class) public class AecuServiceImpl implements AecuService { + private static final String ATTR_RUN_OUTPUT = "runOutput"; + + private static final String ATTR_RUN_SUCCESS = "runSuccess"; + + private static final String ATTR_RUN_RESULT = "runResult"; + + private static final String ATTR_RUN_TIME = "runTime"; + private static final String ATTR_RESULT = "result"; private static final String ATTR_STATE = "state"; @@ -297,22 +305,61 @@ private String generateHistoryNodeName() { @Override public HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuException { try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { - try { - Resource resource = resolver.getResource(history.getRepositoryPath()); - ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); - Calendar end = new GregorianCalendar(); - values.put(ATTR_END, end); - values.put(ATTR_STATE, STATE.FINISHED.name()); - values.put(ATTR_RESULT, history.getResult().name()); - resolver.commit(); - } catch (PersistenceException e) { - throw new AecuException("Unable to finish history " + history.getRepositoryPath(), e); - } + Resource resource = resolver.getResource(history.getRepositoryPath()); + ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); + Calendar end = new GregorianCalendar(); + values.put(ATTR_END, end); + values.put(ATTR_STATE, STATE.FINISHED.name()); + values.put(ATTR_RESULT, history.getResult().name()); + resolver.commit(); return history; } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); } + catch (PersistenceException e) { + throw new AecuException("Unable to finish history " + history.getRepositoryPath(), e); + } + } + + @Override + public HistoryEntry storeExecutionInHistory(HistoryEntry history, ExecutionResult result) throws AecuException { + if ((history == null) || !STATE.RUNNING.equals(history.getState())) { + throw new AecuException("Invalid history entry."); + } + history.getSingleResults().add(result); + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + String path = history.getRepositoryPath() + "/" + history.getSingleResults().size(); + saveExecutionResultInHistory(result, path, resolver); + resolver.commit(); + return history; + } + catch (LoginException e) { + throw new AecuException("Unable to get service resource resolver", e); + } + catch (PersistenceException e) { + throw new AecuException("Unable to add history entry " + history.getRepositoryPath(), e); + } + } + + private void saveExecutionResultInHistory(ExecutionResult result, String path, ResourceResolver resolver) throws AecuException { + createPath(path, resolver, "nt:unstructured"); + Resource entry = resolver.getResource(path); + ModifiableValueMap values = entry.adaptTo(ModifiableValueMap.class); + values.put(ATTR_RUN_SUCCESS, result.isSuccess()); + if (StringUtils.isNotBlank(result.getOutput())) { + values.put(ATTR_RUN_OUTPUT, result.getOutput()); + } + if (StringUtils.isNotBlank(result.getResult())) { + values.put(ATTR_RUN_RESULT, result.getResult()); + } + if (StringUtils.isNotBlank(result.getTime())) { + values.put(ATTR_RUN_TIME, result.getTime()); + } + if (result.getFallbackResult() != null) { + String fallbackPath = path + "/fallback"; + saveExecutionResultInHistory(result.getFallbackResult(), fallbackPath, resolver); + } } } From 35bd6d1989610052cffd633e63abf72713e34115 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Wed, 16 May 2018 09:39:13 +0200 Subject: [PATCH 019/122] added health check for last run, refactored history methods --- .../de/valtech/aecu/service/AecuService.java | 10 + .../core/healthcheck/LastRunHealthCheck.java | 78 +++++ .../aecu/core/history/HistoryUtil.java | 283 ++++++++++++++++++ .../aecu/core/jmx/AecuServiceMBean.java | 10 + .../aecu/core/jmx/AecuServiceMBeanImpl.java | 10 + .../aecu/core/service/AecuServiceImpl.java | 125 ++------ .../aecu/core/service/HistoryEntryImpl.java | 28 +- .../aecu/core/history/HistoryUtilTest.java | 74 +++++ .../core/service/AecuServiceImplTest.java | 28 -- 9 files changed, 507 insertions(+), 139 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java create mode 100644 core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java create mode 100644 core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 0363aa8c..7c759df1 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -79,5 +79,15 @@ public interface AecuService { * @throws AecuException error saving state */ HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuException; + + /** + * Returns the last history entries. The search starts at the newest entry. + * + * @param startIndex start reading at this index + * @param count number of entries to read + * @return history entries (newest first) + * @throws AecuException error reading history + */ + List getHistory(int startIndex, int count) throws AecuException; } diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java new file mode 100644 index 00000000..c972cf0b --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java @@ -0,0 +1,78 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.healthcheck; + +import java.util.List; + +import org.apache.sling.hc.api.HealthCheck; +import org.apache.sling.hc.api.Result; +import org.apache.sling.hc.util.FormattingResultLog; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.HistoryEntry; + +/** + * Checks if the last script run was ok. + * + * @author Roland Gruber + */ +@Component( + immediate = true, + service = HealthCheck.class, + property = { + HealthCheck.TAGS + "=aecu", + HealthCheck.NAME + "=AECU Last Run", + HealthCheck.MBEAN_NAME + "=aecuLastRunHCmBean" + } +) +public class LastRunHealthCheck implements HealthCheck { + + @Reference + private AecuService aecuService; + + @Override + public Result execute() { + final FormattingResultLog resultLog = new FormattingResultLog(); + try { + List history = aecuService.getHistory(0, 1); + if (history.isEmpty()) { + resultLog.info("No runs found"); + } + else { + HistoryEntry entry = history.get(0); + switch (entry.getResult()) { + case FAILURE: + resultLog.critical("Last execution failed"); + break; + case SUCCESS: + resultLog.info("Last run was successful"); + break; + case UNKNOWN: + resultLog.warn("Last execution is still running"); + break; + } + } + } catch (AecuException e) { + resultLog.critical(e.getMessage()); + } + return new Result(resultLog); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java new file mode 100644 index 00000000..78c2b0e2 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -0,0 +1,283 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.history; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.apache.commons.lang3.StringUtils; +import org.apache.jackrabbit.JcrConstants; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ValueMap; +import org.apache.sling.jcr.resource.api.JcrResourceConstants; + +import de.valtech.aecu.core.service.HistoryEntryImpl; +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.ExecutionResult; +import de.valtech.aecu.service.HistoryEntry; +import de.valtech.aecu.service.HistoryEntry.RESULT; +import de.valtech.aecu.service.HistoryEntry.STATE; + +/** + * Reads and writes history entries. + * + * @author Roland Gruber + */ +public class HistoryUtil { + + private static final String HISTORY_BASE = "/var/aecu"; + + private static final String NODE_FALLBACK = "fallback"; + + private static final String ATTR_RUN_OUTPUT = "runOutput"; + + private static final String ATTR_RUN_SUCCESS = "runSuccess"; + + private static final String ATTR_RUN_RESULT = "runResult"; + + private static final String ATTR_RUN_TIME = "runTime"; + + private static final String ATTR_RESULT = "result"; + + private static final String ATTR_STATE = "state"; + + private static final String ATTR_START = "start"; + + private static final String ATTR_END = "end"; + + /** + * Starts a new history entry. + * + * @param resolver resource resolver + * @return history entry + * @throws AecuException error setting up entry + */ + public HistoryEntry createHistoryEntry(ResourceResolver resolver) throws AecuException { + HistoryEntryImpl history = new HistoryEntryImpl(); + Calendar start = new GregorianCalendar(); + String basePath = HISTORY_BASE + "/" + start.get(Calendar.YEAR) + "/" + (start.get(Calendar.MONTH) + 1) + "/" + start.get(Calendar.DAY_OF_MONTH); + String nodeName = generateHistoryNodeName(); + String nodePath = basePath + "/" + nodeName; + createPath(basePath, resolver, JcrResourceConstants.NT_SLING_FOLDER); + createPath(nodePath, resolver, JcrConstants.NT_UNSTRUCTURED); + Resource resource = resolver.getResource(nodePath); + ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); + values.put(ATTR_START, start); + values.put(ATTR_STATE, STATE.RUNNING.name()); + values.put(ATTR_RESULT, RESULT.UNKNOWN.name()); + history.setStart(start.getTime()); + history.setRepositoryPath(nodePath); + history.setState(STATE.RUNNING); + return history; + } + + /** + * Stores an execution run in existing history. + * + * @param history history entry + * @param result script execution result + * @param resolver resource resolver + * @throws AecuException error inserting history entry + */ + public void storeExecutionInHistory(HistoryEntry history, ExecutionResult result, ResourceResolver resolver) throws AecuException { + String path = history.getRepositoryPath() + "/" + history.getSingleResults().size(); + saveExecutionResultInHistory(result, path, resolver); + } + + /** + * Finishes the history entry. + * + * @param history open history entry + * @param resolver resource resolver + * @return history entry + */ + public void finishHistoryEntry(HistoryEntry history, ResourceResolver resolver) { + Resource resource = resolver.getResource(history.getRepositoryPath()); + ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); + Calendar end = new GregorianCalendar(); + values.put(ATTR_END, end); + values.put(ATTR_STATE, STATE.FINISHED.name()); + values.put(ATTR_RESULT, history.getResult().name()); + ((HistoryEntryImpl) history).setEnd(end.getTime()); + ((HistoryEntryImpl) history).setState(STATE.FINISHED); + } + + /** + * Returns the last history entries. The search starts at the newest entry. + * + * @param startIndex start reading at this index + * @param count number of entries to read + * @param resolver resource resolver + * @return history entries (newest first) + */ + public List getHistory(int startIndex, int count, ResourceResolver resolver) { + List entries = new ArrayList<>(); + Resource base = resolver.getResource(HISTORY_BASE); + + // TODO start, count + Resource latest = getLatestHistoryEntry(base); + entries.add(readHistoryEntry(latest)); + + return entries; + } + + /** + * Returns the latest history entry. + * + * @param base base resource + * @return latest run resource + */ + private Resource getLatestHistoryEntry(Resource base) { + if (base == null) { + return null; + } + Resource lastYear = getLastChild(base); + Resource lastMonth = getLastChild(lastYear); + Resource lastDay = getLastChild(lastMonth); + Resource lastRun = getLastChild(lastDay); + return lastRun; + } + + /** + * Returns the last child of the given resource. + * + * @param resource resource + * @return last child + */ + private Resource getLastChild(Resource resource) { + if (resource == null) { + return null; + } + Resource last = null; + Iterator lastIterator = resource.listChildren(); + while (lastIterator.hasNext()) { + last = lastIterator.next(); + } + return last; + } + + /** + * Reads a history entry from JCR. + * + * @param resource history resource + * @return history entry + */ + private HistoryEntry readHistoryEntry(Resource resource) { + HistoryEntryImpl entry = new HistoryEntryImpl(); + entry.setRepositoryPath(resource.getPath()); + ValueMap values = resource.adaptTo(ValueMap.class); + entry.setState(STATE.valueOf(values.get(ATTR_STATE, String.class))); + if (values.containsKey(ATTR_START)) { + entry.setStart(values.get(ATTR_START, Calendar.class).getTime()); + } + if (values.containsKey(ATTR_END)) { + entry.setEnd(values.get(ATTR_END, Calendar.class).getTime()); + } + Iterable children = resource.getChildren(); + for (Resource child : children) { + entry.getSingleResults().add(readHistorySingleResult(child)); + } + return entry; + } + + /** + * Reads a single script run from history. + * + * @param resource resource + * @return result + */ + private ExecutionResult readHistorySingleResult(Resource resource) { + ExecutionResult fallback = null; + Resource fallbackResource = resource.getChild(NODE_FALLBACK); + if (fallbackResource != null) { + fallback = readHistorySingleResult(fallbackResource); + } + ValueMap values = resource.adaptTo(ValueMap.class); + String output = values.get(ATTR_RUN_OUTPUT, ""); + String time = values.get(ATTR_RUN_TIME, ""); + Boolean success = values.get(ATTR_RUN_SUCCESS, Boolean.FALSE); + String runResult = values.get(ATTR_RUN_RESULT, ""); + ExecutionResult result = new ExecutionResult(success, time, runResult, output, fallback); + return result; + } + + private void saveExecutionResultInHistory(ExecutionResult result, String path, ResourceResolver resolver) throws AecuException { + createPath(path, resolver, "nt:unstructured"); + Resource entry = resolver.getResource(path); + ModifiableValueMap values = entry.adaptTo(ModifiableValueMap.class); + values.put(ATTR_RUN_SUCCESS, result.isSuccess()); + if (StringUtils.isNotBlank(result.getOutput())) { + values.put(ATTR_RUN_OUTPUT, result.getOutput()); + } + if (StringUtils.isNotBlank(result.getResult())) { + values.put(ATTR_RUN_RESULT, result.getResult()); + } + if (StringUtils.isNotBlank(result.getTime())) { + values.put(ATTR_RUN_TIME, result.getTime()); + } + if (result.getFallbackResult() != null) { + String fallbackPath = path + "/" + NODE_FALLBACK; + saveExecutionResultInHistory(result.getFallbackResult(), fallbackPath, resolver); + } + } + + /** + * Creates the folder at the given path if not yet existing. + * + * @param path path + * @param resolver resource resolver + * @param primaryType primary type + * @throws AecuException error creating folder + */ + protected void createPath(String path, ResourceResolver resolver, String primaryType) throws AecuException { + Resource folder = resolver.getResource(path); + if (folder == null) { + String parent = path.substring(0, path.lastIndexOf("/")); + String name = path.substring(path.lastIndexOf("/") + 1); + if (resolver.getResource(parent) == null) { + createPath(parent, resolver, primaryType); + } + Map properties = new HashMap<>(); + properties.put(JcrConstants.JCR_PRIMARYTYPE, primaryType); + try { + resolver.create(resolver.getResource(parent), name, properties); + } catch (PersistenceException e) { + throw new AecuException("Unable to create " + path, e); + } + } + } + + /** + * Generates the node name for a history entry. + * + * @return name + */ + private String generateHistoryNodeName() { + Random random = new Random(); + return System.currentTimeMillis() + "" + random.nextInt(100000); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index 2068d3c9..21674c8d 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -58,4 +58,14 @@ public interface AecuServiceMBean { */ String execute(@Name("Path") @Description("Path to file that should be executed") String path) throws AecuException; + /** + * Returns history entries. + * + * @param start start index (0 is last run) + * @param count number of entries to return + * @return history entries + * @throws AecuException + */ + String getHistory(@Name("Start index") int start, @Name("Count") int count) throws AecuException; + } diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 34cfb970..2903fb41 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -74,4 +74,14 @@ public String execute(String path) throws AecuException { return result.toString(); } + @Override + public String getHistory(int start, int count) throws AecuException { + List entries = aecuService.getHistory(start, count); + StringBuilder output = new StringBuilder(); + for (HistoryEntry entry : entries) { + output.append(entry.toString() + "\n\n"); + } + return output.toString(); + } + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 438ef48e..7bc1386b 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -18,18 +18,12 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Random; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.JcrConstants; import org.apache.sling.api.resource.LoginException; -import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; @@ -42,12 +36,12 @@ import com.icfolson.aem.groovy.console.GroovyConsoleService; import com.icfolson.aem.groovy.console.response.RunScriptResponse; +import de.valtech.aecu.core.history.HistoryUtil; import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; import de.valtech.aecu.service.ExecutionResult; import de.valtech.aecu.service.HistoryEntry; -import de.valtech.aecu.service.HistoryEntry.RESULT; import de.valtech.aecu.service.HistoryEntry.STATE; /** @@ -57,24 +51,6 @@ */ @Component(service=AecuService.class) public class AecuServiceImpl implements AecuService { - - private static final String ATTR_RUN_OUTPUT = "runOutput"; - - private static final String ATTR_RUN_SUCCESS = "runSuccess"; - - private static final String ATTR_RUN_RESULT = "runResult"; - - private static final String ATTR_RUN_TIME = "runTime"; - - private static final String ATTR_RESULT = "result"; - - private static final String ATTR_STATE = "state"; - - private static final String ATTR_START = "start"; - - private static final String ATTR_END = "end"; - - private static final String HISTORY_BASE = "/var/aecu"; @Reference private ServiceResourceResolverService resolverService; @@ -240,77 +216,23 @@ protected String getFallbackScript(ResourceResolver resolver, String path) { @Override public HistoryEntry createHistoryEntry() throws AecuException { try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { - HistoryEntryImpl history = new HistoryEntryImpl(); - Calendar start = new GregorianCalendar(); - String basePath = HISTORY_BASE + "/" + start.get(Calendar.YEAR) + "/" + (start.get(Calendar.MONTH) + 1) + "/" + start.get(Calendar.DAY_OF_MONTH); - String nodeName = generateHistoryNodeName(); - String nodePath = basePath + "/" + nodeName; - createPath(basePath, resolver, JcrResourceConstants.NT_SLING_FOLDER); - createPath(nodePath, resolver, JcrConstants.NT_UNSTRUCTURED); - Resource resource = resolver.getResource(nodePath); - ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); - values.put(ATTR_START, start); - values.put(ATTR_STATE, STATE.RUNNING.name()); - values.put(ATTR_RESULT, RESULT.UNKNOWN.name()); - history.setStart(start.getTime()); - history.setPath(nodePath); - try { - resolver.commit(); - } catch (PersistenceException e) { - throw new AecuException("Unable to create history " + nodePath, e); - } - return history; + HistoryUtil historyUtil = new HistoryUtil(); + HistoryEntry entry = historyUtil.createHistoryEntry(resolver); + resolver.commit(); + return entry; + } catch (PersistenceException e) { + throw new AecuException("Unable to create history", e); } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); } } - /** - * Creates the folder at the given path if not yet existing. - * - * @param path path - * @param resolver resource resolver - * @param primaryType primary type - * @throws AecuException error creating folder - */ - protected void createPath(String path, ResourceResolver resolver, String primaryType) throws AecuException { - Resource folder = resolver.getResource(path); - if (folder == null) { - String parent = path.substring(0, path.lastIndexOf("/")); - String name = path.substring(path.lastIndexOf("/") + 1); - if (resolver.getResource(parent) == null) { - createPath(parent, resolver, primaryType); - } - Map properties = new HashMap<>(); - properties.put(JcrConstants.JCR_PRIMARYTYPE, primaryType); - try { - resolver.create(resolver.getResource(parent), name, properties); - } catch (PersistenceException e) { - throw new AecuException("Unable to create " + path, e); - } - } - } - - /** - * Generates the node name for a history entry. - * - * @return name - */ - private String generateHistoryNodeName() { - Random random = new Random(); - return System.currentTimeMillis() + "" + random.nextInt(100000); - } - @Override public HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuException { try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { - Resource resource = resolver.getResource(history.getRepositoryPath()); - ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); - Calendar end = new GregorianCalendar(); - values.put(ATTR_END, end); - values.put(ATTR_STATE, STATE.FINISHED.name()); - values.put(ATTR_RESULT, history.getResult().name()); + HistoryUtil historyUtil = new HistoryUtil(); + historyUtil.finishHistoryEntry(history, resolver); resolver.commit(); return history; } @@ -329,8 +251,8 @@ public HistoryEntry storeExecutionInHistory(HistoryEntry history, ExecutionResul } history.getSingleResults().add(result); try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { - String path = history.getRepositoryPath() + "/" + history.getSingleResults().size(); - saveExecutionResultInHistory(result, path, resolver); + HistoryUtil historyUtil = new HistoryUtil(); + historyUtil.storeExecutionInHistory(history, result, resolver); resolver.commit(); return history; } @@ -342,24 +264,15 @@ public HistoryEntry storeExecutionInHistory(HistoryEntry history, ExecutionResul } } - private void saveExecutionResultInHistory(ExecutionResult result, String path, ResourceResolver resolver) throws AecuException { - createPath(path, resolver, "nt:unstructured"); - Resource entry = resolver.getResource(path); - ModifiableValueMap values = entry.adaptTo(ModifiableValueMap.class); - values.put(ATTR_RUN_SUCCESS, result.isSuccess()); - if (StringUtils.isNotBlank(result.getOutput())) { - values.put(ATTR_RUN_OUTPUT, result.getOutput()); - } - if (StringUtils.isNotBlank(result.getResult())) { - values.put(ATTR_RUN_RESULT, result.getResult()); - } - if (StringUtils.isNotBlank(result.getTime())) { - values.put(ATTR_RUN_TIME, result.getTime()); + @Override + public List getHistory(int startIndex, int count) throws AecuException { + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + HistoryUtil historyUtil = new HistoryUtil(); + return historyUtil.getHistory(startIndex, count, resolver); } - if (result.getFallbackResult() != null) { - String fallbackPath = path + "/fallback"; - saveExecutionResultInHistory(result.getFallbackResult(), fallbackPath, resolver); + catch (LoginException e) { + throw new AecuException("Unable to get service resource resolver", e); } } - + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index 789fd1ef..24a7e2af 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -30,6 +30,7 @@ */ public class HistoryEntryImpl implements HistoryEntry { + private STATE state; private String path; private Date start; private Date end; @@ -52,8 +53,7 @@ public List getSingleResults() { @Override public STATE getState() { - // TODO Auto-generated method stub - return STATE.RUNNING; + return state; } @Override @@ -81,7 +81,7 @@ public String getRepositoryPath() { * * @param start start date */ - protected void setStart(Date start) { + public void setStart(Date start) { this.start = start; } @@ -90,7 +90,7 @@ protected void setStart(Date start) { * * @param end end date */ - protected void setEnd(Date end) { + public void setEnd(Date end) { this.end = end; } @@ -99,8 +99,26 @@ protected void setEnd(Date end) { * * @param path node path */ - protected void setPath(String path) { + public void setRepositoryPath(String path) { this.path = path; } + + public void setState(STATE state) { + this.state = state; + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("Path: " + getRepositoryPath() + "\n"); + output.append("Start: " + getStart() + "\n"); + output.append("End: " + getEnd() + "\n"); + output.append("State: " + getState() + "\n"); + output.append("Result: " + getResult() + "\n\n"); + for (ExecutionResult singleResult : singleResults) { + output.append(singleResult.toString() + "\n"); + } + return output.toString(); + } } diff --git a/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java new file mode 100644 index 00000000..8e18eb9e --- /dev/null +++ b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.history; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.jcr.resource.api.JcrResourceConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +import de.valtech.aecu.service.AecuException; + +/** + * Tests HistoryUtil + * + * @author Roland Gruber + */ +@RunWith(value=MockitoJUnitRunner.class) +public class HistoryUtilTest { + + @Spy + private HistoryUtil historyUtil; + + @Mock + private ResourceResolver resolver; + + @Test + public void createPath_Existing() throws AecuException { + String path = "/var/aecu/2018/5"; + when(resolver.getResource(path)).thenReturn(mock(Resource.class)); + + historyUtil.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); + + verify(historyUtil, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); + } + + @Test + public void createPath_NotExisting() throws AecuException, PersistenceException { + String path = "/var/aecu/2018/5"; + when(resolver.getResource("/var/aecu/2018")).thenReturn(mock(Resource.class)); + + historyUtil.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); + + verify(historyUtil, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); + verify(resolver, times(1)).create(any(Resource.class), eq("5"), any()); + } + +} diff --git a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java index 136a1a74..6a2e4d88 100644 --- a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java +++ b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java @@ -20,22 +20,16 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.HashSet; import java.util.Set; -import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; -import org.apache.sling.jcr.resource.api.JcrResourceConstants; import org.apache.sling.settings.SlingSettingsService; import org.junit.Before; import org.junit.Test; @@ -45,8 +39,6 @@ import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; -import de.valtech.aecu.service.AecuException; - /** * Tests AecuServiceImpl * @@ -141,24 +133,4 @@ public void getFallbackScript_Fallback() { assertNull(service.getFallbackScript(resolver, "/path/to/script.fallback.groovy")); } - @Test - public void createPath_Existing() throws AecuException { - String path = "/var/aecu/2018/5"; - when(resolver.getResource(path)).thenReturn(mock(Resource.class)); - - service.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); - - verify(service, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); - } - - @Test - public void createPath_NotExisting() throws AecuException, PersistenceException { - String path = "/var/aecu/2018/5"; - when(resolver.getResource("/var/aecu/2018")).thenReturn(mock(Resource.class)); - - service.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); - - verify(service, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); - verify(resolver, times(1)).create(any(Resource.class), eq("5"), any()); - } } From 41307a69fd239306c37878d7a6a601024396495c Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Wed, 16 May 2018 11:32:43 +0200 Subject: [PATCH 020/122] proper reading of history --- .../de/valtech/aecu/service/AecuService.java | 2 +- .../aecu/core/history/HistoryUtil.java | 112 ++++++++++++++++-- .../content/jcr_root/var/aecu/.content.xml | 2 +- 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 7c759df1..ae4a6bb5 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -83,7 +83,7 @@ public interface AecuService { /** * Returns the last history entries. The search starts at the newest entry. * - * @param startIndex start reading at this index + * @param startIndex start reading at this index (first is 0) * @param count number of entries to read * @return history entries (newest first) * @throws AecuException error reading history diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index 78c2b0e2..5a7d7ad3 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -27,6 +27,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.JcrConstants; +import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; @@ -81,7 +82,7 @@ public HistoryEntry createHistoryEntry(ResourceResolver resolver) throws AecuExc String basePath = HISTORY_BASE + "/" + start.get(Calendar.YEAR) + "/" + (start.get(Calendar.MONTH) + 1) + "/" + start.get(Calendar.DAY_OF_MONTH); String nodeName = generateHistoryNodeName(); String nodePath = basePath + "/" + nodeName; - createPath(basePath, resolver, JcrResourceConstants.NT_SLING_FOLDER); + createPath(basePath, resolver, JcrResourceConstants.NT_SLING_ORDERED_FOLDER); createPath(nodePath, resolver, JcrConstants.NT_UNSTRUCTURED); Resource resource = resolver.getResource(nodePath); ModifiableValueMap values = resource.adaptTo(ModifiableValueMap.class); @@ -128,20 +129,109 @@ public void finishHistoryEntry(HistoryEntry history, ResourceResolver resolver) /** * Returns the last history entries. The search starts at the newest entry. * - * @param startIndex start reading at this index + * @param startIndex start reading at this index (first is 0) * @param count number of entries to read * @param resolver resource resolver * @return history entries (newest first) */ public List getHistory(int startIndex, int count, ResourceResolver resolver) { List entries = new ArrayList<>(); + if (count == 0) { + return entries; + } Resource base = resolver.getResource(HISTORY_BASE); + Resource current = getLatestHistoryEntry(base); + if (current == null) { + return entries; + } + // skip up to start index + for (int i = 0; i < startIndex; i++) { + current = getPreviousHistoryEntry(current); + } + for (int i = 0; i < count; i++) { + if (current == null) { + break; + } + entries.add(readHistoryEntry(current)); + current = getPreviousHistoryEntry(current); + } + return entries; + } + + /** + * Returns the run before the given one. + * + * @param current current run + * @return previous run + */ + private Resource getPreviousHistoryEntry(Resource current) { + // check if the parent has a sibling before the current node + Resource previous = getPreviousSibling(current); + if (previous != null) { + return previous; + } + // go down till we find an earlier sibling + Resource base = descendToPreviousSiblingInHistory(current.getParent()); + // go back up the folders + return ascendToLastRun(base); + } + + /** + * Gos up the folders to last run. + * + * @param resource current node + * @return last run + */ + private Resource ascendToLastRun(Resource resource) { + if (resource == null) { + return null; + } + Resource last = getLastChild(resource); + ValueMap values = last.adaptTo(ValueMap.class); + if (JcrResourceConstants.NT_SLING_ORDERED_FOLDER.equals(values.get(JcrConstants.JCR_PRIMARYTYPE, String.class))) { + return ascendToLastRun(last); + } + return last; + } - // TODO start, count - Resource latest = getLatestHistoryEntry(base); - entries.add(readHistoryEntry(latest)); + /** + * Descends in history till a previous sibling is found. + * Descending stops at history base level + * + * @param current current resource + * @return previous sibling + */ + private Resource descendToPreviousSiblingInHistory(Resource current) { + if ((current == null) || HISTORY_BASE.equals(current.getPath())) { + return null; + } + Resource previous = getPreviousSibling(current); + if (previous != null) { + return previous; + } + previous = descendToPreviousSiblingInHistory(current.getParent()); + return previous; + } - return entries; + /** + * Returns the previous sibling of the given node. + * + * @param resource current node + * @return last sibling or null + */ + private Resource getPreviousSibling(Resource resource) { + Iterator siblings = resource.getParent().listChildren(); + Resource previous = null; + while (siblings.hasNext()) { + Resource sibling = siblings.next(); + if (sibling.getName().equals(resource.getName())) { + break; + } + if (!sibling.getName().equals(AccessControlConstants.REP_POLICY)) { + previous = sibling; + } + } + return previous; } /** @@ -154,11 +244,7 @@ private Resource getLatestHistoryEntry(Resource base) { if (base == null) { return null; } - Resource lastYear = getLastChild(base); - Resource lastMonth = getLastChild(lastYear); - Resource lastDay = getLastChild(lastMonth); - Resource lastRun = getLastChild(lastDay); - return lastRun; + return ascendToLastRun(base); } /** @@ -189,7 +275,9 @@ private HistoryEntry readHistoryEntry(Resource resource) { HistoryEntryImpl entry = new HistoryEntryImpl(); entry.setRepositoryPath(resource.getPath()); ValueMap values = resource.adaptTo(ValueMap.class); - entry.setState(STATE.valueOf(values.get(ATTR_STATE, String.class))); + if (values.containsKey(ATTR_STATE)) { + entry.setState(STATE.valueOf(values.get(ATTR_STATE, String.class))); + } if (values.containsKey(ATTR_START)) { entry.setStart(values.get(ATTR_START, Calendar.class).getTime()); } diff --git a/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml index 1db66005..c6ad70be 100644 --- a/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml +++ b/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml @@ -1,4 +1,4 @@ \ No newline at end of file From 35c8952e5eeed1735f318633ce240e862fdef80e Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Thu, 17 May 2018 15:38:06 +0200 Subject: [PATCH 021/122] started purge task --- .../PurgeHistoryConfiguration.java | 33 ++++++++++ .../core/maintenance/PurgeHistoryTask.java | 60 +++++++++++++++++++ .../main/content/META-INF/vault/filter.xml | 1 + .../aecu_history_purge/.content.xml | 7 +++ ...aecu.core.maintenance.PurgeHistoryTask.xml | 5 ++ 5 files changed, 106 insertions(+) create mode 100644 core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java create mode 100644 core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java create mode 100644 ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/de.valtech.aecu.core.maintenance.PurgeHistoryTask.xml diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java new file mode 100644 index 00000000..6fb051f0 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.maintenance; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.AttributeType; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(name = "AECU Purge history configuration") +public interface PurgeHistoryConfiguration { + + @AttributeDefinition( + type = AttributeType.INTEGER, + name = "Days to keep", + description = "Entries younger than this will not be removed" + ) + int daysToKeep(); + +} diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java new file mode 100644 index 00000000..80ef7be5 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.maintenance; + +import org.apache.sling.event.jobs.Job; +import org.apache.sling.event.jobs.consumer.JobExecutionContext; +import org.apache.sling.event.jobs.consumer.JobExecutionResult; +import org.apache.sling.event.jobs.consumer.JobExecutor; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.metatype.annotations.Designate; + +import com.adobe.granite.maintenance.MaintenanceConstants; + +/** + * Purges old entries from the history. + * + * @author Roland Gruber + */ +@Component( + property = { + MaintenanceConstants.PROPERTY_TASK_NAME + "=AECUPurgeHistory", + MaintenanceConstants.PROPERTY_TASK_TITLE + "=AECU Purge History", + JobExecutor.PROPERTY_TOPICS + "=" + MaintenanceConstants.TASK_TOPIC_PREFIX + "AECUPurgeHistory", + } +) +@Designate(ocd = PurgeHistoryConfiguration.class) +public class PurgeHistoryTask implements JobExecutor { + + private PurgeHistoryConfiguration config; + + /** + * Activates the service. + * + * @param config configuration + */ + public void activate(PurgeHistoryConfiguration config) { + this.config = config; + } + + @Override + public JobExecutionResult process(Job job, JobExecutionContext context) { + // TODO Auto-generated method stub + return context.result().message("Done").succeeded(); + } + +} diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index 4b6c9117..3e8b5b6c 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -4,6 +4,7 @@ + diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml new file mode 100644 index 00000000..8873d456 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/de.valtech.aecu.core.maintenance.PurgeHistoryTask.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/de.valtech.aecu.core.maintenance.PurgeHistoryTask.xml new file mode 100644 index 00000000..db8d13a9 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/de.valtech.aecu.core.maintenance.PurgeHistoryTask.xml @@ -0,0 +1,5 @@ + + From 5c46f30359c0d06babb7a8625f077543136911be Mon Sep 17 00:00:00 2001 From: Roxana Muresan Date: Thu, 17 May 2018 16:19:57 +0200 Subject: [PATCH 022/122] AECU-hello-world-binding: hello world binding --- .../hello/AECUBindingExtensionProvider.java | 62 +++++++++++++++++++ .../console/bindings/hello/HelloWorld.java | 32 ++++++++++ .../migrations.author/sayHello.groovy | 7 +++ 3 files changed, 101 insertions(+) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java create mode 100644 examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/sayHello.groovy diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java new file mode 100644 index 00000000..b867b847 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.groovy.console.bindings.hello; + +import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; +import groovy.lang.Binding; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.ResourceResolver; +import org.osgi.framework.BundleContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jcr.Session; +import java.util.Map; + +/** + * Provides additional AECU Bindings for the Groovy Console + * @author Roxana Muresan + */ +@Component(immediate = true) +public class AECUBindingExtensionProvider implements BindingExtensionProvider { + + private static final Logger LOG = LoggerFactory.getLogger(AECUBindingExtensionProvider.class); + + @Reference + private BindingExtensionProvider defaultBindingExtensionProvider; + + + @Activate + public void activate(BundleContext bundleContext) { + LOG.debug("defaultBindingExtensionProvider is " + defaultBindingExtensionProvider); + } + + @Override + public Binding getBinding(SlingHttpServletRequest request) { + ResourceResolver resourceResolver = request.getResourceResolver(); + Session session = resourceResolver.adaptTo(Session.class); + Binding binding = defaultBindingExtensionProvider.getBinding(request); + Map inheritedBindings = binding.getVariables(); + inheritedBindings.put("helloWorld", new HelloWorld()); + + return new Binding(inheritedBindings); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java new file mode 100644 index 00000000..cd11cfc4 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java @@ -0,0 +1,32 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ +package de.valtech.aecu.core.groovy.console.bindings.hello; + +import org.osgi.service.component.annotations.Component; + +/** + * Groovy Console Bindings first test class + * @author Roxana Muresan + */ +@Component(immediate = true) +public class HelloWorld { + + public String sayHello() { + return "Hello world! >^.^<"; + } + +} diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/sayHello.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/sayHello.groovy new file mode 100644 index 00000000..20cba1b7 --- /dev/null +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/sayHello.groovy @@ -0,0 +1,7 @@ +def checkResourceResolver = (resourceResolver != null); +def checkHelloWorld = (helloWorld != null); +def sayHello = (checkHelloWorld) ? helloWorld.sayHello() : "NooooOOOOoooooo!!!!!" + +println "resourceProvider is defined $checkResourceResolver" +println "helloWorld is defined $checkHelloWorld" +println "helloWorld says $sayHello" \ No newline at end of file From a6ac87cf69ef7f9a9fa43c1b3a9e7594f9db4d7c Mon Sep 17 00:00:00 2001 From: Roxana Muresan Date: Thu, 17 May 2018 16:23:06 +0200 Subject: [PATCH 023/122] AECU-hello-world-binding: removed unused objects --- .../console/bindings/hello/AECUBindingExtensionProvider.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java index b867b847..8bc8e845 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java @@ -19,7 +19,6 @@ import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; import groovy.lang.Binding; import org.apache.sling.api.SlingHttpServletRequest; -import org.apache.sling.api.resource.ResourceResolver; import org.osgi.framework.BundleContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -27,7 +26,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.jcr.Session; import java.util.Map; /** @@ -50,8 +48,6 @@ public void activate(BundleContext bundleContext) { @Override public Binding getBinding(SlingHttpServletRequest request) { - ResourceResolver resourceResolver = request.getResourceResolver(); - Session session = resourceResolver.adaptTo(Session.class); Binding binding = defaultBindingExtensionProvider.getBinding(request); Map inheritedBindings = binding.getVariables(); inheritedBindings.put("helloWorld", new HelloWorld()); From 52f40ba4a7e0cef818e9dbe69017c43161184ad7 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Thu, 17 May 2018 16:23:12 +0200 Subject: [PATCH 024/122] added test logger --- core/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/pom.xml b/core/pom.xml index f36f7d85..ac629207 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -64,6 +64,10 @@ org.slf4j slf4j-api + + org.slf4j + slf4j-simple + javax.jcr jcr From 61a6cadca0c36abf253365ffd0bf947f6c61f333 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Thu, 17 May 2018 16:23:40 +0200 Subject: [PATCH 025/122] purge history --- .../aecu/core/history/HistoryUtil.java | 54 +++++++++++++++++++ .../PurgeHistoryConfiguration.java | 7 ++- .../core/maintenance/PurgeHistoryTask.java | 26 +++++++-- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index 5a7d7ad3..e08a8bba 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -32,8 +32,12 @@ import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.api.resource.ResourceUtil.BatchResourceRemover; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.jcr.resource.api.JcrResourceConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import de.valtech.aecu.core.service.HistoryEntryImpl; import de.valtech.aecu.service.AecuException; @@ -48,6 +52,8 @@ * @author Roland Gruber */ public class HistoryUtil { + + private static final Logger LOG = LoggerFactory.getLogger(HistoryUtil.class); private static final String HISTORY_BASE = "/var/aecu"; @@ -368,4 +374,52 @@ private String generateHistoryNodeName() { return System.currentTimeMillis() + "" + random.nextInt(100000); } + /** + * Purges the history by keeping only entries within the set number of days. + * + * @param resolver resource resolver + * @param daysToKeep number of days to keep + * @throws PersistenceException error deleting node + */ + public void purgeHistory(ResourceResolver resolver, int daysToKeep) throws PersistenceException { + Resource base = resolver.getResource(HISTORY_BASE); + Calendar calendar = new GregorianCalendar(); + calendar.add(Calendar.DAY_OF_MONTH, -daysToKeep); + LOG.debug("Starting purge with limit " + calendar.getTime().toString()); + deleteYears(base.listChildren(), calendar); + } + + /** + * Deletes the year resources that are too old. + * + * @param resources resources + * @param calendar time limit + * @throws PersistenceException error deleting node + */ + private void deleteYears(Iterator resources, Calendar calendar) throws PersistenceException { + while (resources.hasNext()) { + Resource resource = resources.next(); + String name = resource.getName(); + // skip extra nodes such as ACLs + if (!StringUtils.isNumeric(name)) { + LOG.debug("Skipping purge of other node: " + resource.getPath()); + continue; + } + int year = Integer.parseInt(name); + int yearLimit = calendar.get(Calendar.YEAR); + if (year > yearLimit) { + LOG.debug("Skipping purge of too young node: " + resource.getPath()); + } + else if (year == yearLimit) { + LOG.debug("Skipping purge of too young node: " + resource.getPath()); + // TODO + } + else { + LOG.debug("Purging node: " + resource.getPath()); + BatchResourceRemover remover = ResourceUtil.getBatchResourceRemover(1000); + remover.delete(resource); + } + } + } + } diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java index 6fb051f0..48a91e68 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java @@ -20,8 +20,13 @@ import org.osgi.service.metatype.annotations.AttributeType; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +/** + * Configuration for purge task. + * + * @author Roland Gruber + */ @ObjectClassDefinition(name = "AECU Purge history configuration") -public interface PurgeHistoryConfiguration { +public @interface PurgeHistoryConfiguration { @AttributeDefinition( type = AttributeType.INTEGER, diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java index 80ef7be5..3a1f6cfc 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java @@ -16,15 +16,23 @@ */ package de.valtech.aecu.core.maintenance; +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.event.jobs.Job; import org.apache.sling.event.jobs.consumer.JobExecutionContext; import org.apache.sling.event.jobs.consumer.JobExecutionResult; import org.apache.sling.event.jobs.consumer.JobExecutor; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; import org.osgi.service.metatype.annotations.Designate; import com.adobe.granite.maintenance.MaintenanceConstants; +import de.valtech.aecu.core.history.HistoryUtil; +import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; + /** * Purges old entries from the history. * @@ -41,20 +49,32 @@ public class PurgeHistoryTask implements JobExecutor { private PurgeHistoryConfiguration config; - + + @Reference + private ServiceResourceResolverService resolverService; + /** * Activates the service. * * @param config configuration */ + @Activate public void activate(PurgeHistoryConfiguration config) { this.config = config; } @Override public JobExecutionResult process(Job job, JobExecutionContext context) { - // TODO Auto-generated method stub - return context.result().message("Done").succeeded(); + try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { + HistoryUtil historyUtil = new HistoryUtil(); + historyUtil.purgeHistory(resolver, config.daysToKeep()); + resolver.commit(); + return context.result().message("Purged AECU history entries").succeeded(); + } catch (LoginException e) { + return context.result().message("Service resolver failed with " + e.getMessage()).failed(); + } catch (PersistenceException e) { + return context.result().message("Purge failed with " + e.getMessage()).failed(); + } } } From 965da400bc55751d57e526c963ba59d8765e0fb5 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Fri, 18 May 2018 08:12:17 +0200 Subject: [PATCH 026/122] finished purging task --- .../aecu/core/history/HistoryUtil.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index e08a8bba..bcc99676 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -386,7 +386,7 @@ public void purgeHistory(ResourceResolver resolver, int daysToKeep) throws Persi Calendar calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_MONTH, -daysToKeep); LOG.debug("Starting purge with limit " + calendar.getTime().toString()); - deleteYears(base.listChildren(), calendar); + deleteRecursive(base.listChildren(), calendar, new int[] {Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH}); } /** @@ -394,9 +394,11 @@ public void purgeHistory(ResourceResolver resolver, int daysToKeep) throws Persi * * @param resources resources * @param calendar time limit + * @param fields calendar fields * @throws PersistenceException error deleting node */ - private void deleteYears(Iterator resources, Calendar calendar) throws PersistenceException { + private void deleteRecursive(Iterator resources, Calendar calendar, int[] fields) throws PersistenceException { + int currentField = fields[0]; while (resources.hasNext()) { Resource resource = resources.next(); String name = resource.getName(); @@ -405,14 +407,24 @@ private void deleteYears(Iterator resources, Calendar calendar) throws LOG.debug("Skipping purge of other node: " + resource.getPath()); continue; } - int year = Integer.parseInt(name); - int yearLimit = calendar.get(Calendar.YEAR); - if (year > yearLimit) { + int nodeValue = Integer.parseInt(name); + int limit = calendar.get(currentField); + if (currentField == Calendar.MONTH) { + // months start with 0 but are stored beginning with 1 in CRX + limit++; + } + if (nodeValue > limit) { LOG.debug("Skipping purge of too young node: " + resource.getPath()); } - else if (year == yearLimit) { + else if (nodeValue == limit) { LOG.debug("Skipping purge of too young node: " + resource.getPath()); - // TODO + // check next level + if (fields.length == 1) { + return; + } + int[] fieldsNew = new int[fields.length - 1]; + System.arraycopy(fields, 1, fieldsNew, 0, fieldsNew.length); + deleteRecursive(resource.listChildren(), calendar, fieldsNew); } else { LOG.debug("Purging node: " + resource.getPath()); From 64d77093834c1d79b048882eef06eaab8944a332 Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Tue, 22 May 2018 09:48:29 +0200 Subject: [PATCH 027/122] added history menu entry --- .../aecu/core/models/HelloWorldModel.java | 48 ------------------- .../main/content/META-INF/vault/filter.xml | 1 + .../core/content/nav/tools/aecu/.content.xml | 6 +++ .../nav/tools/aecu/history/.content.xml | 8 ++++ .../aecu/clientlibs/aecu.editor/.content.xml | 6 +++ .../aecu/clientlibs/aecu.editor/css.txt | 3 ++ .../aecu/clientlibs/aecu.editor/css/aecu.css | 0 .../aecu/clientlibs/aecu.editor/js.txt | 1 + .../clientlibs/clientlib-base/.content.xml | 6 --- .../aecu/clientlibs/clientlib-base/css.txt | 15 ------ .../aecu/clientlibs/clientlib-base/js.txt | 15 ------ .../content/breadcrumb => tools}/.content.xml | 6 +-- .../valtech/aecu/tools/history/.content.xml | 47 ++++++++++++++++++ 13 files changed, 74 insertions(+), 88 deletions(-) delete mode 100644 core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java create mode 100644 ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css.txt create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt delete mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml delete mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt delete mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt rename ui.apps/src/main/content/jcr_root/apps/valtech/aecu/{components/content/breadcrumb => tools}/.content.xml (52%) create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/.content.xml diff --git a/core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java b/core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java deleted file mode 100644 index a01cb88c..00000000 --- a/core/src/main/java/de/valtech/aecu/core/models/HelloWorldModel.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 Adobe Systems Incorporated - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.valtech.aecu.core.models; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.inject.Named; - -import org.apache.sling.api.resource.Resource; -import org.apache.sling.models.annotations.Default; -import org.apache.sling.models.annotations.Model; -import org.apache.sling.settings.SlingSettingsService; - -@Model(adaptables=Resource.class) -public class HelloWorldModel { - - @Inject - private SlingSettingsService settings; - - @Inject @Named("sling:resourceType") @Default(values="No resourceType") - protected String resourceType; - - private String message; - - @PostConstruct - protected void init() { - message = "\tHello World!\n"; - message += "\tThis is instance: " + settings.getSlingId() + "\n"; - message += "\tResource type is: " + resourceType + "\n"; - } - - public String getMessage() { - return message; - } -} diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index 3e8b5b6c..5128623f 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -1,6 +1,7 @@ + diff --git a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml new file mode 100644 index 00000000..6124a6ed --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml new file mode 100644 index 00000000..7b92abb7 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml new file mode 100644 index 00000000..5476047b --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml @@ -0,0 +1,6 @@ + + diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css.txt new file mode 100644 index 00000000..b10e4ed2 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css.txt @@ -0,0 +1,3 @@ +#base=css + +aecu.css diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css new file mode 100644 index 00000000..e69de29b diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt new file mode 100644 index 00000000..1544c16c --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt @@ -0,0 +1 @@ +#base=js \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml deleted file mode 100644 index 085da325..00000000 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/.content.xml +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt deleted file mode 100644 index 51f69f74..00000000 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/css.txt +++ /dev/null @@ -1,15 +0,0 @@ -############################################################################### -# Copyright 2017 Adobe Systems Incorporated -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -############################################################################### \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt deleted file mode 100644 index 51f69f74..00000000 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/clientlib-base/js.txt +++ /dev/null @@ -1,15 +0,0 @@ -############################################################################### -# Copyright 2017 Adobe Systems Incorporated -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -############################################################################### \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/breadcrumb/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/.content.xml similarity index 52% rename from ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/breadcrumb/.content.xml rename to ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/.content.xml index 4806da23..07aadeab 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/breadcrumb/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/.content.xml @@ -1,6 +1,4 @@ + jcr:primaryType="sling:Folder" + /> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/.content.xml new file mode 100644 index 00000000..247f17e6 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/.content.xml @@ -0,0 +1,47 @@ + + + + + + + <views jcr:primaryType="nt:unstructured"> + <list + jcr:primaryType="nt:unstructured" + layoutId="list" + selectionMode="row" + sling:resourceType="granite/ui/components/coral/foundation/table" + > + <columns jcr:primaryType="nt:unstructured"> + <select + jcr:primaryType="nt:unstructured" + select="{Boolean}true" + /> + <date + jcr:primaryType="nt:unstructured" + jcr:title="Date" + /> + <status + jcr:primaryType="nt:unstructured" + jcr:title="Status" + /> + </columns> + </list> + </views> +</jcr:root> From f3bd0505b22bc0a50961111efd64fdbce12f3217 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 22 May 2018 14:31:14 +0200 Subject: [PATCH 028/122] started history tool --- .../nav/tools/aecu/history/.content.xml | 2 +- .../aecu/tools/history/dataitem/dataitem.html | 0 .../tools/history/datasource/datasource.html | 0 .../tools/history/{ => page}/.content.xml | 23 +++++++++++++++---- 4 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html rename ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/{ => page}/.content.xml (61%) diff --git a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml index 7b92abb7..7df113d8 100644 --- a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml @@ -3,6 +3,6 @@ jcr:primaryType="nt:unstructured" jcr:title="History" jcr:description="Show history of last runs" - href="/apps/valtech/aecu/tools/history.html" + href="/apps/valtech/aecu/tools/history/page.html" icon="history" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html new file mode 100644 index 00000000..e69de29b diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html new file mode 100644 index 00000000..e69de29b diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml similarity index 61% rename from ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/.content.xml rename to ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml index 247f17e6..7029d866 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml @@ -4,10 +4,12 @@ xmlns:rep="internal" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" - jcr:primaryType="nt:unstructured" - consoleId="aecu-history" - jcr:title="AEM Easy Content Upgrade - History" - sling:resourceType="granite/ui/components/shell/collectionpage" + jcr:primaryType="cq:Page"> + <jcr:content + jcr:primaryType="nt:unstructured" + jcr:title="AEM Easy Content Upgrade - History" + consoleId="aecu-history" + sling:resourceType="granite/ui/components/shell/collectionpage" > <head jcr:primaryType="nt:unstructured"> <clientlibs @@ -26,7 +28,11 @@ jcr:primaryType="nt:unstructured" layoutId="list" selectionMode="row" + selectionCount="single" sling:resourceType="granite/ui/components/coral/foundation/table" + limit="50" + src="/apps/valtech/aecu/tools/history/page/jcr:content/views/list{.offset,limit}.html" + path="${requestPathInfo.suffix}" > <columns jcr:primaryType="nt:unstructured"> <select @@ -42,6 +48,15 @@ jcr:title="Status" /> </columns> + <datasource + jcr:primaryType="nt:unstructured" + offset="${requestPathInfo.selectors[0]}" + path="${requestPathInfo.suffix}" + limit="${empty requestPathInfo.selectors[1] ? "51" : requestPathInfo.selectors[1] + 1}" + sling:resourceType="valtech/aecu/tools/history/datasource" + itemResourceType="valtech/aecu/tools/history/dataitem" + /> </list> </views> + </jcr:content> </jcr:root> From 6cb467581918c21032c28148cd7c6bcb956b2cb3 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 23 May 2018 11:35:37 +0200 Subject: [PATCH 029/122] show history entries --- .../core/model/history/HistoryDataItem.java | 69 ++++++++++++ .../core/model/history/HistoryDataSource.java | 104 ++++++++++++++++++ .../aecu/tools/history/dataitem/dataitem.html | 8 ++ .../tools/history/datasource/datasource.html | 1 + .../aecu/tools/history/page/.content.xml | 7 +- 5 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java create mode 100644 core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java new file mode 100644 index 00000000..7fcaf97f --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.model.history; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import javax.annotation.PostConstruct; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.SlingObject; + +import de.valtech.aecu.service.HistoryEntry; + +/** + * Model class for a single history item. + * + * @author Roland Gruber + */ +@Model(adaptables = Resource.class) +public class HistoryDataItem { + + private final DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); + + @SlingObject + Resource resource; + + HistoryEntry history = null; + + @PostConstruct + public void setup() { + history = resource.adaptTo(ValueMap.class).get(HistoryDataSource.ATTR_HISTORY, HistoryEntry.class); + } + + /** + * Returns the date of the run. + * + * @return date + */ + public String getDate() { + return format.format(history.getEnd()); + } + + /** + * Returns the result of the run. + * + * @return result + */ + public String getStatus() { + return history.getResult().name(); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java new file mode 100644 index 00000000..3658db59 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java @@ -0,0 +1,104 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.model.history; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ValueMap; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.OSGiService; +import org.apache.sling.models.annotations.injectorspecific.SlingObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.adobe.cq.commerce.common.ValueMapDecorator; +import com.adobe.granite.ui.components.ds.AbstractDataSource; +import com.adobe.granite.ui.components.ds.DataSource; +import com.adobe.granite.ui.components.ds.ValueMapResource; + +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.HistoryEntry; + +/** + * Datasource model for history overview page. + * + * @author Roland Gruber + */ +@Model(adaptables=SlingHttpServletRequest.class) +public class HistoryDataSource { + + private static final String ITEM_TYPE = "valtech/aecu/tools/history/dataitem"; + public static final String ATTR_HISTORY = "history"; + + private Logger LOG = LoggerFactory.getLogger(DataSource.class); + + @SlingObject + SlingHttpServletRequest request; + + @OSGiService + AecuService aecuService; + + @PostConstruct + public void setup() { + String[] selectors = request.getRequestPathInfo().getSelectors(); + int offset = 0; + int limit = 50; + if (selectors.length > 1) { + offset = Integer.parseInt(selectors[0]); + limit = Integer.parseInt(selectors[1]); + } + request.setAttribute(DataSource.class.getName(), getResourceIterator(offset, limit)); + } + + /** + * Returns the history entries. + * + * @param offset offset where to start reading + * @param limit maximum number of entries to return + * @return entries + */ + private DataSource getResourceIterator(int offset, int limit) { + return new AbstractDataSource() { + + @Override + public Iterator<Resource> iterator() { + List<Resource> entries = new ArrayList<>(); + try { + List<HistoryEntry> historyEntries = aecuService.getHistory(offset, limit + 1); + for (HistoryEntry historyEntry : historyEntries) { + ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>()); + vm.put(ATTR_HISTORY, historyEntry); + entries.add(new ValueMapResource(request.getResourceResolver(), historyEntry.getRepositoryPath(), ITEM_TYPE, vm)); + } + } catch (AecuException e) { + LOG.error("Unable to read history entries", e); + } + return entries.iterator(); + } + + }; + } + +} diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html index e69de29b..d04d172b 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html @@ -0,0 +1,8 @@ +<sly data-sly-use.dataItem="de.valtech.aecu.core.model.history.HistoryDataItem" /> +<tr is="coral-table-row"> + <td is="coral-table-cell"> + <coral-checkbox coral-table-rowselect></coral-checkbox> + </td> + <td is="coral-table-cell">${dataItem.date}</td> + <td is="coral-table-cell">${dataItem.status}</td> +</tr> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html index e69de29b..0fbb654f 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html @@ -0,0 +1 @@ +<sly data-sly-use.datasource="de.valtech.aecu.core.model.history.HistoryDataSource" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml index 7029d866..8bff17a8 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml @@ -31,8 +31,11 @@ selectionCount="single" sling:resourceType="granite/ui/components/coral/foundation/table" limit="50" - src="/apps/valtech/aecu/tools/history/page/jcr:content/views/list{.offset,limit}.html" + size="${empty requestPathInfo.selectors[1] ? "50" : requestPathInfo.selectors[1]}" + src="/apps/valtech/aecu/tools/history/page/jcr:content/views/list{.offset,limit}.html?wcmmode=disabled" path="${requestPathInfo.suffix}" + sortMode="remote" + stateId="shell.collectionpage" > <columns jcr:primaryType="nt:unstructured"> <select @@ -50,9 +53,7 @@ </columns> <datasource jcr:primaryType="nt:unstructured" - offset="${requestPathInfo.selectors[0]}" path="${requestPathInfo.suffix}" - limit="${empty requestPathInfo.selectors[1] ? "51" : requestPathInfo.selectors[1] + 1}" sling:resourceType="valtech/aecu/tools/history/datasource" itemResourceType="valtech/aecu/tools/history/dataitem" /> From 1babbe34ab56294a902c8b1c9b4fe75bdfdc91f1 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 23 May 2018 13:20:19 +0200 Subject: [PATCH 030/122] action --- .../aecu/tools/history/dataitem/dataitem.html | 4 +-- .../aecu/tools/history/page/.content.xml | 27 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html index d04d172b..f74d2e76 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html @@ -1,7 +1,7 @@ <sly data-sly-use.dataItem="de.valtech.aecu.core.model.history.HistoryDataItem" /> <tr is="coral-table-row"> - <td is="coral-table-cell"> - <coral-checkbox coral-table-rowselect></coral-checkbox> + <td is="coral-table-cell" coral-table-rowselect> + <coral-icon icon="gears" size="M"/> </td> <td is="coral-table-cell">${dataItem.date}</td> <td is="coral-table-cell">${dataItem.status}</td> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml index 8bff17a8..4955c609 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml @@ -10,6 +10,8 @@ jcr:title="AEM Easy Content Upgrade - History" consoleId="aecu-history" sling:resourceType="granite/ui/components/shell/collectionpage" + targetCollection=".aecu-history-entries" + modeGroup="aecu-history-entries" > <head jcr:primaryType="nt:unstructured"> <clientlibs @@ -36,11 +38,14 @@ path="${requestPathInfo.suffix}" sortMode="remote" stateId="shell.collectionpage" + modeGroup="aecu-history-entries" + granite:rel="aecu-history-entries" > <columns jcr:primaryType="nt:unstructured"> - <select + <empty jcr:primaryType="nt:unstructured" - select="{Boolean}true" + fixedWidth="{Boolean}true" + alignment="center" /> <date jcr:primaryType="nt:unstructured" @@ -59,5 +64,23 @@ /> </list> </views> + <actions jcr:primaryType="nt:unstructured"> + <selection jcr:primaryType="nt:unstructured"> + <open + jcr:primaryType="nt:unstructured" + action="foundation.dialog" + variant="actionBar" + title="Show details" + text="Show details" + icon="history" + sling:resourceType="granite/ui/components/coral/foundation/collection/action" + > + <data + jcr:primaryType="nt:unstructured" + src.uritemplate="/apps/valtech/aecu/tools/history/details.html" + /> + </open> + </selection> + </actions> </jcr:content> </jcr:root> From 9f4cbe30ba2c677ca51e95b99ac04062e5f0b148 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 28 May 2018 10:03:03 +0200 Subject: [PATCH 031/122] link to detail page --- .../core/model/history/HistoryDataItem.java | 13 +++++++-- .../aecu/tools/history/dataitem/dataitem.html | 5 +--- .../aecu/tools/history/details/.content.xml | 29 +++++++++++++++++++ .../aecu/tools/history/page/.content.xml | 25 ---------------- 4 files changed, 41 insertions(+), 31 deletions(-) create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java index 7fcaf97f..56d49384 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java @@ -39,9 +39,9 @@ public class HistoryDataItem { private final DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); @SlingObject - Resource resource; + private Resource resource; - HistoryEntry history = null; + private HistoryEntry history = null; @PostConstruct public void setup() { @@ -66,4 +66,13 @@ public String getStatus() { return history.getResult().name(); } + /** + * Returns the path of the run. + * + * @return path + */ + public String getPath() { + return history.getRepositoryPath(); + } + } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html index f74d2e76..6bc0149c 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html @@ -1,8 +1,5 @@ <sly data-sly-use.dataItem="de.valtech.aecu.core.model.history.HistoryDataItem" /> <tr is="coral-table-row"> - <td is="coral-table-cell" coral-table-rowselect> - <coral-icon icon="gears" size="M"/> - </td> - <td is="coral-table-cell">${dataItem.date}</td> + <td is="coral-table-cell"><a href="/apps/valtech/aecu/tools/history/details.html?entry=${dataItem.path}">${dataItem.date}</a></td> <td is="coral-table-cell">${dataItem.status}</td> </tr> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml new file mode 100644 index 00000000..1045a2a4 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root + xmlns:jcr="http://www.jcp.org/jcr/1.0" + xmlns:rep="internal" + xmlns:sling="http://sling.apache.org/jcr/sling/1.0" + xmlns:granite="http://www.adobe.com/jcr/granite/1.0" + jcr:primaryType="cq:Page"> + <jcr:content + jcr:primaryType="nt:unstructured" + jcr:title="AEM Easy Content Upgrade - History details" + sling:resourceType="granite/ui/components/shell/page" + consoleId="aecu-history-details" + > + <head jcr:primaryType="nt:unstructured"> + <clientlibs + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/foundation/includeclientlibs" + categories="[coralui3,granite.ui.coral.foundation,aecu.editor]" + /> + </head> + <title + jcr:primaryType="nt:unstructured" + text="AEM Easy Content Upgrade - History details" + sling:resourceType="granite/ui/components/coral/foundation/text" + /> + <content jcr:primaryType="granite/ui/components/coral/foundation/container"> + </content> + </jcr:content> +</jcr:root> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml index 4955c609..208caa6b 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml @@ -29,8 +29,6 @@ <list jcr:primaryType="nt:unstructured" layoutId="list" - selectionMode="row" - selectionCount="single" sling:resourceType="granite/ui/components/coral/foundation/table" limit="50" size="${empty requestPathInfo.selectors[1] ? "50" : requestPathInfo.selectors[1]}" @@ -42,11 +40,6 @@ granite:rel="aecu-history-entries" > <columns jcr:primaryType="nt:unstructured"> - <empty - jcr:primaryType="nt:unstructured" - fixedWidth="{Boolean}true" - alignment="center" - /> <date jcr:primaryType="nt:unstructured" jcr:title="Date" @@ -64,23 +57,5 @@ /> </list> </views> - <actions jcr:primaryType="nt:unstructured"> - <selection jcr:primaryType="nt:unstructured"> - <open - jcr:primaryType="nt:unstructured" - action="foundation.dialog" - variant="actionBar" - title="Show details" - text="Show details" - icon="history" - sling:resourceType="granite/ui/components/coral/foundation/collection/action" - > - <data - jcr:primaryType="nt:unstructured" - src.uritemplate="/apps/valtech/aecu/tools/history/details.html" - /> - </open> - </selection> - </actions> </jcr:content> </jcr:root> From f80b0f7f768fe252cead60c7934f7223a58fd606 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 28 May 2018 12:54:54 +0200 Subject: [PATCH 032/122] history overview --- .../aecu/core/history/HistoryUtil.java | 2 +- .../core/model/history/HistoryOverview.java | 104 ++++++++++++++++++ .../content/history/overview/.content.xml | 3 + .../content/history/overview/overview.html | 13 +++ .../aecu/tools/history/details/.content.xml | 11 +- 5 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index bcc99676..85b076f2 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -277,7 +277,7 @@ private Resource getLastChild(Resource resource) { * @param resource history resource * @return history entry */ - private HistoryEntry readHistoryEntry(Resource resource) { + public HistoryEntry readHistoryEntry(Resource resource) { HistoryEntryImpl entry = new HistoryEntryImpl(); entry.setRepositoryPath(resource.getPath()); ValueMap values = resource.adaptTo(ValueMap.class); diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java new file mode 100644 index 00000000..1440ea8b --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java @@ -0,0 +1,104 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.model.history; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.request.RequestParameter; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.SlingObject; + +import de.valtech.aecu.core.history.HistoryUtil; +import de.valtech.aecu.service.HistoryEntry; + +/** + * Sling model for history overview area. + * + * @author Roland Gruber + */ +@Model(adaptables = SlingHttpServletRequest.class) +public class HistoryOverview { + + @SlingObject + private SlingHttpServletRequest request; + + @SlingObject + private ResourceResolver resolver; + + private HistoryEntry historyEntry; + + private final DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); + + /** + * Reads the history entry from CRX. + */ + @PostConstruct + public void init() { + RequestParameter entryParam = request.getRequestParameter("entry"); + if (entryParam == null) { + return; + } + String path = entryParam.getString(); + Resource historyResource = resolver.getResource(path); + if (historyResource == null) { + return; + } + HistoryUtil historyUtil = new HistoryUtil(); + historyEntry = historyUtil.readHistoryEntry(historyResource); + } + + /** + * Returns the history entry. + * + * @return history + */ + public HistoryEntry getHistory() { + return historyEntry; + } + + /** + * Returns the start as formatted string. + * + * @return start date + */ + public String getStart() { + if ((historyEntry == null) || (historyEntry.getStart() == null)) { + return StringUtils.EMPTY; + } + return format.format(historyEntry.getStart()); + } + + /** + * Returns the end as formatted string. + * + * @return end date + */ + public String getEnd() { + if ((historyEntry == null) || (historyEntry.getEnd() == null)) { + return StringUtils.EMPTY; + } + return format.format(historyEntry.getEnd()); + } + +} diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml new file mode 100644 index 00000000..5b0bece8 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" + jcr:primaryType="cq:Component"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html new file mode 100644 index 00000000..c38e7cef --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -0,0 +1,13 @@ +<sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> +<table> + <tr> + <td>State: ${cmp.history.state.name}</td> + <td rowspan="3">${cmp.history.result.name}</td> + </tr> + <tr> + <td>Start: ${cmp.start}</td> + </tr> + <tr> + <td>End: ${cmp.end}</td> + </tr> +</table> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml index 1045a2a4..695052dc 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml @@ -23,7 +23,16 @@ text="AEM Easy Content Upgrade - History details" sling:resourceType="granite/ui/components/coral/foundation/text" /> - <content jcr:primaryType="granite/ui/components/coral/foundation/container"> + <content + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/container" + > + <items jcr:primaryType="nt:unstructured"> + <overview + jcr:primaryType="nt:unstructured" + sling:resourceType="valtech/aecu/components/content/history/overview" + /> + </items> </content> </jcr:content> </jcr:root> From 8a2ff755ad1bd204b42359762e86d624b311cc71 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 29 May 2018 09:19:33 +0200 Subject: [PATCH 033/122] styling --- .../apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css | 8 ++++++++ .../components/content/history/overview/overview.html | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index e69de29b..fd8fa0a2 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -0,0 +1,8 @@ + +table.aecu-history-overview { + margin: 2rem; +} + +table.aecu-history-overview td { + padding: 0.5rem; +} diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html index c38e7cef..59944893 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -1,5 +1,5 @@ <sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> -<table> +<table class="aecu-history-overview" width="100%"> <tr> <td>State: ${cmp.history.state.name}</td> <td rowspan="3">${cmp.history.result.name}</td> From 8f00a0fd73e7b702b58962b5cada017f5d9930e7 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 29 May 2018 09:55:57 +0200 Subject: [PATCH 034/122] display single execution --- .../aecu/clientlibs/aecu.editor/css/aecu.css | 2 +- .../executionResults/executionResults.html | 17 +++++++++++++++ .../templates/executionResult.html | 21 +++++++++++++++++++ .../content/history/overview/overview.html | 1 + .../aecu/tools/history/details/.content.xml | 5 +++++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index fd8fa0a2..35913c87 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -1,5 +1,5 @@ -table.aecu-history-overview { +.base-container { margin: 2rem; } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html new file mode 100644 index 00000000..77d8d015 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html @@ -0,0 +1,17 @@ +<sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> + +<sly data-sly-test.empty="${cmp.history.singleResults.empty}"> + <h2>No scripts executed</h2> +</sly> +<sly data-sly-test="${!empty}"> + <sly data-sly-use.details="templates/executionResult.html" /> + <sly data-sly-test="${cmp.history.singleResults.size == 1}"> + <h2>Execution details</h2> + <sly data-sly-list="${cmp.history.singleResults}"> + <sly data-sly-call="${details.details @ result = item}" /> + </sly> + </sly> + <sly data-sly-test="${cmp.history.singleResults.size > 1}"> + <h2>Execution details for ${cmp.history.singleResults.size} scripts</h2> + </sly> +</sly> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html new file mode 100644 index 00000000..824d3194 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html @@ -0,0 +1,21 @@ +<template data-sly-template.details="${ @ result}"> + <table class="aecu-history-detail" width="100%"> + <tr> + <td>Execution time: ${result.time}</td> + <td>${result.success}</td> + </tr> + </table> + <sly data-sly-test="${result.result}"> + <h3>Result</h3> + ${result.result} + </sly> + <sly data-sly-test="${result.output}"> + <h3>Output</h3> + ${result.output} + </sly> + + <sly data-sly-test="${result.fallbackResult}"> + <h2>Fallback script result</h2> + <sly data-sly-call="${details @ result = result.fallbackResult}" /> + </sly> +</template> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html index 59944893..b23c7c5b 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -1,4 +1,5 @@ <sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> +<h1>Run details</h1> <table class="aecu-history-overview" width="100%"> <tr> <td>State: ${cmp.history.state.name}</td> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml index 695052dc..1b138e2b 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml @@ -26,12 +26,17 @@ <content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container" + granite:class="base-container" > <items jcr:primaryType="nt:unstructured"> <overview jcr:primaryType="nt:unstructured" sling:resourceType="valtech/aecu/components/content/history/overview" /> + <details + jcr:primaryType="nt:unstructured" + sling:resourceType="valtech/aecu/components/content/history/executionResults" + /> </items> </content> </jcr:content> From 51fa15d48e11618720e6a9339eace13f52b129bd Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 29 May 2018 10:18:06 +0200 Subject: [PATCH 035/122] headlines --- .../executionResults/templates/executionResult.html | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html index 824d3194..2a1bfb91 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html @@ -1,4 +1,4 @@ -<template data-sly-template.details="${ @ result}"> +<template data-sly-template.details="${ @ result, isFallback=false}"> <table class="aecu-history-detail" width="100%"> <tr> <td>Execution time: ${result.time}</td> @@ -6,16 +6,18 @@ </tr> </table> <sly data-sly-test="${result.result}"> - <h3>Result</h3> + <h3 data-sly-test="${!isFallback}">Result</h3> + <h4 data-sly-test="${isFallback}">Result</h4> ${result.result} </sly> <sly data-sly-test="${result.output}"> - <h3>Output</h3> + <h3 data-sly-test="${!isFallback}">Output</h3> + <h4 data-sly-test="${isFallback}">Output</h4> ${result.output} </sly> <sly data-sly-test="${result.fallbackResult}"> - <h2>Fallback script result</h2> - <sly data-sly-call="${details @ result = result.fallbackResult}" /> + <h3>Fallback script result</h3> + <sly data-sly-call="${details @ result = result.fallbackResult, isFallback = true}" /> </sly> </template> \ No newline at end of file From 935afe8c39114ec548d0d747026c2081995841bf Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 29 May 2018 11:38:49 +0200 Subject: [PATCH 036/122] store path in history --- .../valtech/aecu/service/ExecutionResult.java | 19 +++++++++++++++++-- .../aecu/core/history/HistoryUtil.java | 12 ++++-------- .../aecu/core/service/AecuServiceImpl.java | 2 +- .../executionResults/executionResults.html | 10 ++++++++++ .../templates/executionResult.html | 7 +++++-- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java index 42404969..ec84af11 100644 --- a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -30,6 +30,7 @@ public class ExecutionResult { private String time; private String result; private ExecutionResult fallbackResult; + private String path; /** * Constructor @@ -39,13 +40,15 @@ public class ExecutionResult { * @param result result * @param output script output * @param fallbackResult fallback script result + * @param path script path */ - public ExecutionResult(boolean success, String time, String result, String output, ExecutionResult fallbackResult) { + public ExecutionResult(boolean success, String time, String result, String output, ExecutionResult fallbackResult, String path) { this.success = success; this.output = output; this.time = time; this.result = result; this.fallbackResult = fallbackResult; + this.path = path; } /** @@ -92,10 +95,22 @@ public String getTime() { public ExecutionResult getFallbackResult() { return fallbackResult; } + + /** + * Returns the script path. + * + * @return path + */ + public String getPath() { + return path; + } @Override public String toString() { - StringBuilder stringVal = new StringBuilder("Successful: " + Boolean.toString(success)); + StringBuilder stringVal = new StringBuilder( + "Successful: " + Boolean.toString(success) + + "Path: " + path + ); if (StringUtils.isNotBlank(time)) { stringVal.append("\n" + "Execution time: " + time); } diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index 85b076f2..5b82c7b5 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -59,20 +59,14 @@ public class HistoryUtil { private static final String NODE_FALLBACK = "fallback"; + private static final String ATTR_PATH = "path"; private static final String ATTR_RUN_OUTPUT = "runOutput"; - private static final String ATTR_RUN_SUCCESS = "runSuccess"; - private static final String ATTR_RUN_RESULT = "runResult"; - private static final String ATTR_RUN_TIME = "runTime"; - private static final String ATTR_RESULT = "result"; - private static final String ATTR_STATE = "state"; - private static final String ATTR_START = "start"; - private static final String ATTR_END = "end"; /** @@ -314,7 +308,8 @@ private ExecutionResult readHistorySingleResult(Resource resource) { String time = values.get(ATTR_RUN_TIME, ""); Boolean success = values.get(ATTR_RUN_SUCCESS, Boolean.FALSE); String runResult = values.get(ATTR_RUN_RESULT, ""); - ExecutionResult result = new ExecutionResult(success, time, runResult, output, fallback); + String path = values.get(ATTR_PATH, ""); + ExecutionResult result = new ExecutionResult(success, time, runResult, output, fallback, path); return result; } @@ -323,6 +318,7 @@ private void saveExecutionResultInHistory(ExecutionResult result, String path, R Resource entry = resolver.getResource(path); ModifiableValueMap values = entry.adaptTo(ModifiableValueMap.class); values.put(ATTR_RUN_SUCCESS, result.isSuccess()); + values.put(ATTR_PATH, result.getPath()); if (StringUtils.isNotBlank(result.getOutput())) { values.put(ATTR_RUN_OUTPUT, result.getOutput()); } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 7bc1386b..0695f3d7 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -189,7 +189,7 @@ private ExecutionResult executeScript(ResourceResolver resolver, String path) { if (!success && (getFallbackScript(resolver, path) != null)) { fallbackResult = executeScript(resolver, getFallbackScript(resolver, path)); } - return new ExecutionResult(success, response.getRunningTime(), result, response.getOutput() + response.getExceptionStackTrace(), fallbackResult); + return new ExecutionResult(success, response.getRunningTime(), result, response.getOutput() + response.getExceptionStackTrace(), fallbackResult, path); } /** diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html index 77d8d015..b6cae72f 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html @@ -13,5 +13,15 @@ <h2>Execution details</h2> </sly> <sly data-sly-test="${cmp.history.singleResults.size > 1}"> <h2>Execution details for ${cmp.history.singleResults.size} scripts</h2> + <coral-accordion> + <sly data-sly-list="${cmp.history.singleResults}"> + <coral-accordion-item> + <coral-accordion-item-label>${item.path}</coral-accordion-item-label> + <coral-accordion-item-content> + <sly data-sly-call="${details.details @ result = item}" /> + </coral-accordion-item-content> + </coral-accordion-item> + </sly> + </coral-accordion> </sly> </sly> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html index 2a1bfb91..f1cff102 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html @@ -1,8 +1,11 @@ <template data-sly-template.details="${ @ result, isFallback=false}"> <table class="aecu-history-detail" width="100%"> <tr> - <td>Execution time: ${result.time}</td> - <td>${result.success}</td> + <td>Path: ${result.path}</td> + <td rowspan="2">${result.success}</td> + </tr> + <tr> + <td>Execution time: ${result.time}</td> </tr> </table> <sly data-sly-test="${result.result}"> From 92a85116e47cef9be3b0821fb9732baf2d87b8ea Mon Sep 17 00:00:00 2001 From: Christopher Piosecny <christopher.piosecny@valtech.de> Date: Tue, 29 May 2018 13:44:46 +0200 Subject: [PATCH 037/122] Add Vault InstallHook implementation. --- .../core/installhook/AecuInstallHook.java | 95 +++++++++++++++++++ .../core/installhook/AecuTrackerListener.java | 67 +++++++++++++ examples/pom.xml | 3 + 3 files changed, 165 insertions(+) create mode 100644 core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java create mode 100644 core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java new file mode 100644 index 00000000..14c7f2a6 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -0,0 +1,95 @@ +package de.valtech.aecu.core.installhook; + +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.ExecutionResult; +import de.valtech.aecu.service.HistoryEntry; + +import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener; +import org.apache.jackrabbit.vault.packaging.InstallContext; +import org.apache.jackrabbit.vault.packaging.InstallHook; +import org.apache.jackrabbit.vault.packaging.PackageException; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * InstallHook handling installation of groovy scripts. + */ +public class AecuInstallHook implements InstallHook { + + private static final Logger LOG = LoggerFactory.getLogger(AecuInstallHook.class); + + private final BundleContext bundleContext; + private AecuTrackerListener listener; + + public AecuInstallHook() { + Bundle currentBundle = FrameworkUtil.getBundle(this.getClass()); + if (currentBundle == null) { + throw new IllegalStateException("The class " + this.getClass() + " was not loaded through a bundle classloader"); + } + bundleContext = currentBundle.getBundleContext(); + if (bundleContext == null) { + throw new IllegalStateException("Could not get bundle context for bundle " + currentBundle); + } + + } + + private ServiceReference<AecuService> getAecuServiceReference() { + ServiceReference<AecuService> aecuServiceReference = bundleContext.getServiceReference(AecuService.class); + if (aecuServiceReference == null) { + throw new IllegalStateException("Could not retrieve service reference for AECUService."); + } + return aecuServiceReference; + } + + @Override + public void execute(InstallContext installContext) throws PackageException { + LOG.info("Executing in phase {}", installContext.getPhase()); + ServiceReference<AecuService> aecuServiceReference = getAecuServiceReference(); + AecuService aecuService = bundleContext.getService(aecuServiceReference); + if (aecuService == null) { + throw new IllegalStateException("Could not get the AECU service, verify that the bundle was installed correctly!"); + } + try { + switch (installContext.getPhase()) { + case PREPARE: + ProgressTrackerListener originalListener = installContext.getOptions().getListener(); + listener = new AecuTrackerListener(originalListener, aecuService, "A", "M", "-"); + installContext.getOptions().setListener(listener); + break; + case INSTALLED: + boolean isDryRun = installContext.getOptions().isDryRun(); + if (isDryRun) { + LOG.debug("Skipping any modifications, dry run mode selected"); + } else { + HistoryEntry installationHistory = aecuService.createHistoryEntry(); + for (String groovyScriptPath : listener.getGroovyScriptPaths()) { + LOG.info("Executing script {}", groovyScriptPath); + ExecutionResult result = aecuService.execute(groovyScriptPath); + installationHistory = aecuService.storeExecutionInHistory(installationHistory, result); + LOG.info("Executed script {}: {}", groovyScriptPath, result.getOutput()); + } + aecuService.finishHistoryEntry(installationHistory); + // TODO: from my point of view the installation should not be failed in case a fallback script was executed successfully + if (!installationHistory.getResult().equals(HistoryEntry.RESULT.SUCCESS)) { + throw new PackageException("Failed installation, check installation history at " + installationHistory.getRepositoryPath()); + } + } + break; + default: + break; + } + } catch (AecuException e) { + throw new PackageException(e); + } finally { + if (aecuServiceReference != null) { + bundleContext.ungetService(aecuServiceReference); + } + } + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java new file mode 100644 index 00000000..31c83b11 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java @@ -0,0 +1,67 @@ +package de.valtech.aecu.core.installhook; + +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.AecuService; + +import org.apache.jackrabbit.util.Text; +import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Collects groovy script paths to execute. + */ +public class AecuTrackerListener implements ProgressTrackerListener { + + private static final Logger LOG = LoggerFactory.getLogger(AecuTrackerListener.class); + + private static final String SCRIPT_PARENT_PATH = "/etc/groovyconsole/scripts/aecu/"; + + private final ProgressTrackerListener originalListener; + private final AecuService aecuService; + private final Set<String> actions; + private final Set<String> paths; + + public AecuTrackerListener(ProgressTrackerListener originalListener, AecuService aecuService, String... actions) { + this.originalListener = originalListener; + this.aecuService = aecuService; + this.actions = new HashSet<>(Arrays.asList(actions)); + this.paths = new HashSet<>(); + } + + public Set<String> getGroovyScriptPaths() { + return Collections.unmodifiableSet(paths); + } + + @Override + public void onMessage(Mode mode, String action, String path) { + originalListener.onMessage(mode, action, path); + + if (!actions.contains(action)) { + LOG.debug("Skipping {} due to non matching action {}", path, action); + return; + } + // TODO: not the best idea to couple the detection of project roots to the structure + if (path.startsWith(SCRIPT_PARENT_PATH)) { + String pathToUse = Text.getAbsoluteParent(path, 4); + // grouping items by first sub folder below SCRIPT_PARENT_PATH + LOG.info("Found matching path {}, using parent {}", path, pathToUse); + try { + paths.addAll(aecuService.getFiles(pathToUse)); + } catch (AecuException e) { + // TODO re-throw? + LOG.error(e.getMessage(), e); + } + } + } + + @Override + public void onError(Mode mode, String action, Exception e) { + originalListener.onError(mode, action, e); + } +} diff --git a/examples/pom.xml b/examples/pom.xml index 7af0e4e9..625e4a7f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -55,6 +55,9 @@ <verbose>true</verbose> <failOnError>true</failOnError> <group>Valtech</group> + <properties> + <installhook.aecu.class>de.valtech.aecu.core.installhook.AecuInstallHook</installhook.aecu.class> + </properties> </configuration> </plugin> From 0323e5ac1f86b7a8eef4e095528a6c2d896c8426 Mon Sep 17 00:00:00 2001 From: Christopher Piosecny <christopher.piosecny@valtech.de> Date: Tue, 29 May 2018 17:22:42 +0200 Subject: [PATCH 038/122] Add workaround to enable infinite scrolling in AEM, the Paginator will verify the amount of items by searching for .foundation-collection-item in the response... so we add this for the moment on our own. --- .../apps/valtech/aecu/tools/history/dataitem/dataitem.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html index 6bc0149c..cbeac95f 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html @@ -1,5 +1,6 @@ <sly data-sly-use.dataItem="de.valtech.aecu.core.model.history.HistoryDataItem" /> -<tr is="coral-table-row"> +<!--/* TODO: investigate why we need the class for the Paginator to work */--> +<tr is="coral-table-row" class="foundation-collection-item"> <td is="coral-table-cell"><a href="/apps/valtech/aecu/tools/history/details.html?entry=${dataItem.path}">${dataItem.date}</a></td> <td is="coral-table-cell">${dataItem.status}</td> </tr> \ No newline at end of file From 9d81f9ae10150e465a287fc1e79f7a685e1ae03f Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 30 May 2018 14:06:19 +0200 Subject: [PATCH 039/122] added status icons --- .../core/model/history/HistoryDataItem.java | 30 ++++++++++++++++--- .../aecu/clientlibs/aecu.editor/css/aecu.css | 16 ++++++++++ .../executionResults/executionResults.html | 6 +++- .../templates/executionResult.html | 5 +++- .../aecu/tools/history/dataitem/dataitem.html | 5 +++- 5 files changed, 55 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java index 56d49384..275ebc0a 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java @@ -27,6 +27,7 @@ import org.apache.sling.models.annotations.injectorspecific.SlingObject; import de.valtech.aecu.service.HistoryEntry; +import de.valtech.aecu.service.HistoryEntry.RESULT; /** * Model class for a single history item. @@ -58,12 +59,33 @@ public String getDate() { } /** - * Returns the result of the run. + * Returns the status icon of the run. * - * @return result + * @return icon */ - public String getStatus() { - return history.getResult().name(); + public String getStatusIcon() { + if (RESULT.FAILURE.equals(history.getResult())) { + return "closeCircle"; + } + if (RESULT.SUCCESS.equals(history.getResult())) { + return "checkCircle"; + } + return "clock"; + } + + /** + * Returns the status color of the run. + * + * @return icon + */ + public String getStatusColor() { + if (RESULT.FAILURE.equals(history.getResult())) { + return "fail"; + } + if (RESULT.SUCCESS.equals(history.getResult())) { + return "ok"; + } + return "inprogress"; } /** diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index 35913c87..e8131b68 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -6,3 +6,19 @@ table.aecu-history-overview td { padding: 0.5rem; } + +table.aecu-history-detail td { + padding: 0.5rem; +} + +.icon-color-ok { + color: green; +} + +.icon-color-fail { + color: red; +} + +.icon-color-inprogress { + color: blue; +} diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html index b6cae72f..90010bba 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html @@ -16,7 +16,11 @@ <h2>Execution details for ${cmp.history.singleResults.size} scripts</h2> <coral-accordion> <sly data-sly-list="${cmp.history.singleResults}"> <coral-accordion-item> - <coral-accordion-item-label>${item.path}</coral-accordion-item-label> + <coral-accordion-item-label> + <coral-icon icon="${item.success ? 'checkCircle' : 'closeCircle'}" class="icon-color-${item.success ? 'ok' : 'fail'}" > + </coral-icon> + ${item.path} + </coral-accordion-item-label> <coral-accordion-item-content> <sly data-sly-call="${details.details @ result = item}" /> </coral-accordion-item-content> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html index f1cff102..d1babd62 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html @@ -2,7 +2,10 @@ <table class="aecu-history-detail" width="100%"> <tr> <td>Path: ${result.path}</td> - <td rowspan="2">${result.success}</td> + <td rowspan="2"> + <coral-icon icon="${result.success ? 'checkCircle' : 'closeCircle'}" size="L" class="icon-color-${result.success ? 'ok' : 'fail'}" > + </coral-icon> + </td> </tr> <tr> <td>Execution time: ${result.time}</td> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html index 6bc0149c..bea890e0 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html @@ -1,5 +1,8 @@ <sly data-sly-use.dataItem="de.valtech.aecu.core.model.history.HistoryDataItem" /> <tr is="coral-table-row"> <td is="coral-table-cell"><a href="/apps/valtech/aecu/tools/history/details.html?entry=${dataItem.path}">${dataItem.date}</a></td> - <td is="coral-table-cell">${dataItem.status}</td> + <td is="coral-table-cell"> + <coral-icon icon="${dataItem.statusIcon}" size="M" class="icon-color-${dataItem.statusColor}" > + </coral-icon> + </td> </tr> \ No newline at end of file From f14284e2de23d5333bb78802c03fead3b039b9ac Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 30 May 2018 14:18:33 +0200 Subject: [PATCH 040/122] fixed NPE --- .../main/java/de/valtech/aecu/core/history/HistoryUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index 5b82c7b5..c1603aac 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -187,6 +187,10 @@ private Resource ascendToLastRun(Resource resource) { return null; } Resource last = getLastChild(resource); + if (last == null) { + // stop if there is no child at all + return null; + } ValueMap values = last.adaptTo(ValueMap.class); if (JcrResourceConstants.NT_SLING_ORDERED_FOLDER.equals(values.get(JcrConstants.JCR_PRIMARYTYPE, String.class))) { return ascendToLastRun(last); From 96bfd1c511092d9b30e188d2329fff0d2e808ef6 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 30 May 2018 14:22:21 +0200 Subject: [PATCH 041/122] style --- .../apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index e8131b68..960681c3 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -8,7 +8,8 @@ table.aecu-history-overview td { } table.aecu-history-detail td { - padding: 0.5rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; } .icon-color-ok { From 8f37d9730bd34930e85e3a419e2199a679dcdab4 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 30 May 2018 14:46:19 +0200 Subject: [PATCH 042/122] Renamed check --- ...erviceUserHealthCheck.java => SelfCheckHealthCheck.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename core/src/main/java/de/valtech/aecu/core/healthcheck/{ServiceUserHealthCheck.java => SelfCheckHealthCheck.java} (91%) diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/ServiceUserHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java similarity index 91% rename from core/src/main/java/de/valtech/aecu/core/healthcheck/ServiceUserHealthCheck.java rename to core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java index 3a322a7e..661e45f1 100644 --- a/core/src/main/java/de/valtech/aecu/core/healthcheck/ServiceUserHealthCheck.java +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java @@ -36,11 +36,11 @@ service = HealthCheck.class, property = { HealthCheck.TAGS + "=aecu", - HealthCheck.NAME + "=AECU Service User", - HealthCheck.MBEAN_NAME + "=aecuServiceUserHCmBean" + HealthCheck.NAME + "=AECU Self Check", + HealthCheck.MBEAN_NAME + "=aecuSelfCheckHCmBean" } ) -public class ServiceUserHealthCheck implements HealthCheck { +public class SelfCheckHealthCheck implements HealthCheck { @Reference private ServiceResourceResolverService resolverService; From c8892d8645ba3198e588f059a5beaa4967adf5cb Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 30 May 2018 16:39:01 +0200 Subject: [PATCH 043/122] docs --- Readme.md | 49 ++++++++++++++++++++++++++++++++++++ docs/images/healthCheck.png | Bin 0 -> 18035 bytes 2 files changed, 49 insertions(+) create mode 100644 Readme.md create mode 100644 docs/images/healthCheck.png diff --git a/Readme.md b/Readme.md new file mode 100644 index 00000000..f236bbcc --- /dev/null +++ b/Readme.md @@ -0,0 +1,49 @@ +# AEM Easy Content Upgrade (AECU) + +AECU simplifies content migrations by executing migration scripts during package installation. It is built on top of [Groovy Console](https://github.com/OlsonDigital/aem-groovy-console). + + +Features: + +* GUI to run scripts and see history of runs +* Run mode support +* Fallback scripts in case of errors +* Extension of Groovy Console bindings +* Service API +* Health Checks + +# Requirements + +AECU requires Java 8 and AEM 6.3 or above. + +#Installation + +TODO + +# Execution of Migration Scripts + +TODO + +# History of Past Runs + +TODO + +# Extension to Groovy Console + +TODO + +# JMX Interface + +TODO + +# Health Checks + +Health checks show you the status of AECU itself and the last migration run. +You can access them on the [status page](http://localhost:4502/libs/granite/operations/content/healthreports/healthreportlist.html/system/sling/monitoring/mbeans/org/apache/sling/healthcheck/HealthCheck/aecuHealthCheckmBean). +For the status of older runs use AECU's history page. + +<img src="docs/images/healthCheck.png"> + +# License + +The AC Tool is licensed under the [GNU GENERAL PUBLIC LICENSE - v 3](LICENSE). diff --git a/docs/images/healthCheck.png b/docs/images/healthCheck.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ce1a0ef1722814288e0a3dfa6ad961c6c56cf3 GIT binary patch literal 18035 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 JGI0a{{{@S|#K8an literal 0 HcmV?d00001 From 08c9f918402835f5c4606361293504c7ed691cf4 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 7 Jun 2018 10:50:33 +0200 Subject: [PATCH 044/122] AECU-hello-world-binding: clean up --- .../bindings/hello/AECUBindingExtensionProvider.java | 7 ------- .../core/groovy/console/bindings/hello/HelloWorld.java | 5 +---- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java index 8bc8e845..885ced5c 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java @@ -19,8 +19,6 @@ import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; import groovy.lang.Binding; import org.apache.sling.api.SlingHttpServletRequest; -import org.osgi.framework.BundleContext; -import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; @@ -41,11 +39,6 @@ public class AECUBindingExtensionProvider implements BindingExtensionProvider { private BindingExtensionProvider defaultBindingExtensionProvider; - @Activate - public void activate(BundleContext bundleContext) { - LOG.debug("defaultBindingExtensionProvider is " + defaultBindingExtensionProvider); - } - @Override public Binding getBinding(SlingHttpServletRequest request) { Binding binding = defaultBindingExtensionProvider.getBinding(request); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java index cd11cfc4..d09ea403 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java @@ -16,17 +16,14 @@ */ package de.valtech.aecu.core.groovy.console.bindings.hello; -import org.osgi.service.component.annotations.Component; - /** * Groovy Console Bindings first test class * @author Roxana Muresan */ -@Component(immediate = true) public class HelloWorld { public String sayHello() { - return "Hello world! >^.^<"; + return "Hello y'all! >^.^<"; } } From 65a6ddb742867f69305c324158bea83fbaa54267 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 7 Jun 2018 10:58:33 +0200 Subject: [PATCH 045/122] AECU-hello-world-binding: move and renaming of the extension provider class --- .../AecuBindingExtensionProvider.java} | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/{hello/AECUBindingExtensionProvider.java => provider/AecuBindingExtensionProvider.java} (84%) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java similarity index 84% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java index 885ced5c..26ef83bf 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/AECUBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java @@ -14,9 +14,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/> */ -package de.valtech.aecu.core.groovy.console.bindings.hello; +package de.valtech.aecu.core.groovy.console.bindings.provider; import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; +import de.valtech.aecu.core.groovy.console.bindings.hello.HelloWorld; import groovy.lang.Binding; import org.apache.sling.api.SlingHttpServletRequest; import org.osgi.service.component.annotations.Component; @@ -31,9 +32,9 @@ * @author Roxana Muresan */ @Component(immediate = true) -public class AECUBindingExtensionProvider implements BindingExtensionProvider { +public class AecuBindingExtensionProvider implements BindingExtensionProvider { - private static final Logger LOG = LoggerFactory.getLogger(AECUBindingExtensionProvider.class); + private static final Logger LOG = LoggerFactory.getLogger(AecuBindingExtensionProvider.class); @Reference private BindingExtensionProvider defaultBindingExtensionProvider; From 6214b2f0b56d9f349b8e859a5acbee09343ff87a Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 7 Jun 2018 16:36:53 +0200 Subject: [PATCH 046/122] AECU-Binding-sample: SimpleContentUpdate binding - first version --- core/pom.xml | 12 +- .../console/bindings/SimpleContentUpdate.java | 172 ++++++++++++++++++ .../AecuBindingExtensionProvider.java | 9 +- .../tests_for_simpleContentUpdates.groovy | 23 +++ pom.xml | 16 +- 5 files changed, 217 insertions(+), 15 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java create mode 100644 examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy diff --git a/core/pom.xml b/core/pom.xml index ac629207..33ce50b9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -85,10 +85,14 @@ <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.models.api</artifactId> </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-collections4</artifactId> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java new file mode 100644 index 00000000..786f4b44 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -0,0 +1,172 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jcr.query.Query; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Groovy Console Bindings: Simple Content Update + * @author Roxana Muresan + */ +public class SimpleContentUpdate { + + private static final Logger LOG = LoggerFactory.getLogger(SimpleContentUpdate.class); + + private ResourceResolver resourceResolver;// TODO check if a system user resource resolver is needed here! + + private List<Resource> resourceList = new ArrayList<>();// TODO with stream? + + + public SimpleContentUpdate(ResourceResolver resourceResolver) { + this.resourceResolver = resourceResolver; + + } + + /** content filter methods **/ + public SimpleContentUpdate forResources(String[] paths) { + if (paths != null && paths.length > 0) { + List<Resource> resources = new ArrayList<>(); + for (String path : paths) { + if (path != null) { + CollectionUtils.addIgnoreNull(resources, resourceResolver.getResource(path)); + } + } + CollectionUtils.addAll(this.resourceList, resources.iterator()); + } + return this; + } + + public SimpleContentUpdate forChildResourcesOf(String path) { + if (path != null) { + String queryString = "SELECT * FROM [nt:base] AS s WHERE ISCHILDNODE(s,'" + path + "')"; + LOG.debug("Running query: " + queryString); + CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); + } + return this; + } + + public SimpleContentUpdate forDescendantResourcesOf(String path) { + if (path != null) { + String queryString = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE(s,'" + path + "')"; + LOG.debug("Running query: " + queryString); + CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); + } + return this; + } + + public SimpleContentUpdate forChildResourcesOfWithProperties(String path, Map<String, Object> conditionProperties) { + if (path != null && conditionProperties != null) { + String queryString = "SELECT * FROM [nt:base] AS s WHERE ISCHILDNODE(s,'" + path + "')" + getQueryStringForProperties(conditionProperties); + LOG.debug("Running query: " + queryString); + CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); + } + return this; + } + + public SimpleContentUpdate forDescendantResourcesOfWithProperties(String path, Map<String, Object> conditionProperties) { + if (path != null && conditionProperties != null) { + String queryString = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE(s,'" + path + "')" + getQueryStringForProperties(conditionProperties); + LOG.debug("Running query: " + queryString); + CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); + } + return this; + } + + public SimpleContentUpdate printFoundResources() { + resourceList.forEach(s -> LOG.info("Found " + s.getPath())); + return this; + } + + private String getQueryStringForProperties(Map<String, Object> properties) { + String queryString = ""; + for (String key: properties.keySet()) { + queryString += " AND s.[" + key + "] = '" + properties.get(key).toString() + "'"; + } + return queryString; + } + + /** content edit methods **/ + public void remove() { + try { + for (Resource current : resourceList) { + LOG.debug("Removing resource " + current.getPath()); + resourceResolver.delete(current); + } + resourceResolver.commit(); + } catch (PersistenceException e) { + LOG.error("Failed to commit changes.", e); + } + } + + public void setProperty(String name, Object value) { + if (name != null) { + try { + for (Resource current : resourceList) { + LOG.debug("Setting property " + name + "=" + value + " for resource " + current.getPath()); + ModifiableValueMap properties = current.adaptTo(ModifiableValueMap.class); + properties.put(name, value); + } + resourceResolver.commit(); + } catch (PersistenceException e) { + LOG.error("Failed to commit changes.", e); + } + } + } + + public void removeProperty(String name) { + if (name != null) { + try { + for (Resource current : resourceList) { + LOG.debug("Removing property " + name + " for resource " + current.getPath()); + ModifiableValueMap properties = current.adaptTo(ModifiableValueMap.class); + properties.remove(name); + } + resourceResolver.commit(); + } catch (PersistenceException e) { + LOG.error("Failed to commit changes.", e); + } + } + } + + public void renameProperty(String oldName, String newName) { + if (oldName != null && newName != null) { + try { + for (Resource current : resourceList) { + LOG.debug("Renaming property " + oldName + " to " + newName + " for resource " + current.getPath()); + ModifiableValueMap properties = current.adaptTo(ModifiableValueMap.class); + Object value = properties.remove(oldName); + properties.put(newName, value); + } + resourceResolver.commit(); + } catch (PersistenceException e) { + LOG.error("Failed to commit changes.", e); + } + } + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java index 26ef83bf..03ca1ac3 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java @@ -17,6 +17,7 @@ package de.valtech.aecu.core.groovy.console.bindings.provider; import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; +import de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate; import de.valtech.aecu.core.groovy.console.bindings.hello.HelloWorld; import groovy.lang.Binding; import org.apache.sling.api.SlingHttpServletRequest; @@ -25,8 +26,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Map; - /** * Provides additional AECU Bindings for the Groovy Console * @author Roxana Muresan @@ -43,10 +42,10 @@ public class AecuBindingExtensionProvider implements BindingExtensionProvider { @Override public Binding getBinding(SlingHttpServletRequest request) { Binding binding = defaultBindingExtensionProvider.getBinding(request); - Map<String, Object> inheritedBindings = binding.getVariables(); - inheritedBindings.put("helloWorld", new HelloWorld()); + binding.setVariable("helloWorld", new HelloWorld()); + binding.setVariable("simpleContentUpdate", new SimpleContentUpdate(request.getResourceResolver())); - return new Binding(inheritedBindings); + return binding; } } diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy new file mode 100644 index 00000000..fd1aa58d --- /dev/null +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -0,0 +1,23 @@ +println "simpleContentUpdate is $simpleContentUpdate" + +def conditionMap = [:] +//conditionMap['sling:resourceType'] = "weretail/components/content/heroimage" +//conditionMap['jcr:primaryType'] = "cq:Page" +//conditionMap['fileReference'] = "/content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/surfer-wave-01.jpg" + +simpleContentUpdate +// test filter methods +// .forResources((String[])["/content/we-retail/ca/en/jcr:content","/invalid/path", "/content/we-retail/ca/en/experience/jcr:content"]) +// .forChildResourcesOf("/content/we-retail/ca/en/experience") +// .forDescendantResourcesOf("/content/we-retail/ca/en/experience") + .forChildResourcesOfWithProperties("/content/we-retail/ca/en/experience", conditionMap) +// .forDescendantResourcesOfWithProperties("/content/we-retail/ca/en", conditionMap) + +// print filter results in log file + .printFoundResources() + +// test editor methods +// .setProperty("newProperty", "added by aecu") +// .renameProperty("newProperty", "delete_me_later") +// .removeProperty("delete_me_later") +// .remove() \ No newline at end of file diff --git a/pom.xml b/pom.xml index 96f7e3fd..547f9c7b 100644 --- a/pom.xml +++ b/pom.xml @@ -453,12 +453,16 @@ </exclusion> </exclusions> </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - <version>3.0.1</version> - </dependency> - + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.0.1</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-collections4</artifactId> + <version>4.1</version> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> From 9c21507f7c0720a1383fe32ca8ebd9774f0f2ba2 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 7 Jun 2018 16:43:43 +0200 Subject: [PATCH 047/122] AECU-Binding-sample: changing method pattern for properties editing methods --- .../groovy/console/bindings/SimpleContentUpdate.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 786f4b44..569bb517 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -123,7 +123,7 @@ public void remove() { } } - public void setProperty(String name, Object value) { + public SimpleContentUpdate setProperty(String name, Object value) { if (name != null) { try { for (Resource current : resourceList) { @@ -136,9 +136,10 @@ public void setProperty(String name, Object value) { LOG.error("Failed to commit changes.", e); } } + return this; } - public void removeProperty(String name) { + public SimpleContentUpdate removeProperty(String name) { if (name != null) { try { for (Resource current : resourceList) { @@ -151,9 +152,10 @@ public void removeProperty(String name) { LOG.error("Failed to commit changes.", e); } } + return this; } - public void renameProperty(String oldName, String newName) { + public SimpleContentUpdate renameProperty(String oldName, String newName) { if (oldName != null && newName != null) { try { for (Resource current : resourceList) { @@ -167,6 +169,7 @@ public void renameProperty(String oldName, String newName) { LOG.error("Failed to commit changes.", e); } } + return this; } } From 8d26763857b4aae9df9f911d77ba9fdbfd07f36e Mon Sep 17 00:00:00 2001 From: Bryan Gerhard Chavez <bryan.chavez@valtech.de> Date: Mon, 11 Jun 2018 16:04:47 +0200 Subject: [PATCH 048/122] Execute Servlet for executing groovy scripts. --- .../aecu/core/service/ExecutionServlet.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java diff --git a/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java new file mode 100644 index 00000000..f0c521d8 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.service; + + +import org.apache.felix.scr.annotations.sling.SlingServlet; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.servlets.SlingAllMethodsServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletException; +import java.io.IOException; + + +@SlingServlet(label = "Valtech AECU :: Execute", methods = { "GET" }, paths = { "/bin/public/valtech/aecu/execute"}, metatype = false) +public class ExecutionServlet extends SlingAllMethodsServlet { + + private static final Logger LOG = LoggerFactory.getLogger(ExecutionServlet.class); + + + @Override + protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("hola"); + } + +} \ No newline at end of file From 48d9a7a9e5bd547c20eced8d008f6a4a2f6ef392 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 11 Jun 2018 16:11:04 +0200 Subject: [PATCH 049/122] changed to OSGI annotation --- .../aecu/core/service/ExecutionServlet.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java index f0c521d8..9980f188 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java @@ -17,20 +17,29 @@ package de.valtech.aecu.core.service; -import org.apache.felix.scr.annotations.sling.SlingServlet; +import java.io.IOException; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; + import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.servlets.SlingAllMethodsServlet; +import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.servlet.ServletException; -import java.io.IOException; - -@SlingServlet(label = "Valtech AECU :: Execute", methods = { "GET" }, paths = { "/bin/public/valtech/aecu/execute"}, metatype = false) +@Component(immediate = true, +service = {Servlet.class}, +property = { + "sling.servlet.paths=/bin/public/valtech/aecu/execute", + "sling.servlet.extensions=json", + "sling.servlet.methods=GET" +}) public class ExecutionServlet extends SlingAllMethodsServlet { + private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(ExecutionServlet.class); From fc0ac4ab0cf417b36a1eb4156d256ed789751258 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 12 Jun 2018 11:31:59 +0200 Subject: [PATCH 050/122] added chart and duration --- .../de/valtech/aecu/service/HistoryEntry.java | 30 +++++++++++++++---- .../core/model/history/HistoryDataItem.java | 19 ++++++++++++ .../core/model/history/HistoryOverview.java | 29 ++++++++++++++++++ .../aecu/clientlibs/aecu.editor/css/aecu.css | 15 ++++++++++ .../executionResults/executionResults.html | 4 +-- .../content/history/overview/overview.html | 21 +++++++++++-- .../aecu/tools/history/dataitem/dataitem.html | 3 ++ .../aecu/tools/history/page/.content.xml | 4 +++ 8 files changed, 115 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java index d5e989b0..888c178d 100644 --- a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -31,17 +31,37 @@ public interface HistoryEntry { * Execution state (e.g. running) */ public enum STATE { - RUNNING, - FINISHED + RUNNING("Running"), + FINISHED("Finished"); + + private String label; + + private STATE(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } }; /** * Execution result (e.g. successful) */ public enum RESULT { - SUCCESS, - FAILURE, - UNKNOWN + SUCCESS("Success"), + FAILURE("Failed"), + UNKNOWN("Unknown"); + + private String label; + + private RESULT(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } }; /** diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java index 275ebc0a..82abc044 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java @@ -18,6 +18,7 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.Duration; import javax.annotation.PostConstruct; @@ -28,6 +29,7 @@ import de.valtech.aecu.service.HistoryEntry; import de.valtech.aecu.service.HistoryEntry.RESULT; +import de.valtech.aecu.service.HistoryEntry.STATE; /** * Model class for a single history item. @@ -58,6 +60,23 @@ public String getDate() { return format.format(history.getEnd()); } + /** + * Returns the duration of the run. + * + * @return duration + */ + public String getDuration() { + if (!STATE.FINISHED.equals(history.getState())) { + return ""; + } + Duration duration = Duration.between(history.getStart().toInstant(), history.getEnd().toInstant()); + long seconds = duration.getSeconds(); + if (seconds > 0) { + return duration.getSeconds() + "s"; + } + return (duration.getNano() / 1000000) + "ms"; + } + /** * Returns the status icon of the run. * diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java index 1440ea8b..68baedea 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java @@ -16,12 +16,15 @@ */ package de.valtech.aecu.core.model.history; +import java.math.BigDecimal; +import java.math.MathContext; import java.text.DateFormat; import java.text.SimpleDateFormat; import javax.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.request.RequestParameter; import org.apache.sling.api.resource.Resource; @@ -30,6 +33,7 @@ import org.apache.sling.models.annotations.injectorspecific.SlingObject; import de.valtech.aecu.core.history.HistoryUtil; +import de.valtech.aecu.service.ExecutionResult; import de.valtech.aecu.service.HistoryEntry; /** @@ -101,4 +105,29 @@ public String getEnd() { return format.format(historyEntry.getEnd()); } + /** + * Returns the percentages of successful and failed scripts. + * + * @return percentages (successful, failed) + */ + public Pair<String, String> getPercentages() { + int countAll = historyEntry.getSingleResults().size(); + if (countAll == 0) { + return Pair.of("0", "0"); + } + double countOk = 0; + double countFailed = 0; + for (ExecutionResult result : historyEntry.getSingleResults()) { + if (result.isSuccess()) { + countOk++; + } + else { + countFailed++; + } + } + BigDecimal percentageOk = new BigDecimal((countOk / countAll) * 100); + BigDecimal percentageFailed = new BigDecimal((countFailed / countAll) * 100); + return Pair.of(percentageOk.round(new MathContext(2)).toString(), percentageFailed.round(new MathContext(2)).toString()); + } + } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index 960681c3..7824bd17 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -23,3 +23,18 @@ table.aecu-history-detail td { .icon-color-inprogress { color: blue; } + +.aecu-color-ok { + color: green; +} + +.aecu-color-fail { + color: red; +} + +.aecu-chart-text { + line-height: 1; + text-anchor: middle; + font-size: 0.5em; + transform: translateY(0.35em); +} diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html index 90010bba..3fadc044 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html @@ -16,9 +16,7 @@ <h2>Execution details for ${cmp.history.singleResults.size} scripts</h2> <coral-accordion> <sly data-sly-list="${cmp.history.singleResults}"> <coral-accordion-item> - <coral-accordion-item-label> - <coral-icon icon="${item.success ? 'checkCircle' : 'closeCircle'}" class="icon-color-${item.success ? 'ok' : 'fail'}" > - </coral-icon> + <coral-accordion-item-label class="aecu-color-${item.success ? 'ok' : 'fail'}"> ${item.path} </coral-accordion-item-label> <coral-accordion-item-content> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html index b23c7c5b..36845ac0 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -2,8 +2,25 @@ <h1>Run details</h1> <table class="aecu-history-overview" width="100%"> <tr> - <td>State: ${cmp.history.state.name}</td> - <td rowspan="3">${cmp.history.result.name}</td> + <td>State: ${cmp.history.state.label}</td> + <td rowspan="4"> + <svg width="150px" height="150px" viewBox="0 0 50 50" class="donut"> + <circle class="donut-ring" cx="25" cy="25" r="22" fill="transparent" stroke="grey" stroke-width="0.2"></circle> + <circle class="donut-outerring" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="grey" stroke-width="8.5"></circle> + <circle class="donut-hole" cx="25" cy="25" r="15.91549430918954" fill="#fff"></circle> + <circle class="donut-innerring" cx="25" cy="25" r="12.5" fill="transparent" stroke="grey" stroke-width="2"></circle> + <circle class="donut-red" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#ef1616" stroke-width="8"></circle> + <circle class="donut-green" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#4bb43d" stroke-width="8" stroke-dasharray="${cmp.percentages.left} ${cmp.percentages.right}" stroke-dashoffset="25"></circle> + <g> + <text x="50%" y="50%" class="aecu-chart-text"> + ${cmp.percentages.left}% + </text> + </g> + </svg> + </td> + </tr> + <tr> + <td>Result: ${cmp.history.result.label}</td> </tr> <tr> <td>Start: ${cmp.start}</td> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html index e683e95b..ba98c2e2 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html @@ -2,6 +2,9 @@ <!--/* TODO: investigate why we need the class for the Paginator to work */--> <tr is="coral-table-row" class="foundation-collection-item"> <td is="coral-table-cell"><a href="/apps/valtech/aecu/tools/history/details.html?entry=${dataItem.path}">${dataItem.date}</a></td> + <td is="coral-table-cell"> + ${dataItem.duration} + </td> <td is="coral-table-cell"> <coral-icon icon="${dataItem.statusIcon}" size="M" class="icon-color-${dataItem.statusColor}" > </coral-icon> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml index 208caa6b..b407cfec 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml @@ -44,6 +44,10 @@ jcr:primaryType="nt:unstructured" jcr:title="Date" /> + <duration + jcr:primaryType="nt:unstructured" + jcr:title="Duration" + /> <status jcr:primaryType="nt:unstructured" jcr:title="Status" From 2f9b2e2a0f56a296304d36d43dee0a3cdef35143 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 12 Jun 2018 15:32:31 +0200 Subject: [PATCH 051/122] fixed issue when no history entries exist --- .../main/java/de/valtech/aecu/core/history/HistoryUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index c1603aac..98b778a5 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -264,7 +264,10 @@ private Resource getLastChild(Resource resource) { Resource last = null; Iterator<Resource> lastIterator = resource.listChildren(); while (lastIterator.hasNext()) { - last = lastIterator.next(); + Resource candidate = lastIterator.next(); + if (!AccessControlConstants.REP_POLICY.equals(candidate.getName())) { + last = candidate; + } } return last; } From 513545a03a28bf2c2cb6869b63e851135673faf9 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 12 Jun 2018 15:42:42 +0200 Subject: [PATCH 052/122] fixed number format --- .../de/valtech/aecu/core/model/history/HistoryOverview.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java index 68baedea..2bc1362f 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java @@ -127,7 +127,9 @@ public Pair<String, String> getPercentages() { } BigDecimal percentageOk = new BigDecimal((countOk / countAll) * 100); BigDecimal percentageFailed = new BigDecimal((countFailed / countAll) * 100); - return Pair.of(percentageOk.round(new MathContext(2)).toString(), percentageFailed.round(new MathContext(2)).toString()); + String valueOk = percentageOk.round(new MathContext(2)).toPlainString(); + String valueFailed = percentageFailed.round(new MathContext(2)).toPlainString(); + return Pair.of(valueOk, valueFailed); } } From 3fcf428844d528402cccb2e657122401d716b936 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Thu, 14 Jun 2018 15:35:37 +0200 Subject: [PATCH 053/122] show accordion item based on parameter --- .../valtech/aecu/clientlibs/aecu.editor/js.txt | 4 +++- .../aecu/clientlibs/aecu.editor/js/history.js | 18 ++++++++++++++++++ .../executionResults/executionResults.html | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt index 1544c16c..90ab8e20 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt @@ -1 +1,3 @@ -#base=js \ No newline at end of file +#base=js + +history.js diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js new file mode 100644 index 00000000..dcbff0a8 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js @@ -0,0 +1,18 @@ +$(document).ready(function () { + + var search = window.location.search; + if (search && search.includes('aecuScriptPath')) { + search = search.substring(1); + params = search.split('&'); + for (var i = 0; i < params.length; i++) { + var param = params[i]; + var parts = param.split('='); + if (parts[0] == 'aecuScriptPath') { + var name = parts[1]; + var item = jQuery("coral-accordion-item[data-path='" + name + "']"); + item[0].selected = true; + } + } + } + +}); diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html index 3fadc044..b8c3f6fb 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html @@ -15,7 +15,7 @@ <h2>Execution details</h2> <h2>Execution details for ${cmp.history.singleResults.size} scripts</h2> <coral-accordion> <sly data-sly-list="${cmp.history.singleResults}"> - <coral-accordion-item> + <coral-accordion-item data-path="${item.path}"> <coral-accordion-item-label class="aecu-color-${item.success ? 'ok' : 'fail'}"> ${item.path} </coral-accordion-item-label> From 1ec79def41d6b31a9e85d6c8eaa1ca5a39736c8e Mon Sep 17 00:00:00 2001 From: Bryan Gerhard Chavez <bryan.chavez@valtech.de> Date: Thu, 14 Jun 2018 15:47:44 +0200 Subject: [PATCH 054/122] Execution page Execution Servlet Request Handler framework Executor JS Lowered the maven version required. --- core/pom.xml | 4 + .../core/model/execute/ExecuteDataSource.java | 74 +++++++++ .../aecu/core/service/ExecutionServlet.java | 51 ------ .../aecu/core/servlets/BaseServlet.java | 63 ++++++++ .../aecu/core/servlets/ExecutionServlet.java | 145 ++++++++++++++++++ pom.xml | 8 +- .../nav/tools/aecu/execute/.content.xml | 8 + .../aecu/clientlibs/aecu.editor/js.txt | 8 +- .../aecu/clientlibs/aecu.editor/js/aecu.js | 19 +++ .../clientlibs/aecu.editor/js/constants.js | 39 +++++ .../clientlibs/aecu.editor/js/executor.js | 125 +++++++++++++++ .../aecu.editor/js/requestHandler.js | 31 ++++ .../aecu/clientlibs/aecu.editor/js/utils.js | 32 ++++ .../aecu/tools/execute/dataitem/dataitem.html | 13 ++ .../tools/execute/datasource/datasource.html | 1 + .../aecu/tools/execute/page/.content.xml | 99 ++++++++++++ 16 files changed, 667 insertions(+), 53 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java delete mode 100644 core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java create mode 100644 core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java create mode 100644 core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java create mode 100644 ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml diff --git a/core/pom.xml b/core/pom.xml index ac629207..07061f80 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -101,5 +101,9 @@ <groupId>junit-addons</groupId> <artifactId>junit-addons</artifactId> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> </dependencies> </project> diff --git a/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java new file mode 100644 index 00000000..744382c5 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.model.execute; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +import com.adobe.granite.ui.components.ds.ValueMapResource; +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.AecuService; +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.injectorspecific.SlingObject; + +import com.adobe.granite.ui.components.ds.DataSource; +import com.adobe.granite.ui.components.ds.SimpleDataSource; + + +/** + * Datasource model for execute page. + * + * @author Bryan Chavez + */ +@Model(adaptables=SlingHttpServletRequest.class) +public class ExecuteDataSource { + + private static final String ITEM_TYPE = "valtech/aecu/tools/execute/dataitem"; + private static final String ALLOWED_PATH = "/etc/groovyconsole/scripts"; + + @SlingObject + SlingHttpServletRequest request; + + @Inject + private AecuService aecuService; + + @PostConstruct + public void setup() throws AecuException{ + + String path = request.getParameter("searchPath"); + List<Resource> entries = new ArrayList<>(); + + if(path!=null && StringUtils.isNotEmpty(path) && path.startsWith(ALLOWED_PATH)){ + List<String> allowedScripts = aecuService.getFiles(path); + ResourceResolver resourceResolver = request.getResourceResolver(); + for(String scriptPath : allowedScripts){ + entries.add(new ValueMapResource(resourceResolver, scriptPath, ITEM_TYPE, null)); + } + } + + DataSource ds = new SimpleDataSource(entries.iterator()); + request.setAttribute(DataSource.class.getName(), ds); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java deleted file mode 100644 index 9980f188..00000000 --- a/core/src/main/java/de/valtech/aecu/core/service/ExecutionServlet.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 Valtech GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> - */ -package de.valtech.aecu.core.service; - - -import java.io.IOException; - -import javax.servlet.Servlet; -import javax.servlet.ServletException; - -import org.apache.sling.api.SlingHttpServletRequest; -import org.apache.sling.api.SlingHttpServletResponse; -import org.apache.sling.api.servlets.SlingAllMethodsServlet; -import org.osgi.service.component.annotations.Component; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -@Component(immediate = true, -service = {Servlet.class}, -property = { - "sling.servlet.paths=/bin/public/valtech/aecu/execute", - "sling.servlet.extensions=json", - "sling.servlet.methods=GET" -}) -public class ExecutionServlet extends SlingAllMethodsServlet { - - private static final long serialVersionUID = 1L; - private static final Logger LOG = LoggerFactory.getLogger(ExecutionServlet.class); - - - @Override - protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { - response.getWriter().write("hola"); - } - -} \ No newline at end of file diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java new file mode 100644 index 00000000..fd561b3d --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +package de.valtech.aecu.core.servlets; + +import java.io.IOException; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.servlets.SlingAllMethodsServlet; + +/** + * @author Bryan Chavez + */ +public class BaseServlet extends SlingAllMethodsServlet { + + private static final long serialVersionUID = -5240930544859160292L; + + protected static final String ERROR_MESSAGE_INTERNAL_SERVER = "Internal Server Error"; + + + protected void setNoCache(HttpServletResponse response) { + response.setHeader("Cache-control", "no-cache, no-store"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires", "-1"); + } + + protected void writeResult(SlingHttpServletResponse response, String json, int status) throws IOException { + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.setStatus(status); + response.getWriter().write(json); + } + + protected void writeResult(SlingHttpServletResponse response, String json) throws IOException { + writeResult(response,json,HttpServletResponse.SC_OK); + } + + protected void sendInternalServerError(SlingHttpServletResponse response) throws IOException { + writeResult(response,ERROR_MESSAGE_INTERNAL_SERVER, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + protected boolean validateParameter(String param){ + return param != null && StringUtils.isNotEmpty(param); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java new file mode 100644 index 00000000..42f5d7b4 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java @@ -0,0 +1,145 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +package de.valtech.aecu.core.servlets; + + +import java.io.IOException; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; + +import de.valtech.aecu.core.history.HistoryUtil; +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.ExecutionResult; +import de.valtech.aecu.service.HistoryEntry; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.SlingHttpServletResponse; +import org.apache.sling.api.resource.ResourceResolver; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonObject; + +/** + * @author Bryan Chavez + */ + +@Component(immediate = true, +service = {Servlet.class}, +property = { + "sling.servlet.paths=/bin/public/valtech/aecu/execute", + "sling.servlet.extensions=json", + "sling.servlet.methods=GET" +}) +public class ExecutionServlet extends BaseServlet { + + private static final long serialVersionUID = 1L; + private static final Logger LOG = LoggerFactory.getLogger(ExecutionServlet.class); + + protected static final String ERROR_MESSAGE_MANDATORY = "ExecutionServlet :: Make sure your are sending the correct parameters."; + + @Reference + AecuService aecuService; + + + @Override + protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { + + this.setNoCache(response); + + String historyEntryAction = request.getParameter("historyEntryAction"); + String aecuScriptPath = request.getParameter("aecuScriptPath"); + if(!this.validateParameter(aecuScriptPath) || !this.validateParameter(historyEntryAction)){ + this.writeResult(response, ERROR_MESSAGE_MANDATORY); + return; + } + + try { + HistoryEntry historyEntry = this.getHistoryEntry(request, response, historyEntryAction); + ExecutionResult executionResult = aecuService.execute(aecuScriptPath); + aecuService.storeExecutionInHistory(historyEntry, executionResult); + this.finishHistoryEntry(historyEntry,historyEntryAction); + response.getWriter().write(this.prepareJson(executionResult.isSuccess(),historyEntry.getRepositoryPath())); + + }catch (AecuException e){ + this.sendInternalServerError(response); + } + + } + + protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHttpServletResponse response, String historyEntryAction) + throws AecuException, IOException{ + + HistoryEntry historyEntry; + + switch (historyEntryAction.toLowerCase()) { + case "use": + case "close": + //Used for "use" and "close" + String historyEntryPath = request.getParameter("historyEntryPath"); + if(!this.validateParameter(historyEntryPath)){ + this.writeResult(response, ERROR_MESSAGE_MANDATORY); + return null; + } + + ResourceResolver resolver = request.getResourceResolver(); + HistoryUtil historyUtil = new HistoryUtil(); + historyEntry = historyUtil.readHistoryEntry(resolver.getResource(historyEntryPath)); + break; + default: + //Used for "single" and "create" + historyEntry = aecuService.createHistoryEntry(); + break; + } + + return historyEntry; + } + + protected HistoryEntry finishHistoryEntry(HistoryEntry historyEntry, String historyEntryAction) throws AecuException{ + + switch (historyEntryAction.toLowerCase()) { + case "single": + case "close": + //Used for "single" and "close" + aecuService.finishHistoryEntry(historyEntry); + break; + } + + return historyEntry; + + } + + /** + * This method builds the JSON String for the response. + * Eg: {"success": true,"historyEntryPath":"/var/aecu/2018/6/13/152892696338961314"} + * + * @param status + * @param historyEntryPath + * @return json String + */ + protected String prepareJson (boolean status, String historyEntryPath) { + JsonObject json = new JsonObject(); + json.addProperty("success",status); + json.addProperty("historyEntryPath", historyEntryPath); + return json.toString(); + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 96f7e3fd..b3a9cc39 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ <configuration> <rules> <requireMavenVersion> - <version>[3.3.9,)</version> + <version>[3.2.5,)</version> </requireMavenVersion> <requireJavaVersion> <message>Project must be compiled with Java 8 or higher</message> @@ -483,6 +483,12 @@ <version>1.4</version> <scope>test</scope> </dependency> + <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.3</version> + </dependency> </dependencies> </dependencyManagement> diff --git a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml new file mode 100644 index 00000000..17915990 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" + jcr:primaryType="nt:unstructured" + jcr:title="Execute" + jcr:description="Execute one or more scripts" + href="/apps/valtech/aecu/tools/execute/page.html" + icon="playCircle" +/> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt index 1544c16c..8be9033d 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js.txt @@ -1 +1,7 @@ -#base=js \ No newline at end of file +#base=js + +aecu.js +constants.js +requestHandler.js +executor.js +utils.js \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js new file mode 100644 index 00000000..cf0b1b9f --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js @@ -0,0 +1,19 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +/* Initialize of variable */ +var AECU = AECU || {}; \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js new file mode 100644 index 00000000..2b7784f3 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +AECU.Constants = {}; + +AECU.Constants.Executor = { + servletPath : "/bin/public/valtech/aecu/execute?aecuScriptPath={0}&historyEntryAction={1}&historyEntryPath={2}", + historyPath : "/apps/valtech/aecu/tools/history/details.html?entry={0}&aecuScriptPath={1}" +} + +AECU.Constants.Executor.Status = { + ready : "Ready", + inProgress : "In progress", + fail : "Failed", + pending : "Pending...", + executed: "Successful", + internalError: "Internal Server Error" +} + +AECU.Constants.Executor.HistoryEntryActions = { + single : "single", + create : "create", + use : "use", + close : "close" +} \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js new file mode 100644 index 00000000..f8be825a --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js @@ -0,0 +1,125 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +AECU.Executor = {}; + + +AECU.Executor.historyEntryPath; + + +AECU.Executor.doGET = function(getProps){ + /* ADD HERE YOUR COMMON EXECUTOR AJAX PROPERTIES AND + MERGE THEM WITH getPros */ + var props = { + async: false + } + var executorGetProps = $.extend({},props, getProps); + AECU.RequestHandler.GET(executorGetProps); +} + + +AECU.Executor.executeAll = function(tableRows) { + AECU.Executor.changeAllStatus(AECU.Constants.Executor.Status.pending); + var historyEntryAction; + for (var i = 0, length = tableRows.length; i < length; i++) { + if(i == 0){ + historyEntryAction = AECU.Constants.Executor.HistoryEntryActions.create; + }else if(i == tableRows.length-1){ + historyEntryAction = AECU.Constants.Executor.HistoryEntryActions.close; + }else{ + historyEntryAction = AECU.Constants.Executor.HistoryEntryActions.use; + } + AECU.Executor.execute(tableRows[i],historyEntryAction,AECU.Executor.historyEntryPath); + } + + AECU.Executor.historyEntryPath = undefined; +} + + +AECU.Executor.execute = function(row,historyEntryAction,historyEntryPath) { + this.doGET({ + url : AECU.Constants.Executor.servletPath.format(row.dataset.aecuExecuteScript,historyEntryAction,historyEntryPath), + beforeSend: function(){ + AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.inProgress); + AECU.Executor.disableButton(row); + }, + success: function( data ) { + var json = JSON.parse(data); + AECU.Executor.historyEntryPath = json.historyEntryPath; + AECU.Executor.addHistoryLink(row,json.historyEntryPath); + if(json.success){ + AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.executed); + }else{ + AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.fail); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.internalError); + } + }); +} + +AECU.Executor.addHistoryLink = function(row, historyEntryPath){ + var historyLink = $(row).find("[data-aecu-execute-script-history]")[0]; + historyLink.href = AECU.Constants.Executor.historyPath.format(historyEntryPath, row.dataset.aecuExecuteScript); + historyLink.text = "Go to history"; +} + +AECU.Executor.changeStatus = function(row, value){ + $(row).find("[data-aecu-execute-script-status]").text(value); +} + + +AECU.Executor.changeAllStatus = function(value){ + $("[data-aecu-execute-script-status]").text(value); +} + + +AECU.Executor.disableButton = function(row){ + if(row != undefined){ + $(row).find("[data-aecu-execute-script-button]").prop('disabled', true); + }else{ + /* The only button not in a row. */ + $("#aecu-execute-button-all").prop('disabled', true); + } +} + + + +$(document).ready(function(){ + + /* Disable executeAll button is there are no scripts displayed. */ + if($('[data-aecu-execute-script]').length == 0){ + AECU.Executor.disableButton(); + } + + /* Event for executing all scrips displayed in screen. */ + $("#aecu-execute-button-all").on('click', function(e) { + var tableRows = $('[data-aecu-execute-script]'); + if(tableRows.length > 0){ + AECU.Executor.executeAll(tableRows); + } + }); + + /* Event for each row (script) displayed in screen. */ + $('[data-aecu-execute-script-button]').on('click', function(event) { + AECU.Executor.execute( + this.closest('[data-aecu-execute-script]'), + AECU.Constants.Executor.HistoryEntryActions.single,null); + }); + +}); \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js new file mode 100644 index 00000000..50c0c706 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js @@ -0,0 +1,31 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +AECU.RequestHandler = {}; + +AECU.RequestHandler.getProps = { + type : 'GET', + cache: false, + success : function(data){}, + error : function(jqXHR, textStatus, errorThrown){}, + complete: function (jqXHR, textStatus) {} +} + +AECU.RequestHandler.GET = function(props){ + var finalProps = $.extend({},this.getProps, props); + $.ajax(finalProps); +} \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js new file mode 100644 index 00000000..8287762a --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js @@ -0,0 +1,32 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +/* + * Example: "Hello {0}!".format("World"); + * Output: "Hello World!" + * + */ +String.prototype.format = function(){ + var content = this; + var length = arguments.length; + for (var i=0; i < length; i++) + { + var replacement = '{' + i + '}'; + content = content.replace(replacement, arguments[i]); + } + return content; +}; \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html new file mode 100644 index 00000000..8c1c730e --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html @@ -0,0 +1,13 @@ +<tr class="aecu-execute-script" is="coral-table-row" data-aecu-execute-script="${resource.path}"> + <td is="coral-table-cell"> + <button is="coral-button" variant="primary" icon="checkCircle" iconsize="S" data-aecu-execute-script-button> + Execute Script + </button> + </td> + <td is="coral-table-cell" data-aecu-execute-script-path>${resource.path}</td> + <td is="coral-table-cell"><a target="_blank" data-aecu-execute-script-history>* not executed *</a></td> + <td is="coral-table-cell" data-aecu-execute-script-status>Ready</td> + <td is="coral-table-cell" > + <button is="coral-button" type="button" variant="minimal" icon="dragHandle" coral-table-roworder></button> + </td> +</tr> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html new file mode 100644 index 00000000..8384f71d --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html @@ -0,0 +1 @@ +<sly data-sly-use.datasource="de.valtech.aecu.core.model.execute.ExecuteDataSource" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml new file mode 100644 index 00000000..6257f42a --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" + jcr:primaryType="cq:Page"> + <jcr:content + jcr:mixinTypes="[sling:VanityPath]" + jcr:primaryType="nt:unstructured" + jcr:title="AEM Easy Content Upgrade - Execute" + sling:redirect="{Boolean}false" + sling:resourceType="granite/ui/components/shell/collectionpage" + currentView="${state["shell.collectionpage.layoutId"].string}" + modeGroup="aecu-execute-scripts" + targetCollection=".aecu-execute-scripts"> + <head jcr:primaryType="nt:unstructured"> + <clientlibs + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/foundation/includeclientlibs" + categories="[coralui3,granite.ui.coral.foundation,aecu.editor]"/> + </head> + <dialogue jcr:primaryType="nt:unstructured" + sling:resourceType="valtech/aecu/tools/execute/dialogue"/> + <rails jcr:primaryType="nt:unstructured"> + <search + granite:class="cq-rail-components-search" + jcr:primaryType="nt:unstructured" + jcr:title="Search" + sling:resourceType="granite/ui/components/coral/foundation/panel/railpanel"> + <items jcr:primaryType="nt:unstructured"> + <form + granite:id="aecu-execute-scripts-search-form" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form" + action="/apps/valtech/aecu/tools/execute/page.html" + modeGroup="aecu-execute-scripts-search" + searchResultTitle="Scripts to execute" + targetCollection="#aecu-execute-scripts-search"> + <successresponse + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form/responses/reload"/> + <items jcr:primaryType="nt:unstructured"> + <searchPath + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form/pathfield" + fieldLabel="Select the folder or script" + rootPath="/etc/groovyconsole/scripts" + required="{Boolean}true" + filter="hierarchy" + name="searchPath"/> + <submit + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/foundation/form/submit" + text="Search"/> + </items> + </form> + </items> + </search> + </rails> + <views jcr:primaryType="nt:unstructured" + sling:resourceType="valtech/aecu/tools/execute/dialogue"> + <list + granite:rel="aecu-execute-scripts" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/table" + selectionMode="none" + orderable="{Boolean}true" + src="/mnt/overlay/valtech/aecu/tools/execute/page/jcr:content/views/list{.offset,limit}.html" + stateId="shell.collectionpage"> + <columns jcr:primaryType="nt:unstructured"> + <button + jcr:primaryType="nt:unstructured" + jcr:title="Action"/> + <script + jcr:primaryType="nt:unstructured" + jcr:title="Script"/> + <history + jcr:primaryType="nt:unstructured" + jcr:title="History"/> + <status + jcr:primaryType="nt:unstructured" + jcr:title="Status"/> + </columns> + <datasource + jcr:primaryType="nt:unstructured" + sling:resourceType="valtech/aecu/tools/execute/datasource" + itemResourceType="valtech/aecu/tools/execute/dataitem"/> + </list> + </views> + <actions jcr:primaryType="nt:unstructured"> + <secondary jcr:primaryType="nt:unstructured"> + <executeAll + granite:id="aecu-execute-button-all" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/button" + text="Execute all" + variant="primary"> + </executeAll> + </secondary> + </actions> + </jcr:content> +</jcr:root> From 3c1d31b8fb81f75d94545987eadb2a8d5f425a87 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 15 Jun 2018 11:02:52 +0200 Subject: [PATCH 055/122] added pre tags + refactoring --- .../aecu/clientlibs/aecu.editor/js/history.js | 34 ++++++++++++------- .../templates/executionResult.html | 4 +-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js index dcbff0a8..2b07372f 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js @@ -1,18 +1,28 @@ $(document).ready(function () { - var search = window.location.search; - if (search && search.includes('aecuScriptPath')) { - search = search.substring(1); - params = search.split('&'); - for (var i = 0; i < params.length; i++) { - var param = params[i]; - var parts = param.split('='); - if (parts[0] == 'aecuScriptPath') { - var name = parts[1]; - var item = jQuery("coral-accordion-item[data-path='" + name + "']"); - item[0].selected = true; + AECU.History = {}; + + /** + * Select the accordion item based on the GET parameter. + */ + AECU.History.selectAccordion = function() { + var search = window.location.search; + if (search && search.includes('aecuScriptPath')) { + search = search.substring(1); + params = search.split('&'); + for (var i = 0; i < params.length; i++) { + var param = params[i]; + var parts = param.split('='); + if (parts[0] == 'aecuScriptPath') { + var name = parts[1]; + var item = jQuery("coral-accordion-item[data-path='" + name + "']"); + item[0].selected = true; + } } } - } + }; + + + AECU.History.selectAccordion(); }); diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html index d1babd62..80781938 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html @@ -14,12 +14,12 @@ <sly data-sly-test="${result.result}"> <h3 data-sly-test="${!isFallback}">Result</h3> <h4 data-sly-test="${isFallback}">Result</h4> - ${result.result} + <pre>${result.result}</pre> </sly> <sly data-sly-test="${result.output}"> <h3 data-sly-test="${!isFallback}">Output</h3> <h4 data-sly-test="${isFallback}">Output</h4> - ${result.output} + <pre>${result.output}</pre> </sly> <sly data-sly-test="${result.fallbackResult}"> From c01e3c66e9fd06acb76e8e002e5626495171a3b0 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 15 Jun 2018 11:50:00 +0200 Subject: [PATCH 056/122] fixed selecting of accordion item --- .../aecu/clientlibs/aecu.editor/js/history.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js index 2b07372f..f49c7a26 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js @@ -1,4 +1,5 @@ -$(document).ready(function () { +(function($, ns, channel, window) { + "use strict"; AECU.History = {}; @@ -9,20 +10,26 @@ $(document).ready(function () { var search = window.location.search; if (search && search.includes('aecuScriptPath')) { search = search.substring(1); - params = search.split('&'); + var params = search.split('&'); for (var i = 0; i < params.length; i++) { var param = params[i]; var parts = param.split('='); if (parts[0] == 'aecuScriptPath') { var name = parts[1]; var item = jQuery("coral-accordion-item[data-path='" + name + "']"); - item[0].selected = true; + Coral.commons.ready(item[0], function() { + item[0].selected = true; + }); } } } }; + /** + * Initial actions + */ + $(document).ready(function() { + AECU.History.selectAccordion(); + }); - AECU.History.selectAccordion(); - -}); +})(jQuery, Granite.author, jQuery(document), this); From e4a04e1cc8a9da375873f833d5593049f3bbee9f Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 15 Jun 2018 13:21:33 +0200 Subject: [PATCH 057/122] docs --- Readme.md | 38 ++++++++++++++++-- .../aecu/core/jmx/AecuServiceMBean.java | 4 +- docs/images/jmx.png | Bin 0 -> 57594 bytes 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 docs/images/jmx.png diff --git a/Readme.md b/Readme.md index f236bbcc..4a6d9cbd 100644 --- a/Readme.md +++ b/Readme.md @@ -14,12 +14,19 @@ Features: # Requirements -AECU requires Java 8 and AEM 6.3 or above. +AECU requires Java 8 and AEM 6.3 or above. Groovy Console can be installed manually if [bundle install](#bundleInstall) is not used. -#Installation +# Installation TODO +## <a name="bundleInstall">Bundle Installation</a> + +To simplify installation we provide a bundle package that already includes the Groovy Console. This makes sure there are no compatibility issues. + +TODO + + # Execution of Migration Scripts TODO @@ -34,7 +41,32 @@ TODO # JMX Interface -TODO +<img src="docs/images/jmx.png"> + +AECU provides JMX methods for executing scripts and reading the history. You can also check the version here. + +## Execute + +This will execute the given script or folder. If a folder is specified then all files (incl. any subfolders) are executed. AECU will respect runmodes during execution. + +Parameters: + * Path: file or folder to execute + +## GetHistory + +Prints the history of the specified last runs. + +Parameters: + * Start index: starts with 0 (= latest history entry) + * Count: number of entries to print + +## GetFiles + +This will print all files that are executable for a given path. You can use this to check which scripts of a given folder would be executed. + +Parameters: +* Path: file or folder to check + # Health Checks diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index 21674c8d..46f84c09 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -56,7 +56,8 @@ public interface AecuServiceMBean { * @return execution result * @throws AecuException error during execution */ - String execute(@Name("Path") @Description("Path to file that should be executed") String path) throws AecuException; + @Description("Executes a single file or all files of a folder structure") + String execute(@Name("Path") @Description("Path to file/folder that should be executed") String path) throws AecuException; /** * Returns history entries. @@ -66,6 +67,7 @@ public interface AecuServiceMBean { * @return history entries * @throws AecuException */ + @Description("Returns the last history entries") String getHistory(@Name("Start index") int start, @Name("Count") int count) throws AecuException; } diff --git a/docs/images/jmx.png b/docs/images/jmx.png new file mode 100644 index 0000000000000000000000000000000000000000..f1bb3d4037c3bb06f65b39ab75e54a625eae8926 GIT binary patch literal 57594 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≢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 literal 0 HcmV?d00001 From 5ff614158b9c451cdc5ee7989a27780ebd167270 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 15 Jun 2018 13:22:31 +0200 Subject: [PATCH 058/122] docs --- Readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 4a6d9cbd..8c1be781 100644 --- a/Readme.md +++ b/Readme.md @@ -20,7 +20,8 @@ AECU requires Java 8 and AEM 6.3 or above. Groovy Console can be installed manua TODO -## <a name="bundleInstall">Bundle Installation</a> +<a name="bundleInstall"></a> +## Bundle Installation To simplify installation we provide a bundle package that already includes the Groovy Console. This makes sure there are no compatibility issues. From 5a16630e7628bccfe65746504e179d974eb3807c Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 15 Jun 2018 13:24:23 +0200 Subject: [PATCH 059/122] docs --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 8c1be781..d5e5e25a 100644 --- a/Readme.md +++ b/Readme.md @@ -55,7 +55,7 @@ Parameters: ## GetHistory -Prints the history of the specified last runs. +Prints the history of the specified last runs. The entries are sorted by date and start with the last run. Parameters: * Start index: starts with 0 (= latest history entry) From 730cf7c945fb86303df1fb225ccf4ceb527cd8c1 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 18 Jun 2018 09:26:47 +0200 Subject: [PATCH 060/122] docs --- Readme.md | 40 +++++++++++++++++++++++++++++++- docs/images/historyDetails.png | Bin 0 -> 92471 bytes docs/images/historyOverview.png | Bin 0 -> 32966 bytes docs/images/tools.png | Bin 0 -> 39247 bytes 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 docs/images/historyDetails.png create mode 100644 docs/images/historyOverview.png create mode 100644 docs/images/tools.png diff --git a/Readme.md b/Readme.md index d5e5e25a..211d48df 100644 --- a/Readme.md +++ b/Readme.md @@ -12,15 +12,31 @@ Features: * Service API * Health Checks +Table of contents +1. [Requirements](#requirements) +2. [Installation](#installation) +3. [Execution of Migration Scripts](#execution) +4. [History of Past Runs](#history) +5. [Extension to Groovy Console](#groovy) +6. [JMX Interface](#jmx) +7. [Health Checks](#healthchecks) +8. [License](#license) + + +<a name="requirements"></a> + # Requirements AECU requires Java 8 and AEM 6.3 or above. Groovy Console can be installed manually if [bundle install](#bundleInstall) is not used. +<a name="installation"></a> + # Installation TODO <a name="bundleInstall"></a> + ## Bundle Installation To simplify installation we provide a bundle package that already includes the Groovy Console. This makes sure there are no compatibility issues. @@ -28,18 +44,36 @@ To simplify installation we provide a bundle package that already includes the G TODO +<a name="execution"></a> + # Execution of Migration Scripts TODO +<a name="history"></a> + # History of Past Runs -TODO +You can find the history in AECU's tools menu. + +<img src="docs/images/tools.png"> + +The history shows all runs that were executed via package install hook, manual run and JMX. It will not display scripts that were executed directly via Groovy Console. + +<img src="docs/images/historyOverview.png"> + +You can click on any run to see the full details. This will show the status for each script. You can also see the output of all scripts. + +<img src="docs/images/historyDetails.png"> + +<a name="groovy"></a> # Extension to Groovy Console TODO +<a name="jmx"></a> + # JMX Interface <img src="docs/images/jmx.png"> @@ -69,6 +103,8 @@ Parameters: * Path: file or folder to check +<a name="healthchecks"></a> + # Health Checks Health checks show you the status of AECU itself and the last migration run. @@ -77,6 +113,8 @@ For the status of older runs use AECU's history page. <img src="docs/images/healthCheck.png"> +<a name="license"></a> + # License The AC Tool is licensed under the [GNU GENERAL PUBLIC LICENSE - v 3](LICENSE). diff --git a/docs/images/historyDetails.png b/docs/images/historyDetails.png new file mode 100644 index 0000000000000000000000000000000000000000..e09a7c20bef1d715202a3e3f74f7e18014d75948 GIT binary patch literal 92471 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 G^S=Oi&hK;p literal 0 HcmV?d00001 diff --git a/docs/images/historyOverview.png b/docs/images/historyOverview.png new file mode 100644 index 0000000000000000000000000000000000000000..910ee01a03fe46f5d7e78f63c91f3dd39fad4dc7 GIT binary patch literal 32966 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 R1$-ajg|O7~f@eCO{{y-}P(A<v literal 0 HcmV?d00001 diff --git a/docs/images/tools.png b/docs/images/tools.png new file mode 100644 index 0000000000000000000000000000000000000000..94c58025c0b8d7a5b82416b3cac8ecfd4eab1973 GIT binary patch literal 39247 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 literal 0 HcmV?d00001 From 5eb904a8f88e1993ad3f27023061c910aa3c1da5 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 18 Jun 2018 16:45:22 +0200 Subject: [PATCH 061/122] added missing node --- .../main/content/jcr_root/apps/settings/granite/.content.xml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml new file mode 100644 index 00000000..491392d5 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" + jcr:primaryType="sling:Folder"/> From f4d9b28de2d12f799116f256edf9fabeacd009e3 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 18 Jun 2018 16:48:24 +0200 Subject: [PATCH 062/122] added missing nodes --- .../settings/granite/operations/maintenance/.content.xml | 6 ++++++ .../operations/maintenance/granite_weekly/.content.xml | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100755 ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml create mode 100755 ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml new file mode 100755 index 00000000..ee344538 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" + jcr:primaryType="sling:OrderedFolder" + sling:configCollectionInherit="true" + sling:configPropertyInherit="true"> +</jcr:root> diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml new file mode 100755 index 00000000..ee344538 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" + jcr:primaryType="sling:OrderedFolder" + sling:configCollectionInherit="true" + sling:configPropertyInherit="true"> +</jcr:root> From 5a9d01c5ee02fb3ab250c6fbb3b0116cd0542ff6 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 11:12:58 +0200 Subject: [PATCH 063/122] AECU-Binding-sample: refactoring: separated traversal, filtering and edit actions --- core/pom.xml | 4 + .../console/bindings/SimpleContentUpdate.java | 137 +++++------------- .../HelloWorld.java => actions/Action.java} | 15 +- .../console/bindings/actions/PrintPath.java | 27 ++++ .../bindings/actions/RemoveProperty.java | 37 +++++ .../bindings/actions/RenameProperty.java | 40 +++++ .../console/bindings/actions/SetProperty.java | 40 +++++ .../console/bindings/filters/FilterBy.java | 23 +++ .../bindings/filters/FilterByProperties.java | 50 +++++++ .../AecuBindingExtensionProvider.java | 8 +- .../traversers/ForChildResourcesOf.java | 54 +++++++ .../traversers/ForDescendantResourcesOf.java | 61 ++++++++ .../bindings/traversers/ForResources.java | 49 +++++++ .../bindings/traversers/TraversData.java | 28 ++++ .../tests_for_simpleContentUpdates.groovy | 35 ++--- pom.xml | 7 + 16 files changed, 480 insertions(+), 135 deletions(-) rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/{hello/HelloWorld.java => actions/Action.java} (74%) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java diff --git a/core/pom.xml b/core/pom.xml index 33ce50b9..031fd470 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -105,5 +105,9 @@ <groupId>junit-addons</groupId> <artifactId>junit-addons</artifactId> </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-library</artifactId> + </dependency> </dependencies> </project> diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 569bb517..3389d9dc 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -16,16 +16,23 @@ */ package de.valtech.aecu.core.groovy.console.bindings; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.sling.api.resource.ModifiableValueMap; +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.actions.RemoveProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.RenameProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.SetProperty; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByProperties; +import de.valtech.aecu.core.groovy.console.bindings.traversers.ForChildResourcesOf; +import de.valtech.aecu.core.groovy.console.bindings.traversers.ForDescendantResourcesOf; +import de.valtech.aecu.core.groovy.console.bindings.traversers.ForResources; +import de.valtech.aecu.core.groovy.console.bindings.traversers.TraversData; import org.apache.sling.api.resource.PersistenceException; -import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.jcr.query.Query; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -37,139 +44,65 @@ public class SimpleContentUpdate { private static final Logger LOG = LoggerFactory.getLogger(SimpleContentUpdate.class); - private ResourceResolver resourceResolver;// TODO check if a system user resource resolver is needed here! + private ResourceResolver resourceResolver;// TODO system user resolver!! - private List<Resource> resourceList = new ArrayList<>();// TODO with stream? + private Map<TraversData, FilterBy> traversalsWithFilter = new HashMap<>(); + private List<Action> actions = new ArrayList<>(); public SimpleContentUpdate(ResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; - } /** content filter methods **/ public SimpleContentUpdate forResources(String[] paths) { - if (paths != null && paths.length > 0) { - List<Resource> resources = new ArrayList<>(); - for (String path : paths) { - if (path != null) { - CollectionUtils.addIgnoreNull(resources, resourceResolver.getResource(path)); - } - } - CollectionUtils.addAll(this.resourceList, resources.iterator()); - } + traversalsWithFilter.put(new ForResources(paths), null); return this; } public SimpleContentUpdate forChildResourcesOf(String path) { - if (path != null) { - String queryString = "SELECT * FROM [nt:base] AS s WHERE ISCHILDNODE(s,'" + path + "')"; - LOG.debug("Running query: " + queryString); - CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); - } + traversalsWithFilter.put(new ForChildResourcesOf(path), null); return this; } - public SimpleContentUpdate forDescendantResourcesOf(String path) { - if (path != null) { - String queryString = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE(s,'" + path + "')"; - LOG.debug("Running query: " + queryString); - CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); - } + public SimpleContentUpdate forChildResourcesOfWithProperties(String path, Map<String, String> conditionProperties) { + traversalsWithFilter.put(new ForChildResourcesOf(path), new FilterByProperties(conditionProperties)); return this; } - public SimpleContentUpdate forChildResourcesOfWithProperties(String path, Map<String, Object> conditionProperties) { - if (path != null && conditionProperties != null) { - String queryString = "SELECT * FROM [nt:base] AS s WHERE ISCHILDNODE(s,'" + path + "')" + getQueryStringForProperties(conditionProperties); - LOG.debug("Running query: " + queryString); - CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); - } + public SimpleContentUpdate forDescendantResourcesOf(String path) { + traversalsWithFilter.put(new ForDescendantResourcesOf(path), null); return this; } - public SimpleContentUpdate forDescendantResourcesOfWithProperties(String path, Map<String, Object> conditionProperties) { - if (path != null && conditionProperties != null) { - String queryString = "SELECT * FROM [nt:base] AS s WHERE ISDESCENDANTNODE(s,'" + path + "')" + getQueryStringForProperties(conditionProperties); - LOG.debug("Running query: " + queryString); - CollectionUtils.addAll(this.resourceList, resourceResolver.findResources(queryString, Query.JCR_SQL2)); - } + public SimpleContentUpdate forDescendantResourcesOfWithProperties(String path, Map<String, String> conditionProperties) { + traversalsWithFilter.put(new ForDescendantResourcesOf(path), new FilterByProperties(conditionProperties)); return this; } - public SimpleContentUpdate printFoundResources() { - resourceList.forEach(s -> LOG.info("Found " + s.getPath())); + /** properties edit methods **/ + public SimpleContentUpdate doSetProperty(String name, String value) { + actions.add(new SetProperty(name, value)); return this; } - private String getQueryStringForProperties(Map<String, Object> properties) { - String queryString = ""; - for (String key: properties.keySet()) { - queryString += " AND s.[" + key + "] = '" + properties.get(key).toString() + "'"; - } - return queryString; - } - - /** content edit methods **/ - public void remove() { - try { - for (Resource current : resourceList) { - LOG.debug("Removing resource " + current.getPath()); - resourceResolver.delete(current); - } - resourceResolver.commit(); - } catch (PersistenceException e) { - LOG.error("Failed to commit changes.", e); - } - } - - public SimpleContentUpdate setProperty(String name, Object value) { - if (name != null) { - try { - for (Resource current : resourceList) { - LOG.debug("Setting property " + name + "=" + value + " for resource " + current.getPath()); - ModifiableValueMap properties = current.adaptTo(ModifiableValueMap.class); - properties.put(name, value); - } - resourceResolver.commit(); - } catch (PersistenceException e) { - LOG.error("Failed to commit changes.", e); - } - } + public SimpleContentUpdate doRemoveProperty(String name) { + actions.add(new RemoveProperty(name)); return this; } - public SimpleContentUpdate removeProperty(String name) { - if (name != null) { - try { - for (Resource current : resourceList) { - LOG.debug("Removing property " + name + " for resource " + current.getPath()); - ModifiableValueMap properties = current.adaptTo(ModifiableValueMap.class); - properties.remove(name); - } - resourceResolver.commit(); - } catch (PersistenceException e) { - LOG.error("Failed to commit changes.", e); - } - } + public SimpleContentUpdate doRenameProperty(String oldName, String newName) { + actions.add(new RenameProperty(oldName, newName)); return this; } - public SimpleContentUpdate renameProperty(String oldName, String newName) { - if (oldName != null && newName != null) { - try { - for (Resource current : resourceList) { - LOG.debug("Renaming property " + oldName + " to " + newName + " for resource " + current.getPath()); - ModifiableValueMap properties = current.adaptTo(ModifiableValueMap.class); - Object value = properties.remove(oldName); - properties.put(newName, value); - } - resourceResolver.commit(); - } catch (PersistenceException e) { - LOG.error("Failed to commit changes.", e); + public String apply() throws PersistenceException { + for (Map.Entry<TraversData, FilterBy> traversWithFilter : traversalsWithFilter.entrySet()) { + for (Action action : actions) { + traversWithFilter.getKey().traverse(resourceResolver, traversWithFilter.getValue(), action); } } - return this; + return "Testing Groovy Console Output :)! And this is how it works \\^^/"; } -} +} \ No newline at end of file diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java similarity index 74% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java index d09ea403..551139b7 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/hello/HelloWorld.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java @@ -14,16 +14,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/> */ -package de.valtech.aecu.core.groovy.console.bindings.hello; +package de.valtech.aecu.core.groovy.console.bindings.actions; -/** - * Groovy Console Bindings first test class - * @author Roxana Muresan - */ -public class HelloWorld { +import com.drew.lang.annotations.NotNull; +import org.apache.sling.api.resource.Resource; + +public interface Action { - public String sayHello() { - return "Hello y'all! >^.^<"; - } + String doAction(@NotNull Resource resource); } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java new file mode 100644 index 00000000..77494c55 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java @@ -0,0 +1,27 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions; + +import org.apache.sling.api.resource.Resource; + +public class PrintPath implements Action { + + @Override + public String doAction(Resource resource) { + return resource.getPath(); + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java new file mode 100644 index 00000000..0b09b911 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions; + +import com.drew.lang.annotations.NotNull; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; + +public class RemoveProperty implements Action { + + private String name; + + public RemoveProperty(@NotNull String name) { + this.name = name; + } + + @Override + public String doAction(Resource resource) { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + properties.remove(name); + return "Removing property " + name + " for resource " + resource.getPath(); + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java new file mode 100644 index 00000000..72ce4c77 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions; + +import com.drew.lang.annotations.NotNull; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; + +public class RenameProperty implements Action { + + private String oldName; + private String newName; + + public RenameProperty(@NotNull String oldName, @NotNull String newName) { + this.oldName = oldName; + this.newName = newName; + } + + @Override + public String doAction(Resource resource) { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + Object value = properties.remove(oldName); + properties.put(newName, value); + return "Renaming property " + oldName + " to " + newName + " for resource " + resource.getPath(); + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java new file mode 100644 index 00000000..e955cc68 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions; + +import com.drew.lang.annotations.NotNull; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; + +public class SetProperty implements Action { + + private String name; + private Object value; + + public SetProperty(@NotNull String name, Object value) { + this.name = name; + this.value = value; + } + + + @Override + public String doAction(Resource resource) { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + properties.put(name, value); + return "Setting property " + name + "=" + value + " for resource " + resource.getPath(); + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java new file mode 100644 index 00000000..4547f8a2 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java @@ -0,0 +1,23 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.filters; + +import org.apache.sling.api.resource.Resource; + +public interface FilterBy { + boolean filter(Resource resource); +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java new file mode 100644 index 00000000..70d5f163 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.filters; + +import com.drew.lang.annotations.NotNull; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; + +import java.util.HashMap; +import java.util.Map; + +public class FilterByProperties implements FilterBy { + + private Map<String, String> conditionProperties = new HashMap<>(); + + public FilterByProperties(@NotNull Map<String, String> conditionProperties) { + this.conditionProperties.putAll(conditionProperties); + } + + @Override + public boolean filter(Resource resource) { + if (resource != null) { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + for (String key : conditionProperties.keySet()) { + String conditionValue = conditionProperties.get(key); + String propertiesValue = properties.get(key, String.class); + + if ((conditionValue == null && propertiesValue != null) || (conditionValue != null && !conditionValue.equals(propertiesValue))) { + return false; + } + } + } + return true; + } +} + diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java index 03ca1ac3..e7b7c9e2 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java @@ -18,13 +18,10 @@ import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; import de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate; -import de.valtech.aecu.core.groovy.console.bindings.hello.HelloWorld; import groovy.lang.Binding; import org.apache.sling.api.SlingHttpServletRequest; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Provides additional AECU Bindings for the Groovy Console @@ -33,8 +30,6 @@ @Component(immediate = true) public class AecuBindingExtensionProvider implements BindingExtensionProvider { - private static final Logger LOG = LoggerFactory.getLogger(AecuBindingExtensionProvider.class); - @Reference private BindingExtensionProvider defaultBindingExtensionProvider; @@ -42,8 +37,7 @@ public class AecuBindingExtensionProvider implements BindingExtensionProvider { @Override public Binding getBinding(SlingHttpServletRequest request) { Binding binding = defaultBindingExtensionProvider.getBinding(request); - binding.setVariable("helloWorld", new HelloWorld()); - binding.setVariable("simpleContentUpdate", new SimpleContentUpdate(request.getResourceResolver())); + binding.setVariable("aecu", new SimpleContentUpdate(request.getResourceResolver())); return binding; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java new file mode 100644 index 00000000..20782fbc --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.traversers; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +import java.util.Iterator; + +public class ForChildResourcesOf implements TraversData { + + private String path; + + public ForChildResourcesOf(String path) { + this.path = path; + } + + + @Override + public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action) throws PersistenceException { + if (path != null) { + Resource parentResource = resourceResolver.getResource(path); + if (parentResource != null) { + Iterator<Resource> resourceIterator = resourceResolver.listChildren(parentResource); + while (resourceIterator.hasNext()) { + Resource resource = resourceIterator.next(); + if (filter == null || filter.filter(resource)) { + if (action != null) { + action.doAction(resource); + } + } + } + resourceResolver.commit(); + } + } + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java new file mode 100644 index 00000000..6fb1dda7 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.traversers; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +import java.util.Iterator; + +public class ForDescendantResourcesOf implements TraversData { + + private String path; + + public ForDescendantResourcesOf(String path) { + this.path = path; + } + + + @Override + public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action) throws PersistenceException { + if (path != null) { + Resource parentResource = resourceResolver.getResource(path); + if (parentResource != null) { + traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action); + } + } + } + + private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, Resource resource, FilterBy filter, Action action) throws PersistenceException { + if (resource != null && resource.hasChildren()) { + Iterator<Resource> childResources = resource.listChildren(); + while (childResources.hasNext()) { + Resource child = childResources.next(); + if (filter == null || filter.filter(child)) { + if (action != null) { + action.doAction(child); + } + } + traverseChildResourcesRecursive(resourceResolver, child, filter, action); + } + resourceResolver.commit(); // TOD: maybe commit will be called to often this way: TODO: think about it for later!! + } + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java new file mode 100644 index 00000000..66b2379c --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.traversers; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +public class ForResources implements TraversData { + + private String[] paths; + + public ForResources(String[] paths) { + this.paths = paths; + } + + @Override + public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action) throws PersistenceException { + if (paths != null && paths.length > 0) { + for (String path : paths) { + if (path != null) { + Resource resource = resourceResolver.getResource(path); + if (filter == null || filter.filter(resource)) { + if (action != null) { + action.doAction(resource); + } + } + } + } + resourceResolver.commit(); + } + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java new file mode 100644 index 00000000..74c021b3 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.traversers; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.ResourceResolver; + +public interface TraversData { + + void traverse(ResourceResolver resourceResolve, FilterBy filter, Action action) throws PersistenceException; + +} diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index fd1aa58d..6fa015df 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -1,23 +1,24 @@ -println "simpleContentUpdate is $simpleContentUpdate" +println "simpleContentUpdate is $aecu" -def conditionMap = [:] -//conditionMap['sling:resourceType'] = "weretail/components/content/heroimage" -//conditionMap['jcr:primaryType'] = "cq:Page" -//conditionMap['fileReference'] = "/content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/surfer-wave-01.jpg" +def conditionMapHero = [:] +conditionMapHero['sling:resourceType'] = "weretail/components/content/heroimage" +conditionMapHero['fileReference'] = "/content/dam/we-retail/en/activities/running/fitness-woman.jpg" + +def conditionMapPage = [:] +conditionMapPage['jcr:primaryType'] = "cq:PageContent" -simpleContentUpdate -// test filter methods -// .forResources((String[])["/content/we-retail/ca/en/jcr:content","/invalid/path", "/content/we-retail/ca/en/experience/jcr:content"]) -// .forChildResourcesOf("/content/we-retail/ca/en/experience") -// .forDescendantResourcesOf("/content/we-retail/ca/en/experience") - .forChildResourcesOfWithProperties("/content/we-retail/ca/en/experience", conditionMap) -// .forDescendantResourcesOfWithProperties("/content/we-retail/ca/en", conditionMap) -// print filter results in log file - .printFoundResources() +aecu +// test filter methods + .forResources((String[])["/content/we-retail/ca/en/jcr:content","/invalid/path", "/content/we-retail/ca/en/experience/jcr:content"]) + .forChildResourcesOf("/content/we-retail/ca/en/women") + .forDescendantResourcesOf("/content/we-retail/ca/en/men") + .forChildResourcesOfWithProperties("/content/we-retail/ca/en/products", conditionMapPage) + .forDescendantResourcesOfWithProperties("/content/we-retail/ca/en/equipment", conditionMapHero) + .forDescendantResourcesOfWithProperties("/content/we-retail/ca/en/women", conditionMapHero) // test editor methods -// .setProperty("newProperty", "added by aecu") -// .renameProperty("newProperty", "delete_me_later") + .doSetProperty("newProperty", "added by aecu") + .doRenameProperty("newProperty", "delete_me_later") // .removeProperty("delete_me_later") -// .remove() \ No newline at end of file + .apply() \ No newline at end of file diff --git a/pom.xml b/pom.xml index 547f9c7b..d935214d 100644 --- a/pom.xml +++ b/pom.xml @@ -462,6 +462,7 @@ <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.1</version> + <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> @@ -487,6 +488,12 @@ <version>1.4</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-library</artifactId> + <version>1.1</version> + <scope>test</scope> + </dependency> </dependencies> </dependencyManagement> From c6889ef744152e64c50943bd1484389afcf972bb Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 11:51:50 +0200 Subject: [PATCH 064/122] AECU-Binding-sample:amsll pom fix + added StringBuffer for printing to Groovy Console Output. --- core/pom.xml | 4 ++++ .../groovy/console/bindings/SimpleContentUpdate.java | 5 +++-- .../bindings/traversers/ForChildResourcesOf.java | 4 ++-- .../bindings/traversers/ForDescendantResourcesOf.java | 10 +++++----- .../console/bindings/traversers/ForResources.java | 4 ++-- .../console/bindings/traversers/TraversData.java | 2 +- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index ac629207..07061f80 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -101,5 +101,9 @@ <groupId>junit-addons</groupId> <artifactId>junit-addons</artifactId> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> </dependencies> </project> diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 3389d9dc..f51934ea 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -97,12 +97,13 @@ public SimpleContentUpdate doRenameProperty(String oldName, String newName) { } public String apply() throws PersistenceException { + StringBuffer stringBuffer = new StringBuffer("SimpleContentUpdate.apply()\n"); for (Map.Entry<TraversData, FilterBy> traversWithFilter : traversalsWithFilter.entrySet()) { for (Action action : actions) { - traversWithFilter.getKey().traverse(resourceResolver, traversWithFilter.getValue(), action); + traversWithFilter.getKey().traverse(resourceResolver, traversWithFilter.getValue(), action, stringBuffer); } } - return "Testing Groovy Console Output :)! And this is how it works \\^^/"; + return stringBuffer.toString(); } } \ No newline at end of file diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java index 20782fbc..317e96f0 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -34,7 +34,7 @@ public ForChildResourcesOf(String path) { @Override - public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action) throws PersistenceException { + public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { if (path != null) { Resource parentResource = resourceResolver.getResource(path); if (parentResource != null) { @@ -43,7 +43,7 @@ public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action Resource resource = resourceIterator.next(); if (filter == null || filter.filter(resource)) { if (action != null) { - action.doAction(resource); + stringBuffer.append(action.doAction(resource) + "\n"); } } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java index 6fb1dda7..b5ac2583 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -34,26 +34,26 @@ public ForDescendantResourcesOf(String path) { @Override - public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action) throws PersistenceException { + public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { if (path != null) { Resource parentResource = resourceResolver.getResource(path); if (parentResource != null) { - traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action); + traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action, stringBuffer); } } } - private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, Resource resource, FilterBy filter, Action action) throws PersistenceException { + private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, Resource resource, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { if (resource != null && resource.hasChildren()) { Iterator<Resource> childResources = resource.listChildren(); while (childResources.hasNext()) { Resource child = childResources.next(); if (filter == null || filter.filter(child)) { if (action != null) { - action.doAction(child); + stringBuffer.append(action.doAction(child) + "\n"); } } - traverseChildResourcesRecursive(resourceResolver, child, filter, action); + traverseChildResourcesRecursive(resourceResolver, child, filter, action, stringBuffer); } resourceResolver.commit(); // TOD: maybe commit will be called to often this way: TODO: think about it for later!! } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java index 66b2379c..0677f1f2 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -31,14 +31,14 @@ public ForResources(String[] paths) { } @Override - public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action) throws PersistenceException { + public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { if (paths != null && paths.length > 0) { for (String path : paths) { if (path != null) { Resource resource = resourceResolver.getResource(path); if (filter == null || filter.filter(resource)) { if (action != null) { - action.doAction(resource); + stringBuffer.append(action.doAction(resource) + "\n"); } } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java index 74c021b3..614b5a59 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -23,6 +23,6 @@ public interface TraversData { - void traverse(ResourceResolver resourceResolve, FilterBy filter, Action action) throws PersistenceException; + void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException; } From c73cba5bdb9e62329c08610fb57211f776fa9962 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 11:53:35 +0200 Subject: [PATCH 065/122] AECU-Binding-sample: Groovy Console Output reads also from StringBuffer --- .../core/groovy/console/bindings/SimpleContentUpdate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index f51934ea..432e2161 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -96,14 +96,14 @@ public SimpleContentUpdate doRenameProperty(String oldName, String newName) { return this; } - public String apply() throws PersistenceException { + public StringBuffer apply() throws PersistenceException { StringBuffer stringBuffer = new StringBuffer("SimpleContentUpdate.apply()\n"); for (Map.Entry<TraversData, FilterBy> traversWithFilter : traversalsWithFilter.entrySet()) { for (Action action : actions) { traversWithFilter.getKey().traverse(resourceResolver, traversWithFilter.getValue(), action, stringBuffer); } } - return stringBuffer.toString(); + return stringBuffer; } } \ No newline at end of file From 914eb7a9ec0378fe0014c03805ed5c26e5c95fac Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 11:56:10 +0200 Subject: [PATCH 066/122] AECU-Binding-sample: added class author comments --- .../aecu/core/groovy/console/bindings/actions/Action.java | 3 +++ .../aecu/core/groovy/console/bindings/actions/PrintPath.java | 3 +++ .../core/groovy/console/bindings/actions/RemoveProperty.java | 3 +++ .../core/groovy/console/bindings/actions/RenameProperty.java | 3 +++ .../core/groovy/console/bindings/actions/SetProperty.java | 3 +++ .../aecu/core/groovy/console/bindings/filters/FilterBy.java | 5 +++++ .../groovy/console/bindings/filters/FilterByProperties.java | 3 +++ .../console/bindings/traversers/ForChildResourcesOf.java | 3 +++ .../bindings/traversers/ForDescendantResourcesOf.java | 3 +++ .../groovy/console/bindings/traversers/ForResources.java | 3 +++ .../core/groovy/console/bindings/traversers/TraversData.java | 3 +++ 11 files changed, 35 insertions(+) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java index 551139b7..c61e4372 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java @@ -19,6 +19,9 @@ import com.drew.lang.annotations.NotNull; import org.apache.sling.api.resource.Resource; +/** + * @author Roxana Muresan + */ public interface Action { String doAction(@NotNull Resource resource); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java index 77494c55..ca5ecdf3 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java @@ -18,6 +18,9 @@ import org.apache.sling.api.resource.Resource; +/** + * @author Roxana Muresan + */ public class PrintPath implements Action { @Override diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java index 0b09b911..ee7e31e3 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java @@ -20,6 +20,9 @@ import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +/** + * @author Roxana Muresan + */ public class RemoveProperty implements Action { private String name; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java index 72ce4c77..6f3d287b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java @@ -20,6 +20,9 @@ import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +/** + * @author Roxana Muresan + */ public class RenameProperty implements Action { private String oldName; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java index e955cc68..575a24c6 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java @@ -20,6 +20,9 @@ import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +/** + * @author Roxana Muresan + */ public class SetProperty implements Action { private String name; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java index 4547f8a2..403afbf6 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java @@ -18,6 +18,11 @@ import org.apache.sling.api.resource.Resource; +/** + * @author Roxana Muresan + */ public interface FilterBy { + boolean filter(Resource resource); + } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java index 70d5f163..f5ae75c3 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java @@ -23,6 +23,9 @@ import java.util.HashMap; import java.util.Map; +/** + * @author Roxana Muresan + */ public class FilterByProperties implements FilterBy { private Map<String, String> conditionProperties = new HashMap<>(); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java index 317e96f0..3aaf7320 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -24,6 +24,9 @@ import java.util.Iterator; +/** + * @author Roxana Muresan + */ public class ForChildResourcesOf implements TraversData { private String path; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java index b5ac2583..54afeb5c 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -24,6 +24,9 @@ import java.util.Iterator; +/** + * @author Roxana Muresan + */ public class ForDescendantResourcesOf implements TraversData { private String path; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java index 0677f1f2..1062527b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -22,6 +22,9 @@ import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +/** + * @author Roxana Muresan + */ public class ForResources implements TraversData { private String[] paths; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java index 614b5a59..ab6921b1 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -21,6 +21,9 @@ import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.ResourceResolver; +/** + * @author Roxana Muresan + */ public interface TraversData { void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException; From 1bb31d418eeb7f804930941baed592166d4b0332 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 12:17:59 +0200 Subject: [PATCH 067/122] AECU-Binding-sample: added @Nonnull annptations --- core/pom.xml | 4 +++ .../console/bindings/SimpleContentUpdate.java | 17 +++++++------ .../console/bindings/actions/Action.java | 5 ++-- .../console/bindings/actions/PrintPath.java | 4 ++- .../bindings/actions/RemoveProperty.java | 7 +++--- .../bindings/actions/RenameProperty.java | 7 +++--- .../console/bindings/actions/SetProperty.java | 7 +++--- .../console/bindings/filters/FilterBy.java | 4 ++- .../bindings/filters/FilterByProperties.java | 22 ++++++++-------- .../traversers/ForChildResourcesOf.java | 25 ++++++++----------- .../traversers/ForDescendantResourcesOf.java | 18 ++++++------- .../bindings/traversers/ForResources.java | 22 ++++++++-------- .../bindings/traversers/TraversData.java | 4 ++- pom.xml | 5 ++++ 14 files changed, 81 insertions(+), 70 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 07061f80..0ae50f4f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -105,5 +105,9 @@ <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + </dependency> </dependencies> </project> diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 432e2161..39093861 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -31,6 +31,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -55,43 +56,43 @@ public SimpleContentUpdate(ResourceResolver resourceResolver) { } /** content filter methods **/ - public SimpleContentUpdate forResources(String[] paths) { + public SimpleContentUpdate forResources(@Nonnull String[] paths) { traversalsWithFilter.put(new ForResources(paths), null); return this; } - public SimpleContentUpdate forChildResourcesOf(String path) { + public SimpleContentUpdate forChildResourcesOf(@Nonnull String path) { traversalsWithFilter.put(new ForChildResourcesOf(path), null); return this; } - public SimpleContentUpdate forChildResourcesOfWithProperties(String path, Map<String, String> conditionProperties) { + public SimpleContentUpdate forChildResourcesOfWithProperties(@Nonnull String path, @Nonnull Map<String, String> conditionProperties) { traversalsWithFilter.put(new ForChildResourcesOf(path), new FilterByProperties(conditionProperties)); return this; } - public SimpleContentUpdate forDescendantResourcesOf(String path) { + public SimpleContentUpdate forDescendantResourcesOf(@Nonnull String path) { traversalsWithFilter.put(new ForDescendantResourcesOf(path), null); return this; } - public SimpleContentUpdate forDescendantResourcesOfWithProperties(String path, Map<String, String> conditionProperties) { + public SimpleContentUpdate forDescendantResourcesOfWithProperties(@Nonnull String path, @Nonnull Map<String, String> conditionProperties) { traversalsWithFilter.put(new ForDescendantResourcesOf(path), new FilterByProperties(conditionProperties)); return this; } /** properties edit methods **/ - public SimpleContentUpdate doSetProperty(String name, String value) { + public SimpleContentUpdate doSetProperty(@Nonnull String name, String value) { actions.add(new SetProperty(name, value)); return this; } - public SimpleContentUpdate doRemoveProperty(String name) { + public SimpleContentUpdate doRemoveProperty(@Nonnull String name) { actions.add(new RemoveProperty(name)); return this; } - public SimpleContentUpdate doRenameProperty(String oldName, String newName) { + public SimpleContentUpdate doRenameProperty(@Nonnull String oldName, @Nonnull String newName) { actions.add(new RenameProperty(oldName, newName)); return this; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java index c61e4372..e9c269ba 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java @@ -16,14 +16,15 @@ */ package de.valtech.aecu.core.groovy.console.bindings.actions; -import com.drew.lang.annotations.NotNull; import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ public interface Action { - String doAction(@NotNull Resource resource); + String doAction(@Nonnull Resource resource); } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java index ca5ecdf3..484e0bc4 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java @@ -18,13 +18,15 @@ import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ public class PrintPath implements Action { @Override - public String doAction(Resource resource) { + public String doAction(@Nonnull Resource resource) { return resource.getPath(); } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java index ee7e31e3..5a1abdc1 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java @@ -16,10 +16,11 @@ */ package de.valtech.aecu.core.groovy.console.bindings.actions; -import com.drew.lang.annotations.NotNull; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ @@ -27,12 +28,12 @@ public class RemoveProperty implements Action { private String name; - public RemoveProperty(@NotNull String name) { + public RemoveProperty(@Nonnull String name) { this.name = name; } @Override - public String doAction(Resource resource) { + public String doAction(@Nonnull Resource resource) { ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); properties.remove(name); return "Removing property " + name + " for resource " + resource.getPath(); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java index 6f3d287b..2de91aa8 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java @@ -16,10 +16,11 @@ */ package de.valtech.aecu.core.groovy.console.bindings.actions; -import com.drew.lang.annotations.NotNull; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ @@ -28,13 +29,13 @@ public class RenameProperty implements Action { private String oldName; private String newName; - public RenameProperty(@NotNull String oldName, @NotNull String newName) { + public RenameProperty(@Nonnull String oldName, @Nonnull String newName) { this.oldName = oldName; this.newName = newName; } @Override - public String doAction(Resource resource) { + public String doAction(@Nonnull Resource resource) { ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); Object value = properties.remove(oldName); properties.put(newName, value); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java index 575a24c6..cbe7e3b2 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java @@ -16,10 +16,11 @@ */ package de.valtech.aecu.core.groovy.console.bindings.actions; -import com.drew.lang.annotations.NotNull; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ @@ -28,14 +29,14 @@ public class SetProperty implements Action { private String name; private Object value; - public SetProperty(@NotNull String name, Object value) { + public SetProperty(@Nonnull String name, Object value) { this.name = name; this.value = value; } @Override - public String doAction(Resource resource) { + public String doAction(@Nonnull Resource resource) { ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); properties.put(name, value); return "Setting property " + name + "=" + value + " for resource " + resource.getPath(); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java index 403afbf6..3e7e6a18 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java @@ -18,11 +18,13 @@ import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ public interface FilterBy { - boolean filter(Resource resource); + boolean filter(@Nonnull Resource resource); } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java index f5ae75c3..993724fd 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java @@ -16,10 +16,10 @@ */ package de.valtech.aecu.core.groovy.console.bindings.filters; -import com.drew.lang.annotations.NotNull; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; @@ -30,21 +30,19 @@ public class FilterByProperties implements FilterBy { private Map<String, String> conditionProperties = new HashMap<>(); - public FilterByProperties(@NotNull Map<String, String> conditionProperties) { + public FilterByProperties(@Nonnull Map<String, String> conditionProperties) { this.conditionProperties.putAll(conditionProperties); } @Override - public boolean filter(Resource resource) { - if (resource != null) { - ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); - for (String key : conditionProperties.keySet()) { - String conditionValue = conditionProperties.get(key); - String propertiesValue = properties.get(key, String.class); - - if ((conditionValue == null && propertiesValue != null) || (conditionValue != null && !conditionValue.equals(propertiesValue))) { - return false; - } + public boolean filter(@Nonnull Resource resource) { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + for (String key : conditionProperties.keySet()) { + String conditionValue = conditionProperties.get(key); + String propertiesValue = properties.get(key, String.class); + + if ((conditionValue == null && propertiesValue != null) || (conditionValue != null && !conditionValue.equals(propertiesValue))) { + return false; } } return true; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java index 3aaf7320..7c4b7149 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -22,6 +22,7 @@ import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +import javax.annotation.Nonnull; import java.util.Iterator; /** @@ -31,27 +32,23 @@ public class ForChildResourcesOf implements TraversData { private String path; - public ForChildResourcesOf(String path) { + public ForChildResourcesOf(@Nonnull String path) { this.path = path; } @Override - public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { - if (path != null) { - Resource parentResource = resourceResolver.getResource(path); - if (parentResource != null) { - Iterator<Resource> resourceIterator = resourceResolver.listChildren(parentResource); - while (resourceIterator.hasNext()) { - Resource resource = resourceIterator.next(); - if (filter == null || filter.filter(resource)) { - if (action != null) { - stringBuffer.append(action.doAction(resource) + "\n"); - } - } + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException { + Resource parentResource = resourceResolver.getResource(path); + if (parentResource != null) { + Iterator<Resource> resourceIterator = resourceResolver.listChildren(parentResource); + while (resourceIterator.hasNext()) { + Resource resource = resourceIterator.next(); + if (filter == null || filter.filter(resource)) { + stringBuffer.append(action.doAction(resource) + "\n"); } - resourceResolver.commit(); } + resourceResolver.commit(); } } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java index 54afeb5c..09f2a9e7 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -22,6 +22,7 @@ import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +import javax.annotation.Nonnull; import java.util.Iterator; /** @@ -31,18 +32,16 @@ public class ForDescendantResourcesOf implements TraversData { private String path; - public ForDescendantResourcesOf(String path) { + public ForDescendantResourcesOf(@Nonnull String path) { this.path = path; } @Override - public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { - if (path != null) { - Resource parentResource = resourceResolver.getResource(path); - if (parentResource != null) { - traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action, stringBuffer); - } + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException { + Resource parentResource = resourceResolver.getResource(path); + if (parentResource != null) { + traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action, stringBuffer); } } @@ -52,13 +51,12 @@ private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, while (childResources.hasNext()) { Resource child = childResources.next(); if (filter == null || filter.filter(child)) { - if (action != null) { - stringBuffer.append(action.doAction(child) + "\n"); - } + stringBuffer.append(action.doAction(child) + "\n"); } traverseChildResourcesRecursive(resourceResolver, child, filter, action, stringBuffer); } resourceResolver.commit(); // TOD: maybe commit will be called to often this way: TODO: think about it for later!! } } + } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java index 1062527b..fda86d50 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -22,6 +22,8 @@ import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ @@ -29,24 +31,20 @@ public class ForResources implements TraversData { private String[] paths; - public ForResources(String[] paths) { + public ForResources(@Nonnull String[] paths) { this.paths = paths; } @Override - public void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { - if (paths != null && paths.length > 0) { - for (String path : paths) { - if (path != null) { - Resource resource = resourceResolver.getResource(path); - if (filter == null || filter.filter(resource)) { - if (action != null) { - stringBuffer.append(action.doAction(resource) + "\n"); - } - } + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException { + for (String path : paths) { + if (path != null) { + Resource resource = resourceResolver.getResource(path); + if (filter == null || filter.filter(resource)) { + stringBuffer.append(action.doAction(resource) + "\n"); } } - resourceResolver.commit(); } + resourceResolver.commit(); } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java index ab6921b1..9212c6a6 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -21,11 +21,13 @@ import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.ResourceResolver; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ public interface TraversData { - void traverse(ResourceResolver resourceResolver, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException; + void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException; } diff --git a/pom.xml b/pom.xml index 11dff3aa..59b76b64 100644 --- a/pom.xml +++ b/pom.xml @@ -488,6 +488,11 @@ <artifactId>gson</artifactId> <version>2.3</version> </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <version>2.0.1</version> + </dependency> </dependencies> </dependencyManagement> From 24ee2ea782711baed2a18d7d3c7030b61a3ce7bf Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 13:51:20 +0200 Subject: [PATCH 068/122] AECU-Binding-sample: added cases for more complex filters --- .../console/bindings/filters/ANDFilter.java | 45 +++++++++++++++++++ .../console/bindings/filters/NOTFilter.java | 39 ++++++++++++++++ .../console/bindings/filters/ORFilter.java | 44 ++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java new file mode 100644 index 00000000..bc235dae --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.filters; + +import org.apache.sling.api.resource.Resource; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * @author Roxana Muresan + */ +public class ANDFilter implements FilterBy { + + private List<FilterBy> filters; + + + public ANDFilter(@Nonnull List<FilterBy> filters) { + this.filters = filters; + } + + @Override + public boolean filter(@Nonnull Resource resource) { + boolean foundFalse = filters + .parallelStream() + .filter(f -> f.filter(resource) == false) + .findAny().isPresent(); + return !foundFalse; + + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java new file mode 100644 index 00000000..b0cff175 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.filters; + +import org.apache.sling.api.resource.Resource; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class NOTFilter implements FilterBy { + + private FilterBy filter; + + + public NOTFilter(@Nonnull FilterBy filter) { + this.filter = filter; + } + + @Override + public boolean filter(@Nonnull Resource resource) { + return !filter.filter(resource); + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java new file mode 100644 index 00000000..76623987 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.filters; + +import org.apache.sling.api.resource.Resource; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * @author Roxana Muresan + */ +public class ORFilter implements FilterBy { + + private List<FilterBy> filters; + + + public ORFilter(List<FilterBy> filters) { + this.filters = filters; + } + + @Override + public boolean filter(@Nonnull Resource resource) { + boolean foundTrue = filters + .parallelStream() + .filter(f -> f.filter(resource)) + .findAny().isPresent(); + return foundTrue; + } +} From 1d22200bf9fb7785653acb34e55f025919b8bb7d Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 16:25:13 +0200 Subject: [PATCH 069/122] AECU-Binding-sample: moved the actual migration functionality outside of aecu binding; exposed the filter package to the groovy console. --- .../groovy/console/bindings/Migration.java | 100 ++++++++++++++++++ .../console/bindings/SimpleContentUpdate.java | 76 +------------ .../AecuStarImportExtensionProvider.java | 18 ++++ 3 files changed, 120 insertions(+), 74 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java new file mode 100644 index 00000000..b0e52fac --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java @@ -0,0 +1,100 @@ +package de.valtech.aecu.core.groovy.console.bindings; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.actions.RemoveProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.RenameProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.SetProperty; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByProperties; +import de.valtech.aecu.core.groovy.console.bindings.traversers.ForChildResourcesOf; +import de.valtech.aecu.core.groovy.console.bindings.traversers.ForDescendantResourcesOf; +import de.valtech.aecu.core.groovy.console.bindings.traversers.ForResources; +import de.valtech.aecu.core.groovy.console.bindings.traversers.TraversData; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.ResourceResolver; +import org.scribe.utils.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class Migration { + + private static Logger LOG = LoggerFactory.getLogger(Migration.class); + + private ResourceResolver resourceResolver = null; + + private List<TraversData> traversals = new ArrayList<>(); + private FilterBy filter = null; + private List<Action> actions = new ArrayList<>(); + + + public Migration(@Nonnull ResourceResolver resourceResolver) { + this.resourceResolver = resourceResolver; + } + + /** content filter methods **/ + public Migration forResources(@Nonnull String[] paths) { + LOG.debug("forResources: {}", paths.toString()); + traversals.add(new ForResources(paths)); + return this; + } + + public Migration forChildResourcesOf(@Nonnull String path) { + LOG.debug("forChildResourcesOf: {}", path); + traversals.add(new ForChildResourcesOf(path)); + return this; + } + + public Migration forDescendantResourcesOf(@Nonnull String path) { + LOG.debug("forDescendantResourcesOf: {}", path); + traversals.add(new ForDescendantResourcesOf(path)); + return this; + } + + /** filters **/ + public Migration filterByProperties(@Nonnull Map<String, String> conditionProperties) { + LOG.debug("filterByProperties: {}", MapUtils.toString(conditionProperties)); + filter = new FilterByProperties(conditionProperties); + return this; + } + + public Migration filterWith(@Nonnull FilterBy filter) { + LOG.debug("filterWith: {}", filter); + this.filter = filter; + return this; + } + + /** properties edit methods **/ + public Migration doSetProperty(@Nonnull String name, String value) { + LOG.debug("doSetProperty: {} = {}", name, value); + actions.add(new SetProperty(name, value)); + return this; + } + + public Migration doRemoveProperty(@Nonnull String name) { + LOG.debug("doRemoveProperty: {}", name); + actions.add(new RemoveProperty(name)); + return this; + } + + public Migration doRenameProperty(@Nonnull String oldName, @Nonnull String newName) { + LOG.debug("doRenameProperty: {} to {}", oldName, newName); + actions.add(new RenameProperty(oldName, newName)); + return this; + } + + public StringBuffer apply() throws PersistenceException { + LOG.debug("apply migration"); + StringBuffer stringBuffer = new StringBuffer("Running migration...\n"); + for (TraversData traversal : traversals) { + for (Action action : actions) { + traversal.traverse(resourceResolver, filter, action, stringBuffer); + } + } + return stringBuffer; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 39093861..759c033a 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -16,26 +16,7 @@ */ package de.valtech.aecu.core.groovy.console.bindings; -import de.valtech.aecu.core.groovy.console.bindings.actions.Action; -import de.valtech.aecu.core.groovy.console.bindings.actions.RemoveProperty; -import de.valtech.aecu.core.groovy.console.bindings.actions.RenameProperty; -import de.valtech.aecu.core.groovy.console.bindings.actions.SetProperty; -import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; -import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByProperties; -import de.valtech.aecu.core.groovy.console.bindings.traversers.ForChildResourcesOf; -import de.valtech.aecu.core.groovy.console.bindings.traversers.ForDescendantResourcesOf; -import de.valtech.aecu.core.groovy.console.bindings.traversers.ForResources; -import de.valtech.aecu.core.groovy.console.bindings.traversers.TraversData; -import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.ResourceResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; /** * Groovy Console Bindings: Simple Content Update @@ -43,68 +24,15 @@ */ public class SimpleContentUpdate { - private static final Logger LOG = LoggerFactory.getLogger(SimpleContentUpdate.class); - private ResourceResolver resourceResolver;// TODO system user resolver!! - private Map<TraversData, FilterBy> traversalsWithFilter = new HashMap<>(); - private List<Action> actions = new ArrayList<>(); - public SimpleContentUpdate(ResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } - /** content filter methods **/ - public SimpleContentUpdate forResources(@Nonnull String[] paths) { - traversalsWithFilter.put(new ForResources(paths), null); - return this; - } - - public SimpleContentUpdate forChildResourcesOf(@Nonnull String path) { - traversalsWithFilter.put(new ForChildResourcesOf(path), null); - return this; - } - - public SimpleContentUpdate forChildResourcesOfWithProperties(@Nonnull String path, @Nonnull Map<String, String> conditionProperties) { - traversalsWithFilter.put(new ForChildResourcesOf(path), new FilterByProperties(conditionProperties)); - return this; - } - - public SimpleContentUpdate forDescendantResourcesOf(@Nonnull String path) { - traversalsWithFilter.put(new ForDescendantResourcesOf(path), null); - return this; - } - - public SimpleContentUpdate forDescendantResourcesOfWithProperties(@Nonnull String path, @Nonnull Map<String, String> conditionProperties) { - traversalsWithFilter.put(new ForDescendantResourcesOf(path), new FilterByProperties(conditionProperties)); - return this; - } - - /** properties edit methods **/ - public SimpleContentUpdate doSetProperty(@Nonnull String name, String value) { - actions.add(new SetProperty(name, value)); - return this; - } - - public SimpleContentUpdate doRemoveProperty(@Nonnull String name) { - actions.add(new RemoveProperty(name)); - return this; - } - - public SimpleContentUpdate doRenameProperty(@Nonnull String oldName, @Nonnull String newName) { - actions.add(new RenameProperty(oldName, newName)); - return this; - } - - public StringBuffer apply() throws PersistenceException { - StringBuffer stringBuffer = new StringBuffer("SimpleContentUpdate.apply()\n"); - for (Map.Entry<TraversData, FilterBy> traversWithFilter : traversalsWithFilter.entrySet()) { - for (Action action : actions) { - traversWithFilter.getKey().traverse(resourceResolver, traversWithFilter.getValue(), action, stringBuffer); - } - } - return stringBuffer; + public Migration getNewMigration() { + return new Migration(resourceResolver); } } \ No newline at end of file diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java new file mode 100644 index 00000000..c5990d53 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java @@ -0,0 +1,18 @@ +package de.valtech.aecu.core.groovy.console.bindings.provider; + +import com.icfolson.aem.groovy.console.api.StarImportExtensionProvider; +import com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants; +import org.osgi.service.component.annotations.Component; + +import java.util.Set; + +@Component(immediate = true) +public class AecuStarImportExtensionProvider implements StarImportExtensionProvider { + + @Override + public Set<String> getStarImports() { + Set<String> imports = GroovyConsoleConstants.DEFAULT_STAR_IMPORTS; + imports.add("de.valtech.aecu.core.groovy.console.bindings.filters"); + return imports; + } +} From 7148069a9023dc074f7c18333300b2b8c2a21faf Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 17:58:54 +0200 Subject: [PATCH 070/122] AECU-Binding-sample: added system user for content migration with write permissions on /content. --- .../AecuBindingExtensionProvider.java | 15 +++++++++++++-- .../ServiceResourceResolverService.java | 19 ++++++++++++++++--- .../main/content/META-INF/vault/filter.xml | 1 + ...nded-valtechAecuContentMigratorUser.config | 1 + .../content/jcr_root/content/_rep_policy.xml | 8 ++++++++ .../aecu/aecu-content-migrator/.content.xml | 6 ++++++ 6 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuContentMigratorUser.config create mode 100644 ui.apps/src/main/content/jcr_root/content/_rep_policy.xml create mode 100644 ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java index e7b7c9e2..66efe13e 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java @@ -18,10 +18,14 @@ import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; import de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate; +import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; import groovy.lang.Binding; import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.LoginException; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Provides additional AECU Bindings for the Groovy Console @@ -30,15 +34,22 @@ @Component(immediate = true) public class AecuBindingExtensionProvider implements BindingExtensionProvider { + private static final Logger LOG = LoggerFactory.getLogger(AecuBindingExtensionProvider.class); + @Reference private BindingExtensionProvider defaultBindingExtensionProvider; + @Reference + private ServiceResourceResolverService resourceResolverService; @Override public Binding getBinding(SlingHttpServletRequest request) { Binding binding = defaultBindingExtensionProvider.getBinding(request); - binding.setVariable("aecu", new SimpleContentUpdate(request.getResourceResolver())); - + try { + binding.setVariable("aecu", new SimpleContentUpdate(resourceResolverService.getContentMigratorResourceResolver())); + } catch (LoginException e) { + LOG.error("Failed to get resource resolver for aecu-content-migrator, make sure you all the configurations needed for this system user are deployed."); + } return binding; } diff --git a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java index c3107c40..55b4dde9 100644 --- a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java +++ b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java @@ -16,15 +16,15 @@ */ package de.valtech.aecu.core.serviceuser; -import java.util.HashMap; -import java.util.Map; - import org.apache.sling.api.resource.LoginException; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ResourceResolverFactory; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import java.util.HashMap; +import java.util.Map; + /** * Provides the service resource resolver. * @@ -34,6 +34,7 @@ public class ServiceResourceResolverService { private static final String SUBSERVICE_AECU = "aecu"; + private static final String SUBSERVICE_AECU_CONTENT_MIGRATION = "aecu-content-migrator"; @Reference ResourceResolverFactory resolverFactory; @@ -50,4 +51,16 @@ public ResourceResolver getServiceResourceResolver() throws LoginException { return resolverFactory.getServiceResourceResolver(authenticationInfo); } + /** + * Returns a resource resolver of the AECU content migrator user. + * + * @return service resource resolver + * @throws LoginException error opening resource resolver + */ + public ResourceResolver getContentMigratorResourceResolver() throws LoginException { + final Map<String, Object> authenticationInfo = new HashMap<>(); + authenticationInfo.put(ResourceResolverFactory.SUBSERVICE, SUBSERVICE_AECU_CONTENT_MIGRATION); + return resolverFactory.getServiceResourceResolver(authenticationInfo); + } + } diff --git a/ui.apps/src/main/content/META-INF/vault/filter.xml b/ui.apps/src/main/content/META-INF/vault/filter.xml index 5128623f..ac60f294 100644 --- a/ui.apps/src/main/content/META-INF/vault/filter.xml +++ b/ui.apps/src/main/content/META-INF/vault/filter.xml @@ -9,4 +9,5 @@ <filter root="/etc/groovyconsole/scripts/aecu" mode="merge"/> <filter root="/rep:policy" mode="merge"/> <filter root="/var/aecu/rep:policy" mode="merge"/> + <filter root="/content/rep:policy" mode="merge"/> </workspaceFilter> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuContentMigratorUser.config b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuContentMigratorUser.config new file mode 100644 index 00000000..91811d89 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-valtechAecuContentMigratorUser.config @@ -0,0 +1 @@ +user.mapping=["de.valtech.aecu.core:aecu-content-migrator\=aecu-content-migrator"] \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/content/_rep_policy.xml b/ui.apps/src/main/content/jcr_root/content/_rep_policy.xml new file mode 100644 index 00000000..5a61f173 --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/content/_rep_policy.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" + jcr:primaryType="rep:ACL"> + <allow + jcr:primaryType="rep:GrantACE" + rep:principalName="aecu-content-migrator" + rep:privileges="{Name}[jcr:all]"/> +</jcr:root> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml new file mode 100644 index 00000000..4d165d6f --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" + jcr:primaryType="rep:SystemUser" + jcr:uuid="0597301b-4690-30ea-8cba-217f5a66faf6" + rep:authorizableId="aecu-content-migrator" + rep:principalName="aecu-content-migrator"/> From f2e2cfce0e5eb9014eca3b320b351dfb3aa3d444 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 22 Jun 2018 18:00:43 +0200 Subject: [PATCH 071/122] AECU-Binding-sample: updated groovy test script. --- .../tests_for_simpleContentUpdates.groovy | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index 6fa015df..43c9068a 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -1,24 +1,47 @@ -println "simpleContentUpdate is $aecu" +def conditionMap_Hero1 = [:] +conditionMap_Hero1['sling:resourceType'] = "weretail/components/content/heroimage" +def conditionMap_Hero2 = [:] +conditionMap_Hero2['fileReference'] = "/content/dam/we-retail/en/activities/running/fitness-woman.jpg" -def conditionMapHero = [:] -conditionMapHero['sling:resourceType'] = "weretail/components/content/heroimage" -conditionMapHero['fileReference'] = "/content/dam/we-retail/en/activities/running/fitness-woman.jpg" +def conditionMap_Page = [:] +conditionMap_Page['jcr:primaryType'] = "cq:PageContent" -def conditionMapPage = [:] -conditionMapPage['jcr:primaryType'] = "cq:PageContent" +def return1 = aecu.getNewMigration() +// traversers + .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" + .forChildResourcesOf("/content/we-retail/ca/en/men") + .forDescendantResourcesOf("/content/we-retail/ca/en/women") +// filters + .filterByProperties(conditionMap_Page) +// actions + .doSetProperty("newProperty", "aecu test with conditionMap_Page") + .doRenameProperty("newProperty", "delete_me_later") +// .removeProperty("delete_me_later") + .apply() +println "$return1" -aecu -// test filter methods - .forResources((String[])["/content/we-retail/ca/en/jcr:content","/invalid/path", "/content/we-retail/ca/en/experience/jcr:content"]) - .forChildResourcesOf("/content/we-retail/ca/en/women") - .forDescendantResourcesOf("/content/we-retail/ca/en/men") - .forChildResourcesOfWithProperties("/content/we-retail/ca/en/products", conditionMapPage) - .forDescendantResourcesOfWithProperties("/content/we-retail/ca/en/equipment", conditionMapHero) - .forDescendantResourcesOfWithProperties("/content/we-retail/ca/en/women", conditionMapHero) -// test editor methods - .doSetProperty("newProperty", "added by aecu") +def complexFilter = new ORFilter( + [ new FilterByProperties(conditionMap_Page), + new ANDFilter( [ + new FilterByProperties(conditionMap_Hero1), + new FilterByProperties(conditionMap_Hero2) + ] ) + ]) + +def return2 = aecu.getNewMigration() +// traversers + .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" + .forChildResourcesOf("/content/we-retail/ca/en/men") + .forDescendantResourcesOf("/content/we-retail/ca/en/women") +// filters + .filterWith(complexFilter) +// actions + .doSetProperty("newProperty", "aecu test with conditionMap_Hero") .doRenameProperty("newProperty", "delete_me_later") // .removeProperty("delete_me_later") - .apply() \ No newline at end of file + .apply() +println "$return2" + +return return1 + return2 \ No newline at end of file From 2f608d97a68eca11d3311b89822f579cc42e149d Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 3 Jul 2018 12:15:02 +0200 Subject: [PATCH 072/122] updated docs --- Readme.md | 15 +++++++++++++-- docs/images/run.png | Bin 0 -> 82852 bytes 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 docs/images/run.png diff --git a/Readme.md b/Readme.md index 211d48df..1c2192a2 100644 --- a/Readme.md +++ b/Readme.md @@ -46,9 +46,20 @@ TODO <a name="execution"></a> -# Execution of Migration Scripts +# Manual Execution of Migration Scripts -TODO +Manual script execution is useful in case you want to manually rerun a script (e.g. because it failed before). You can find the execute feature in AECU's tools menu. + +<img src="docs/images/tools.png"> + +Execution is done in two simple steps: + +1. Select the base path and run the search. This will show a list of runnable scripts. +2. Run all scripts in batch or just single ones. If you run all you can change the order before (drag and drop with marker at the right). + +Once execution is done you will see if the script(s) succeeded. Click on the history link to see the details. + +<img src="docs/images/run.png"> <a name="history"></a> diff --git a/docs/images/run.png b/docs/images/run.png new file mode 100644 index 0000000000000000000000000000000000000000..e83a0002eac2e95e0d40b7570777c9cfaeba141a GIT binary patch literal 82852 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 literal 0 HcmV?d00001 From bfd9ca4054e360b8cd5e3a0e4818911951ed1e65 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Tue, 3 Jul 2018 13:47:10 +0200 Subject: [PATCH 073/122] docs --- Readme.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 1c2192a2..22160bcf 100644 --- a/Readme.md +++ b/Readme.md @@ -16,6 +16,8 @@ Table of contents 1. [Requirements](#requirements) 2. [Installation](#installation) 3. [Execution of Migration Scripts](#execution) + 1. [Install Hook](#installHook) + 2. [Manual Execution](#manualExecution) 4. [History of Past Runs](#history) 5. [Extension to Groovy Console](#groovy) 6. [JMX Interface](#jmx) @@ -46,7 +48,36 @@ TODO <a name="execution"></a> -# Manual Execution of Migration Scripts +# Execution of Migration Scripts + +<a name="installHook"></a> + +## Install Hook + +This is the preferred method to execute your scripts. It allows to run them without any user interaction. Just package them with a content package and do a regular deployment. + +You can add the install hook by adding de.valtech.aecu.core.installhook.AecuInstallHook as a hook to your package properties. The AECU package and Groovy Console need to be installed beforehand. + +```xml +<plugin> + <groupId>com.day.jcr.vault</groupId> + <artifactId>content-package-maven-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <filterSource>src/main/content/META-INF/vault/filter.xml</filterSource> + <verbose>true</verbose> + <failOnError>true</failOnError> + <group>Valtech</group> + <properties> + <installhook.aecu.class>de.valtech.aecu.core.installhook.AecuInstallHook</installhook.aecu.class> + </properties> + </configuration> +</plugin> +``` + +<a name="manualExecution"></a> + +## Manual Execution Manual script execution is useful in case you want to manually rerun a script (e.g. because it failed before). You can find the execute feature in AECU's tools menu. From 728f0294a604ce137eb291b6e2f3f01f8d47e337 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Wed, 4 Jul 2018 11:31:14 +0200 Subject: [PATCH 074/122] aem-easy-content-upgrade: sample groovy script update --- .../tests_for_simpleContentUpdates.groovy | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index 43c9068a..605a49fa 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -7,7 +7,7 @@ def conditionMap_Page = [:] conditionMap_Page['jcr:primaryType'] = "cq:PageContent" -def return1 = aecu.getNewMigration() +println aecu.getNewMigration()// TODO contentUpgradeBuilder(). // traversers .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") @@ -19,10 +19,11 @@ def return1 = aecu.getNewMigration() .doRenameProperty("newProperty", "delete_me_later") // .removeProperty("delete_me_later") .apply() -println "$return1" -def complexFilter = new ORFilter( + + +def complexFilter = new ORFilter( [ new FilterByProperties(conditionMap_Page), new ANDFilter( [ new FilterByProperties(conditionMap_Hero1), @@ -30,7 +31,7 @@ def complexFilter = new ORFilter( ] ) ]) -def return2 = aecu.getNewMigration() +println aecu.getNewMigration() // traversers .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") @@ -41,7 +42,4 @@ def return2 = aecu.getNewMigration() .doSetProperty("newProperty", "aecu test with conditionMap_Hero") .doRenameProperty("newProperty", "delete_me_later") // .removeProperty("delete_me_later") - .apply() -println "$return2" - -return return1 + return2 \ No newline at end of file + .apply() \ No newline at end of file From 031d74a0a39511e0c67cd3baecabb21cf5eb7aab Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 4 Jul 2018 15:45:13 +0200 Subject: [PATCH 075/122] added icons --- .../aecu/core/servlets/ExecutionServlet.java | 17 ++++++------ .../clientlibs/aecu.editor/js/constants.js | 14 +++++----- .../clientlibs/aecu.editor/js/executor.js | 27 ++++++++++++------- .../aecu/tools/execute/dataitem/dataitem.html | 5 +++- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java index 42f5d7b4..e8ae684e 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java @@ -23,11 +23,6 @@ import javax.servlet.Servlet; import javax.servlet.ServletException; -import de.valtech.aecu.core.history.HistoryUtil; -import de.valtech.aecu.service.AecuException; -import de.valtech.aecu.service.AecuService; -import de.valtech.aecu.service.ExecutionResult; -import de.valtech.aecu.service.HistoryEntry; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.ResourceResolver; @@ -38,6 +33,12 @@ import com.google.gson.JsonObject; +import de.valtech.aecu.core.history.HistoryUtil; +import de.valtech.aecu.service.AecuException; +import de.valtech.aecu.service.AecuService; +import de.valtech.aecu.service.ExecutionResult; +import de.valtech.aecu.service.HistoryEntry; + /** * @author Bryan Chavez */ @@ -68,7 +69,7 @@ protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse r String historyEntryAction = request.getParameter("historyEntryAction"); String aecuScriptPath = request.getParameter("aecuScriptPath"); if(!this.validateParameter(aecuScriptPath) || !this.validateParameter(historyEntryAction)){ - this.writeResult(response, ERROR_MESSAGE_MANDATORY); + writeResult(response, ERROR_MESSAGE_MANDATORY); return; } @@ -77,7 +78,7 @@ protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse r ExecutionResult executionResult = aecuService.execute(aecuScriptPath); aecuService.storeExecutionInHistory(historyEntry, executionResult); this.finishHistoryEntry(historyEntry,historyEntryAction); - response.getWriter().write(this.prepareJson(executionResult.isSuccess(),historyEntry.getRepositoryPath())); + writeResult(response, this.prepareJson(executionResult.isSuccess(),historyEntry.getRepositoryPath())); }catch (AecuException e){ this.sendInternalServerError(response); @@ -96,7 +97,7 @@ protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHtt //Used for "use" and "close" String historyEntryPath = request.getParameter("historyEntryPath"); if(!this.validateParameter(historyEntryPath)){ - this.writeResult(response, ERROR_MESSAGE_MANDATORY); + writeResult(response, ERROR_MESSAGE_MANDATORY); return null; } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js index 2b7784f3..d1205299 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js @@ -18,17 +18,17 @@ AECU.Constants = {}; AECU.Constants.Executor = { - servletPath : "/bin/public/valtech/aecu/execute?aecuScriptPath={0}&historyEntryAction={1}&historyEntryPath={2}", + servletPath : "/bin/public/valtech/aecu/execute.json?aecuScriptPath={0}&historyEntryAction={1}&historyEntryPath={2}", historyPath : "/apps/valtech/aecu/tools/history/details.html?entry={0}&aecuScriptPath={1}" } AECU.Constants.Executor.Status = { - ready : "Ready", - inProgress : "In progress", - fail : "Failed", - pending : "Pending...", - executed: "Successful", - internalError: "Internal Server Error" + ready : {icon: "helpCircle", className: ""}, + inProgress : {icon: "playCircle", className: "icon-color-inprogress"}, + fail : {icon: "closeCircle", className: "icon-color-fail"}, + pending : {icon: "pending", className: "icon-color-inprogress"}, + executed: {icon: "checkCircle", className: "icon-color-ok"}, + internalError: {icon: "sentimentNegative", className: "icon-color-fail"} } AECU.Constants.Executor.HistoryEntryActions = { diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js index f8be825a..d58ed8a9 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js @@ -54,21 +54,20 @@ AECU.Executor.execute = function(row,historyEntryAction,historyEntryPath) { this.doGET({ url : AECU.Constants.Executor.servletPath.format(row.dataset.aecuExecuteScript,historyEntryAction,historyEntryPath), beforeSend: function(){ - AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.inProgress); + AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.inProgress); AECU.Executor.disableButton(row); }, - success: function( data ) { - var json = JSON.parse(data); + success: function( json ) { AECU.Executor.historyEntryPath = json.historyEntryPath; AECU.Executor.addHistoryLink(row,json.historyEntryPath); if(json.success){ - AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.executed); + AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.executed); }else{ - AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.fail); + AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.fail); } }, error: function (jqXHR, textStatus, errorThrown) { - AECU.Executor.changeStatus(row,AECU.Constants.Executor.Status.internalError); + AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.internalError); } }); } @@ -79,15 +78,25 @@ AECU.Executor.addHistoryLink = function(row, historyEntryPath){ historyLink.text = "Go to history"; } -AECU.Executor.changeStatus = function(row, value){ - $(row).find("[data-aecu-execute-script-status]").text(value); +AECU.Executor.changeRowStatus = function(row, value){ + AECU.Executor.changeStatus($(row).find("[data-aecu-execute-script-status]"), value); } AECU.Executor.changeAllStatus = function(value){ - $("[data-aecu-execute-script-status]").text(value); + AECU.Executor.changeStatus($("[data-aecu-execute-script-status]"), value); } +AECU.Executor.changeStatus = function(items, value){ + var icon = value.icon; + var className = value.className; + var iconTags = items.children("coral-icon"); + iconTags.each(function() { + this.set('icon', icon) + }); + iconTags.removeClass('icon-color-inprogress'); + iconTags.addClass(className); +} AECU.Executor.disableButton = function(row){ if(row != undefined){ diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html index 8c1c730e..aaa7f6ee 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html @@ -6,7 +6,10 @@ </td> <td is="coral-table-cell" data-aecu-execute-script-path>${resource.path}</td> <td is="coral-table-cell"><a target="_blank" data-aecu-execute-script-history>* not executed *</a></td> - <td is="coral-table-cell" data-aecu-execute-script-status>Ready</td> + <td is="coral-table-cell" data-aecu-execute-script-status> + <coral-icon icon="helpCircle" size="M" > + </coral-icon> + </td> <td is="coral-table-cell" > <button is="coral-button" type="button" variant="minimal" icon="dragHandle" coral-table-roworder></button> </td> From 3b9489fcd17c678585618dcb8a860f5632c5fa7a Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Wed, 4 Jul 2018 16:09:08 +0200 Subject: [PATCH 076/122] fixed icon sync --- .../apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js index d58ed8a9..a6210fe9 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js @@ -92,7 +92,8 @@ AECU.Executor.changeStatus = function(items, value){ var className = value.className; var iconTags = items.children("coral-icon"); iconTags.each(function() { - this.set('icon', icon) + this.set('icon', icon); + this._syncDOM(); }); iconTags.removeClass('icon-color-inprogress'); iconTags.addClass(className); From 98d621e4213c905e6e663a3b1300c6b12e1eeade Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Thu, 5 Jul 2018 10:34:56 +0200 Subject: [PATCH 077/122] layout --- .../aecu/clientlibs/aecu.editor/css/aecu.css | 5 ++ .../aecu/tools/execute/page/.content.xml | 69 ++++++++++--------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index 7824bd17..5e4063d6 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -3,6 +3,11 @@ margin: 2rem; } +.aecu-searchfield { + margin-top: 1rem; + margin-bottom: 1rem; +} + table.aecu-history-overview td { padding: 0.5rem; } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml index 6257f42a..ab89ac26 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml @@ -16,46 +16,53 @@ sling:resourceType="granite/ui/components/foundation/includeclientlibs" categories="[coralui3,granite.ui.coral.foundation,aecu.editor]"/> </head> - <dialogue jcr:primaryType="nt:unstructured" - sling:resourceType="valtech/aecu/tools/execute/dialogue"/> <rails jcr:primaryType="nt:unstructured"> <search granite:class="cq-rail-components-search" jcr:primaryType="nt:unstructured" jcr:title="Search" - sling:resourceType="granite/ui/components/coral/foundation/panel/railpanel"> + sling:resourceType="granite/ui/components/coral/foundation/panel/railpanel" + > <items jcr:primaryType="nt:unstructured"> - <form - granite:id="aecu-execute-scripts-search-form" - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/form" - action="/apps/valtech/aecu/tools/execute/page.html" - modeGroup="aecu-execute-scripts-search" - searchResultTitle="Scripts to execute" - targetCollection="#aecu-execute-scripts-search"> - <successresponse - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/form/responses/reload"/> - <items jcr:primaryType="nt:unstructured"> - <searchPath - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/form/pathfield" - fieldLabel="Select the folder or script" - rootPath="/etc/groovyconsole/scripts" - required="{Boolean}true" - filter="hierarchy" - name="searchPath"/> - <submit - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/foundation/form/submit" - text="Search"/> - </items> - </form> + <content + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/container" + granite:class="base-container" + > + <items jcr:primaryType="nt:unstructured"> + <form + granite:id="aecu-execute-scripts-search-form" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form" + action="/apps/valtech/aecu/tools/execute/page.html" + modeGroup="aecu-execute-scripts-search" + searchResultTitle="Scripts to execute" + targetCollection="#aecu-execute-scripts-search"> + <successresponse + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form/responses/reload"/> + <items jcr:primaryType="nt:unstructured"> + <searchPath + granite:class="aecu-searchfield" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form/pathfield" + fieldLabel="Select the folder or script" + rootPath="/etc/groovyconsole/scripts" + required="{Boolean}true" + filter="hierarchy" + name="searchPath"/> + <submit + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/foundation/form/submit" + text="Search"/> + </items> + </form> + </items> + </content> </items> </search> </rails> - <views jcr:primaryType="nt:unstructured" - sling:resourceType="valtech/aecu/tools/execute/dialogue"> + <views jcr:primaryType="nt:unstructured"> <list granite:rel="aecu-execute-scripts" jcr:primaryType="nt:unstructured" From 99b1689a86d966014994e944d2fe22e6a9dc112b Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Thu, 5 Jul 2018 15:38:19 +0200 Subject: [PATCH 078/122] added text color, titles and button deactivation --- .../clientlibs/aecu.editor/js/constants.js | 36 +++++++++++++++---- .../clientlibs/aecu.editor/js/executor.js | 15 ++++++-- .../aecu/tools/execute/dataitem/dataitem.html | 6 ++-- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js index d1205299..bbe1fdc8 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js @@ -23,12 +23,36 @@ AECU.Constants.Executor = { } AECU.Constants.Executor.Status = { - ready : {icon: "helpCircle", className: ""}, - inProgress : {icon: "playCircle", className: "icon-color-inprogress"}, - fail : {icon: "closeCircle", className: "icon-color-fail"}, - pending : {icon: "pending", className: "icon-color-inprogress"}, - executed: {icon: "checkCircle", className: "icon-color-ok"}, - internalError: {icon: "sentimentNegative", className: "icon-color-fail"} + ready : { + icon: "helpCircle", + className: "", + text: "Ready to run" + }, + inProgress : { + icon: "playCircle", + className: "icon-color-inprogress", + text: "In progress" + }, + fail : { + icon: "closeCircle", + className: "icon-color-fail", + text: "Failed" + }, + pending : { + icon: "pending", + className: "icon-color-inprogress", + text: "Pending" + }, + executed: { + icon: "checkCircle", + className: "icon-color-ok", + text: "Ok" + }, + internalError: { + icon: "sentimentNegative", + className: "icon-color-fail", + text: "Internal error" + } } AECU.Constants.Executor.HistoryEntryActions = { diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js index a6210fe9..adde4353 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js @@ -45,7 +45,7 @@ AECU.Executor.executeAll = function(tableRows) { } AECU.Executor.execute(tableRows[i],historyEntryAction,AECU.Executor.historyEntryPath); } - + AECU.Executor.disableButton(); AECU.Executor.historyEntryPath = undefined; } @@ -80,25 +80,35 @@ AECU.Executor.addHistoryLink = function(row, historyEntryPath){ AECU.Executor.changeRowStatus = function(row, value){ AECU.Executor.changeStatus($(row).find("[data-aecu-execute-script-status]"), value); + AECU.Executor.changeScriptColor($(row).find("[data-aecu-execute-script-path]"), value); } AECU.Executor.changeAllStatus = function(value){ AECU.Executor.changeStatus($("[data-aecu-execute-script-status]"), value); + AECU.Executor.changeScriptColor($("[data-aecu-execute-script-path]"), value); } -AECU.Executor.changeStatus = function(items, value){ +AECU.Executor.changeStatus = function(items, value) { var icon = value.icon; + var title = value.text; var className = value.className; var iconTags = items.children("coral-icon"); iconTags.each(function() { this.set('icon', icon); + this.set('title', title); this._syncDOM(); }); iconTags.removeClass('icon-color-inprogress'); iconTags.addClass(className); } +AECU.Executor.changeScriptColor = function(items, value) { + var className = value.className; + items.removeClass('icon-color-inprogress'); + items.addClass(className); +} + AECU.Executor.disableButton = function(row){ if(row != undefined){ $(row).find("[data-aecu-execute-script-button]").prop('disabled', true); @@ -127,6 +137,7 @@ $(document).ready(function(){ /* Event for each row (script) displayed in screen. */ $('[data-aecu-execute-script-button]').on('click', function(event) { + AECU.Executor.disableButton(); AECU.Executor.execute( this.closest('[data-aecu-execute-script]'), AECU.Constants.Executor.HistoryEntryActions.single,null); diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html index aaa7f6ee..26a5bf64 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html @@ -1,13 +1,13 @@ <tr class="aecu-execute-script" is="coral-table-row" data-aecu-execute-script="${resource.path}"> <td is="coral-table-cell"> - <button is="coral-button" variant="primary" icon="checkCircle" iconsize="S" data-aecu-execute-script-button> - Execute Script + <button is="coral-button" variant="primary" iconsize="S" data-aecu-execute-script-button> + Execute script </button> </td> <td is="coral-table-cell" data-aecu-execute-script-path>${resource.path}</td> <td is="coral-table-cell"><a target="_blank" data-aecu-execute-script-history>* not executed *</a></td> <td is="coral-table-cell" data-aecu-execute-script-status> - <coral-icon icon="helpCircle" size="M" > + <coral-icon icon="helpCircle" size="M" title="Not run"> </coral-icon> </td> <td is="coral-table-cell" > From df202cc3e899a2810e36a5362afbed05cfd18ff2 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 6 Jul 2018 08:54:40 +0200 Subject: [PATCH 079/122] open rail panel --- .../valtech/aecu/clientlibs/aecu.editor/js/executor.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js index adde4353..7592bf81 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js @@ -142,5 +142,13 @@ $(document).ready(function(){ this.closest('[data-aecu-execute-script]'), AECU.Constants.Executor.HistoryEntryActions.single,null); }); + + /* open rail tab */ + var button = $('coral-cyclebutton'); + if (button) { + Coral.commons.ready(button[0], function() { + button.find('button').click(); + }); + } }); \ No newline at end of file From adcf0122f2ea6ab7f9fdaf1f941d936b2e2d57ac Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 6 Jul 2018 09:14:23 +0200 Subject: [PATCH 080/122] layout --- .../aecu/clientlibs/aecu.editor/css/aecu.css | 18 +++++++++++++++++- .../executionResults/executionResults.html | 4 ++-- .../templates/executionResult.html | 18 ++++++++++-------- .../content/history/overview/overview.html | 4 ++-- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index 5e4063d6..823282a3 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -9,7 +9,10 @@ } table.aecu-history-overview td { - padding: 0.5rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + padding-top: 0.2rem; + padding-bottom: 0.2rem; } table.aecu-history-detail td { @@ -43,3 +46,16 @@ table.aecu-history-detail td { font-size: 0.5em; transform: translateY(0.35em); } + +.aecu-font-normal { + font-size: 1rem; +} + +.aecu-font-large { + font-size: 1.25rem; +} + +.aecu-padding-sides5 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html index b8c3f6fb..aea50281 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html @@ -6,13 +6,13 @@ <h2>No scripts executed</h2> <sly data-sly-test="${!empty}"> <sly data-sly-use.details="templates/executionResult.html" /> <sly data-sly-test="${cmp.history.singleResults.size == 1}"> - <h2>Execution details</h2> + <h2 class="aecu-font-large">Execution details</h2> <sly data-sly-list="${cmp.history.singleResults}"> <sly data-sly-call="${details.details @ result = item}" /> </sly> </sly> <sly data-sly-test="${cmp.history.singleResults.size > 1}"> - <h2>Execution details for ${cmp.history.singleResults.size} scripts</h2> + <h2 class="aecu-font-large">Execution details for ${cmp.history.singleResults.size} scripts</h2> <coral-accordion> <sly data-sly-list="${cmp.history.singleResults}"> <coral-accordion-item data-path="${item.path}"> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html index 80781938..d06b5bb4 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html @@ -1,5 +1,6 @@ <template data-sly-template.details="${ @ result, isFallback=false}"> - <table class="aecu-history-detail" width="100%"> +<div class="aecu-padding-sides5"> + <table class="aecu-history-detail aecu-font-normal" width="100%"> <tr> <td>Path: ${result.path}</td> <td rowspan="2"> @@ -12,18 +13,19 @@ </tr> </table> <sly data-sly-test="${result.result}"> - <h3 data-sly-test="${!isFallback}">Result</h3> - <h4 data-sly-test="${isFallback}">Result</h4> - <pre>${result.result}</pre> + <h3 data-sly-test="${!isFallback}" class="aecu-font-large">Result</h3> + <h4 data-sly-test="${isFallback}" class="aecu-font-large">Result</h4> + <pre class="aecu-font-normal">${result.result}</pre> </sly> <sly data-sly-test="${result.output}"> - <h3 data-sly-test="${!isFallback}">Output</h3> - <h4 data-sly-test="${isFallback}">Output</h4> - <pre>${result.output}</pre> + <h3 data-sly-test="${!isFallback}" class="aecu-font-large">Output</h3> + <h4 data-sly-test="${isFallback}" class="aecu-font-large">Output</h4> + <pre class="aecu-font-normal">${result.output}</pre> </sly> <sly data-sly-test="${result.fallbackResult}"> - <h3>Fallback script result</h3> + <h3 class="aecu-font-large">Fallback script result</h3> <sly data-sly-call="${details @ result = result.fallbackResult, isFallback = true}" /> </sly> +</div> </template> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html index 36845ac0..2a7f0af4 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -1,9 +1,9 @@ <sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> <h1>Run details</h1> -<table class="aecu-history-overview" width="100%"> +<table class="aecu-history-overview aecu-font-normal" width="100%"> <tr> <td>State: ${cmp.history.state.label}</td> - <td rowspan="4"> + <td rowspan="4" align="right"> <svg width="150px" height="150px" viewBox="0 0 50 50" class="donut"> <circle class="donut-ring" cx="25" cy="25" r="22" fill="transparent" stroke="grey" stroke-width="0.2"></circle> <circle class="donut-outerring" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="grey" stroke-width="8.5"></circle> From 8a3edfd7f429d77f0ea258e43b5fdfb4b1b49a2e Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 6 Jul 2018 11:16:25 +0200 Subject: [PATCH 081/122] MIT license --- LICENSE | 695 +----------------- Readme.md | 2 +- .../valtech/aecu/service/AecuException.java | 25 +- .../de/valtech/aecu/service/AecuService.java | 25 +- .../valtech/aecu/service/ExecutionResult.java | 25 +- .../de/valtech/aecu/service/HistoryEntry.java | 25 +- .../de/valtech/aecu/service/package-info.java | 25 +- .../groovy/console/bindings/Migration.java | 21 + .../console/bindings/SimpleContentUpdate.java | 29 +- .../console/bindings/actions/Action.java | 33 +- .../console/bindings/actions/PrintPath.java | 33 +- .../bindings/actions/RemoveProperty.java | 33 +- .../bindings/actions/RenameProperty.java | 33 +- .../console/bindings/actions/SetProperty.java | 33 +- .../console/bindings/filters/ANDFilter.java | 34 +- .../console/bindings/filters/FilterBy.java | 33 +- .../bindings/filters/FilterByProperties.java | 38 +- .../console/bindings/filters/NOTFilter.java | 33 +- .../console/bindings/filters/ORFilter.java | 34 +- .../AecuBindingExtensionProvider.java | 29 +- .../AecuStarImportExtensionProvider.java | 21 + .../traversers/ForChildResourcesOf.java | 29 +- .../traversers/ForDescendantResourcesOf.java | 29 +- .../bindings/traversers/ForResources.java | 29 +- .../bindings/traversers/TraversData.java | 29 +- .../core/healthcheck/LastRunHealthCheck.java | 25 +- .../healthcheck/SelfCheckHealthCheck.java | 25 +- .../aecu/core/history/HistoryUtil.java | 25 +- .../core/installhook/AecuInstallHook.java | 21 + .../core/installhook/AecuTrackerListener.java | 21 + .../aecu/core/jmx/AecuServiceMBean.java | 25 +- .../aecu/core/jmx/AecuServiceMBeanImpl.java | 25 +- .../PurgeHistoryConfiguration.java | 25 +- .../core/maintenance/PurgeHistoryTask.java | 25 +- .../core/model/execute/ExecuteDataSource.java | 29 +- .../core/model/history/HistoryDataItem.java | 25 +- .../core/model/history/HistoryDataSource.java | 25 +- .../core/model/history/HistoryOverview.java | 25 +- .../aecu/core/service/AecuServiceImpl.java | 25 +- .../core/service/GroovyConsoleRequest.java | 25 +- .../aecu/core/service/HistoryEntryImpl.java | 25 +- .../ServiceResourceResolverService.java | 25 +- .../aecu/core/servlets/BaseServlet.java | 30 +- .../aecu/core/servlets/ExecutionServlet.java | 30 +- .../aecu/core/history/HistoryUtilTest.java | 25 +- .../core/service/AecuServiceImplTest.java | 25 +- .../aecu/clientlibs/aecu.editor/js/aecu.js | 29 +- .../clientlibs/aecu.editor/js/constants.js | 29 +- .../clientlibs/aecu.editor/js/executor.js | 29 +- .../aecu/clientlibs/aecu.editor/js/history.js | 22 + .../aecu.editor/js/requestHandler.js | 29 +- .../aecu/clientlibs/aecu.editor/js/utils.js | 29 +- 52 files changed, 876 insertions(+), 1197 deletions(-) diff --git a/LICENSE b/LICENSE index f288702d..2b919721 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,21 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<https://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<https://www.gnu.org/licenses/why-not-lgpl.html>. +MIT License + +Copyright (c) 2018 Valtech GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Readme.md b/Readme.md index 22160bcf..7e5715b9 100644 --- a/Readme.md +++ b/Readme.md @@ -159,4 +159,4 @@ For the status of older runs use AECU's history page. # License -The AC Tool is licensed under the [GNU GENERAL PUBLIC LICENSE - v 3](LICENSE). +The AC Tool is licensed under the [MIT LICENSE](LICENSE). diff --git a/api/src/main/java/de/valtech/aecu/service/AecuException.java b/api/src/main/java/de/valtech/aecu/service/AecuException.java index e9c378ee..dc3128d6 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuException.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuException.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.service; diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index ae4a6bb5..1f9910d6 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.service; diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java index ec84af11..8940df7e 100644 --- a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.service; diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java index 888c178d..5c6307d1 100644 --- a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.service; diff --git a/api/src/main/java/de/valtech/aecu/service/package-info.java b/api/src/main/java/de/valtech/aecu/service/package-info.java index ebcb0d61..747a9ee6 100644 --- a/api/src/main/java/de/valtech/aecu/service/package-info.java +++ b/api/src/main/java/de/valtech/aecu/service/package-info.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ @Version("1.0") diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java index b0e52fac..b334f044 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java @@ -1,3 +1,24 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package de.valtech.aecu.core.groovy.console.bindings; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 759c033a..d6913dd3 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java index e9c269ba..26f7d31f 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java @@ -1,25 +1,30 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions; -import org.apache.sling.api.resource.Resource; - import javax.annotation.Nonnull; +import org.apache.sling.api.resource.Resource; + /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java index 484e0bc4..af9a4f2e 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java @@ -1,25 +1,30 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions; -import org.apache.sling.api.resource.Resource; - import javax.annotation.Nonnull; +import org.apache.sling.api.resource.Resource; + /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java index 5a1abdc1..2047c603 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java @@ -1,26 +1,31 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions; +import javax.annotation.Nonnull; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; -import javax.annotation.Nonnull; - /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java index 2de91aa8..9d205bc6 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java @@ -1,26 +1,31 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions; +import javax.annotation.Nonnull; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; -import javax.annotation.Nonnull; - /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java index cbe7e3b2..990ebfcd 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java @@ -1,26 +1,31 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions; +import javax.annotation.Nonnull; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; -import javax.annotation.Nonnull; - /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java index bc235dae..a4d9fc6d 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java @@ -1,25 +1,31 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; -import org.apache.sling.api.resource.Resource; +import java.util.List; import javax.annotation.Nonnull; -import java.util.List; + +import org.apache.sling.api.resource.Resource; /** * @author Roxana Muresan diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java index 3e7e6a18..82a62357 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java @@ -1,25 +1,30 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; -import org.apache.sling.api.resource.Resource; - import javax.annotation.Nonnull; +import org.apache.sling.api.resource.Resource; + /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java index 993724fd..f7aed48f 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java @@ -1,28 +1,34 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; -import org.apache.sling.api.resource.ModifiableValueMap; -import org.apache.sling.api.resource.Resource; - -import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nonnull; + +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; + /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java index b0cff175..7924c67b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java @@ -1,25 +1,30 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; -import org.apache.sling.api.resource.Resource; - import javax.annotation.Nonnull; +import org.apache.sling.api.resource.Resource; + /** * @author Roxana Muresan */ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java index 76623987..5777e4ad 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java @@ -1,25 +1,31 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; -import org.apache.sling.api.resource.Resource; +import java.util.List; import javax.annotation.Nonnull; -import java.util.List; + +import org.apache.sling.api.resource.Resource; /** * @author Roxana Muresan diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java index 66efe13e..8482e0ef 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.provider; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java index c5990d53..81e32a64 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java @@ -1,3 +1,24 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package de.valtech.aecu.core.groovy.console.bindings.provider; import com.icfolson.aem.groovy.console.api.StarImportExtensionProvider; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java index 7c4b7149..26819ce5 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java index 09f2a9e7..a3c68c3e 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java index fda86d50..ba877462 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java index 9212c6a6..6c001216 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java index c972cf0b..cff8744f 100644 --- a/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.healthcheck; diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java index 661e45f1..ddc85b4e 100644 --- a/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.healthcheck; diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index 98b778a5..06c6c83b 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.history; diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java index 14c7f2a6..de6b8c30 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -1,3 +1,24 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package de.valtech.aecu.core.installhook; import de.valtech.aecu.service.AecuException; diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java index 31c83b11..97969d6e 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java @@ -1,3 +1,24 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ package de.valtech.aecu.core.installhook; import de.valtech.aecu.service.AecuException; diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index 46f84c09..e79e7545 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.jmx; diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 2903fb41..ea81ca34 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.jmx; diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java index 48a91e68..69e331c3 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.maintenance; diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java index 3a1f6cfc..f7beecf8 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.maintenance; diff --git a/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java index 744382c5..508dc3f7 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java +++ b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.model.execute; diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java index 82abc044..1337c2cb 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.model.history; diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java index 3658db59..393df55b 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.model.history; diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java index 2bc1362f..daefba74 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.model.history; diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 0695f3d7..f9c6c766 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.service; diff --git a/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java index b168b919..853a2bfc 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java +++ b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.service; diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index 24a7e2af..7cc9ba1b 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.service; diff --git a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java index 55b4dde9..3890cfd1 100644 --- a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java +++ b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.serviceuser; diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java index fd561b3d..5c0c77ba 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java @@ -1,20 +1,24 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - package de.valtech.aecu.core.servlets; import java.io.IOException; diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java index e8ae684e..00cac50a 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java @@ -1,20 +1,24 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - package de.valtech.aecu.core.servlets; diff --git a/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java index 8e18eb9e..2d4f4e97 100644 --- a/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java +++ b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.history; diff --git a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java index 6a2e4d88..37440b41 100644 --- a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java +++ b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.service; diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js index cf0b1b9f..958cbf09 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/aecu.js @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ /* Initialize of variable */ diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js index bbe1fdc8..5e66a67a 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ AECU.Constants = {}; diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js index 7592bf81..6c4184f5 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ AECU.Executor = {}; diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js index f49c7a26..20ffb92b 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js @@ -1,3 +1,25 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + (function($, ns, channel, window) { "use strict"; diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js index 50c0c706..231be4e7 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ AECU.RequestHandler = {}; diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js index 8287762a..0d1106a4 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ /* From 16a216101f7c793422e561e95cb201cf22e801b0 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 6 Jul 2018 11:25:06 +0200 Subject: [PATCH 082/122] bindings/improvements-1: added set property for Integer and Boolean; renamed some classes and method names --- .../{Migration.java => ContentUpgrade.java} | 47 +++++++++++-------- .../console/bindings/SimpleContentUpdate.java | 6 +-- .../bindings/actions/SetBooleanProperty.java | 11 +++++ .../bindings/actions/SetIntegerProperty.java | 11 +++++ ...etProperty.java => SetStringProperty.java} | 11 +++-- .../bindings/SimpleContentUpdateTest.java | 28 +++++++++++ .../tests_for_simpleContentUpdates.groovy | 16 ++++--- 7 files changed, 97 insertions(+), 33 deletions(-) rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/{Migration.java => ContentUpgrade.java} (61%) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/{SetProperty.java => SetStringProperty.java} (86%) create mode 100644 core/src/test/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdateTest.java diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java similarity index 61% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index b0e52fac..7ffa1783 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/Migration.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -1,9 +1,6 @@ package de.valtech.aecu.core.groovy.console.bindings; -import de.valtech.aecu.core.groovy.console.bindings.actions.Action; -import de.valtech.aecu.core.groovy.console.bindings.actions.RemoveProperty; -import de.valtech.aecu.core.groovy.console.bindings.actions.RenameProperty; -import de.valtech.aecu.core.groovy.console.bindings.actions.SetProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.*; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByProperties; import de.valtech.aecu.core.groovy.console.bindings.traversers.ForChildResourcesOf; @@ -21,9 +18,9 @@ import java.util.List; import java.util.Map; -public class Migration { +public class ContentUpgrade { - private static Logger LOG = LoggerFactory.getLogger(Migration.class); + private static Logger LOG = LoggerFactory.getLogger(ContentUpgrade.class); private ResourceResolver resourceResolver = null; @@ -32,64 +29,76 @@ public class Migration { private List<Action> actions = new ArrayList<>(); - public Migration(@Nonnull ResourceResolver resourceResolver) { + public ContentUpgrade(@Nonnull ResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } /** content filter methods **/ - public Migration forResources(@Nonnull String[] paths) { + public ContentUpgrade forResources(@Nonnull String[] paths) { LOG.debug("forResources: {}", paths.toString()); traversals.add(new ForResources(paths)); return this; } - public Migration forChildResourcesOf(@Nonnull String path) { + public ContentUpgrade forChildResourcesOf(@Nonnull String path) { LOG.debug("forChildResourcesOf: {}", path); traversals.add(new ForChildResourcesOf(path)); return this; } - public Migration forDescendantResourcesOf(@Nonnull String path) { + public ContentUpgrade forDescendantResourcesOf(@Nonnull String path) { LOG.debug("forDescendantResourcesOf: {}", path); traversals.add(new ForDescendantResourcesOf(path)); return this; } /** filters **/ - public Migration filterByProperties(@Nonnull Map<String, String> conditionProperties) { + public ContentUpgrade filterByProperties(@Nonnull Map<String, String> conditionProperties) { LOG.debug("filterByProperties: {}", MapUtils.toString(conditionProperties)); filter = new FilterByProperties(conditionProperties); return this; } - public Migration filterWith(@Nonnull FilterBy filter) { + public ContentUpgrade filterWith(@Nonnull FilterBy filter) { LOG.debug("filterWith: {}", filter); this.filter = filter; return this; } /** properties edit methods **/ - public Migration doSetProperty(@Nonnull String name, String value) { - LOG.debug("doSetProperty: {} = {}", name, value); - actions.add(new SetProperty(name, value)); + public ContentUpgrade doSetStringProperty(@Nonnull String name, String value) { + LOG.debug("doSetStringProperty: {} = {}", name, value); + actions.add(new SetStringProperty(name, value)); return this; } - public Migration doRemoveProperty(@Nonnull String name) { + public ContentUpgrade doSetBooleanProperty(@Nonnull String name, Boolean value) { + LOG.debug("doSetBooleanProperty: {} = {}", name, value); + actions.add(new SetBooleanProperty(name, value)); + return this; + } + + public ContentUpgrade doSetIntegerProperty(@Nonnull String name, int value) { + LOG.debug("doSetIntegerProperty: {} = {}", name, value); + actions.add(new SetIntegerProperty(name, value)); + return this; + } + + public ContentUpgrade doRemoveProperty(@Nonnull String name) { LOG.debug("doRemoveProperty: {}", name); actions.add(new RemoveProperty(name)); return this; } - public Migration doRenameProperty(@Nonnull String oldName, @Nonnull String newName) { + public ContentUpgrade doRenameProperty(@Nonnull String oldName, @Nonnull String newName) { LOG.debug("doRenameProperty: {} to {}", oldName, newName); actions.add(new RenameProperty(oldName, newName)); return this; } public StringBuffer apply() throws PersistenceException { - LOG.debug("apply migration"); - StringBuffer stringBuffer = new StringBuffer("Running migration...\n"); + LOG.debug("apply content upgrade"); + StringBuffer stringBuffer = new StringBuffer("Running content upgrade...\n"); for (TraversData traversal : traversals) { for (Action action : actions) { traversal.traverse(resourceResolver, filter, action, stringBuffer); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 759c033a..0415df0b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -24,15 +24,15 @@ */ public class SimpleContentUpdate { - private ResourceResolver resourceResolver;// TODO system user resolver!! + private ResourceResolver resourceResolver; public SimpleContentUpdate(ResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } - public Migration getNewMigration() { - return new Migration(resourceResolver); + public ContentUpgrade contentUpgradeBuilder() { + return new ContentUpgrade(resourceResolver); } } \ No newline at end of file diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java new file mode 100644 index 00000000..8d0a1d28 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java @@ -0,0 +1,11 @@ +package de.valtech.aecu.core.groovy.console.bindings.actions; + +import javax.annotation.Nonnull; + +public class SetBooleanProperty extends SetStringProperty { + + public SetBooleanProperty(@Nonnull String name, Boolean value) { + this.name = name; + this.value = value; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java new file mode 100644 index 00000000..3da629d3 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java @@ -0,0 +1,11 @@ +package de.valtech.aecu.core.groovy.console.bindings.actions; + +import javax.annotation.Nonnull; + +public class SetIntegerProperty extends SetStringProperty { + + public SetIntegerProperty(@Nonnull String name, Integer value) { + this.name = name; + this.value = value; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java similarity index 86% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java index cbe7e3b2..b339b216 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java @@ -24,17 +24,18 @@ /** * @author Roxana Muresan */ -public class SetProperty implements Action { +public class SetStringProperty implements Action { - private String name; - private Object value; + protected String name; + protected Object value; - public SetProperty(@Nonnull String name, Object value) { + protected SetStringProperty() {} + + public SetStringProperty(@Nonnull String name, String value) { this.name = name; this.value = value; } - @Override public String doAction(@Nonnull Resource resource) { ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); diff --git a/core/src/test/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdateTest.java b/core/src/test/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdateTest.java new file mode 100644 index 00000000..95173f52 --- /dev/null +++ b/core/src/test/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdateTest.java @@ -0,0 +1,28 @@ +package de.valtech.aecu.core.groovy.console.bindings; + +import org.apache.sling.api.resource.ResourceResolver; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class SimpleContentUpdateTest { + + @Mock + private ResourceResolver resourceResolverMock; + + private SimpleContentUpdate simpleContentUpdate; + + + @Before + public void setUp() throws Exception { + simpleContentUpdate = new SimpleContentUpdate(resourceResolverMock); + } + + @Test + public void toDo() { + // TODO!! + } +} diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index 605a49fa..6a6d5305 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -7,7 +7,7 @@ def conditionMap_Page = [:] conditionMap_Page['jcr:primaryType'] = "cq:PageContent" -println aecu.getNewMigration()// TODO contentUpgradeBuilder(). +println aecu.contentUpgradeBuilder() // traversers .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") @@ -15,8 +15,10 @@ println aecu.getNewMigration()// TODO contentUpgradeBuilder(). // filters .filterByProperties(conditionMap_Page) // actions - .doSetProperty("newProperty", "aecu test with conditionMap_Page") - .doRenameProperty("newProperty", "delete_me_later") + .doSetStringProperty("newStringProperty", "aecu test with conditionMap_Page") + .doSetBooleanProperty("newBooleanProperty", true) + .doSetIntegerProperty("newStringProperty", 123) + .doRenameProperty("newStringProperty", "delete_me_later") // .removeProperty("delete_me_later") .apply() @@ -31,7 +33,7 @@ def complexFilter = new ORFilter( ] ) ]) -println aecu.getNewMigration() +println aecu.contentUpgradeBuilder() // traversers .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") @@ -39,7 +41,9 @@ println aecu.getNewMigration() // filters .filterWith(complexFilter) // actions - .doSetProperty("newProperty", "aecu test with conditionMap_Hero") - .doRenameProperty("newProperty", "delete_me_later") + .doSetProperty("newStringProperty", "aecu test with conditionMap_Hero") + .doSetBooleanProperty("newBooleanProperty", false) + .doSetIntegerProperty("newStringProperty", 789) + .doRenameProperty("newStringProperty", "delete_me_later") // .removeProperty("delete_me_later") .apply() \ No newline at end of file From f255b54d8fc66632b22a0bcdd68ec966dcb7ae07 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 6 Jul 2018 11:56:17 +0200 Subject: [PATCH 083/122] bindings/improvements-1: dry run added --- .../groovy/console/bindings/ContentUpgrade.java | 13 +++++++++++-- .../console/bindings/actions/SetStringProperty.java | 2 +- .../bindings/traversers/ForChildResourcesOf.java | 6 ++++-- .../traversers/ForDescendantResourcesOf.java | 12 +++++++----- .../console/bindings/traversers/ForResources.java | 6 ++++-- .../console/bindings/traversers/TraversData.java | 2 +- 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index 7ffa1783..be928eac 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -98,10 +98,19 @@ public ContentUpgrade doRenameProperty(@Nonnull String oldName, @Nonnull String public StringBuffer apply() throws PersistenceException { LOG.debug("apply content upgrade"); - StringBuffer stringBuffer = new StringBuffer("Running content upgrade...\n"); + return apply(false); + } + + public StringBuffer applyDry() throws PersistenceException { + LOG.debug("apply content upgrade dry"); + return apply(true); + } + + private StringBuffer apply(boolean dryRun) throws PersistenceException { + StringBuffer stringBuffer = new StringBuffer("Running content upgrade " + (dryRun ? "DRY" : "") + "...\n"); for (TraversData traversal : traversals) { for (Action action : actions) { - traversal.traverse(resourceResolver, filter, action, stringBuffer); + traversal.traverse(resourceResolver, filter, action, stringBuffer, dryRun); } } return stringBuffer; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java index b339b216..c0b00d99 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java @@ -40,6 +40,6 @@ public SetStringProperty(@Nonnull String name, String value) { public String doAction(@Nonnull Resource resource) { ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); properties.put(name, value); - return "Setting property " + name + "=" + value + " for resource " + resource.getPath(); + return "Setting " + value.getClass().getSimpleName() + " property " + name + "=" + value + " for resource " + resource.getPath(); } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java index 7c4b7149..f4bab0a9 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -38,7 +38,7 @@ public ForChildResourcesOf(@Nonnull String path) { @Override - public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException { + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { Resource parentResource = resourceResolver.getResource(path); if (parentResource != null) { Iterator<Resource> resourceIterator = resourceResolver.listChildren(parentResource); @@ -48,7 +48,9 @@ public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter stringBuffer.append(action.doAction(resource) + "\n"); } } - resourceResolver.commit(); + if (!dryRun) { + resourceResolver.commit(); + } } } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java index 09f2a9e7..de752929 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -38,14 +38,14 @@ public ForDescendantResourcesOf(@Nonnull String path) { @Override - public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException { + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { Resource parentResource = resourceResolver.getResource(path); if (parentResource != null) { - traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action, stringBuffer); + traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action, stringBuffer, dryRun); } } - private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, Resource resource, FilterBy filter, Action action, StringBuffer stringBuffer) throws PersistenceException { + private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, Resource resource, FilterBy filter, Action action, StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { if (resource != null && resource.hasChildren()) { Iterator<Resource> childResources = resource.listChildren(); while (childResources.hasNext()) { @@ -53,9 +53,11 @@ private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, if (filter == null || filter.filter(child)) { stringBuffer.append(action.doAction(child) + "\n"); } - traverseChildResourcesRecursive(resourceResolver, child, filter, action, stringBuffer); + traverseChildResourcesRecursive(resourceResolver, child, filter, action, stringBuffer, dryRun); + } + if (!dryRun) { + resourceResolver.commit(); } - resourceResolver.commit(); // TOD: maybe commit will be called to often this way: TODO: think about it for later!! } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java index fda86d50..a5528e2c 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -36,7 +36,7 @@ public ForResources(@Nonnull String[] paths) { } @Override - public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException { + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { for (String path : paths) { if (path != null) { Resource resource = resourceResolver.getResource(path); @@ -45,6 +45,8 @@ public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter } } } - resourceResolver.commit(); + if (!dryRun) { + resourceResolver.commit(); + } } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java index 9212c6a6..31b71715 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -28,6 +28,6 @@ */ public interface TraversData { - void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer) throws PersistenceException; + void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException; } From a4dadd720eae116232b0769f876b0b488aace2bf Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 6 Jul 2018 16:37:56 +0200 Subject: [PATCH 084/122] bindings/improvements-1: added copy, move, delete Actions for resources and copy, move Actions for properties; moved the Action classes in subpackages --- .../console/bindings/ContentUpgrade.java | 44 +++++++++++++-- .../console/bindings/actions/Action.java | 3 +- .../bindings/actions/SetBooleanProperty.java | 11 ---- .../bindings/actions/SetIntegerProperty.java | 11 ---- .../CopyPropertyToRelativePath.java | 55 +++++++++++++++++++ .../DeleteProperty.java} | 9 +-- .../MovePropertyToRelativePath.java | 55 +++++++++++++++++++ .../{ => properties}/RenameProperty.java | 3 +- .../properties/SetBooleanProperty.java | 30 ++++++++++ .../properties/SetIntegerProperty.java | 30 ++++++++++ .../{ => properties}/SetStringProperty.java | 3 +- .../resource/CopyResourceToRelativePath.java | 48 ++++++++++++++++ .../actions/resource/DeleteResource.java | 43 +++++++++++++++ .../resource/MoveResourceToRelativePath.java | 48 ++++++++++++++++ 14 files changed, 360 insertions(+), 33 deletions(-) delete mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java delete mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/{RemoveProperty.java => properties/DeleteProperty.java} (79%) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/{ => properties}/RenameProperty.java (91%) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/{ => properties}/SetStringProperty.java (91%) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index be928eac..a7b898b8 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -1,6 +1,10 @@ package de.valtech.aecu.core.groovy.console.bindings; import de.valtech.aecu.core.groovy.console.bindings.actions.*; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.*; +import de.valtech.aecu.core.groovy.console.bindings.actions.resource.CopyResourceToRelativePath; +import de.valtech.aecu.core.groovy.console.bindings.actions.resource.DeleteResource; +import de.valtech.aecu.core.groovy.console.bindings.actions.resource.MoveResourceToRelativePath; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByProperties; import de.valtech.aecu.core.groovy.console.bindings.traversers.ForChildResourcesOf; @@ -33,7 +37,7 @@ public ContentUpgrade(@Nonnull ResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } - /** content filter methods **/ + /** content path filter methods **/ public ContentUpgrade forResources(@Nonnull String[] paths) { LOG.debug("forResources: {}", paths.toString()); traversals.add(new ForResources(paths)); @@ -84,9 +88,9 @@ public ContentUpgrade doSetIntegerProperty(@Nonnull String name, int value) { return this; } - public ContentUpgrade doRemoveProperty(@Nonnull String name) { - LOG.debug("doRemoveProperty: {}", name); - actions.add(new RemoveProperty(name)); + public ContentUpgrade doDeleteProperty(@Nonnull String name) { + LOG.debug("doDeleteProperty: {}", name); + actions.add(new DeleteProperty(name)); return this; } @@ -96,6 +100,38 @@ public ContentUpgrade doRenameProperty(@Nonnull String oldName, @Nonnull String return this; } + public ContentUpgrade doCopyPropertyToRelativePath(@Nonnull String name, @Nonnull String relativeResourcePath) { + LOG.debug("doCopyProperty: {} to {}", name, relativeResourcePath); + actions.add(new CopyPropertyToRelativePath(name, resourceResolver, relativeResourcePath)); + return this; + } + + public ContentUpgrade doMovePropertyToRelativePath(@Nonnull String name, @Nonnull String relativeResourcePath) { + LOG.debug("doMoveProperty: {} to {}", name, relativeResourcePath); + actions.add(new MovePropertyToRelativePath(name, resourceResolver, relativeResourcePath)); + return this; + } + + /** resource edit methods **/ + public ContentUpgrade doCopyResourceToRelativePath(@Nonnull String relativePath) { + LOG.debug("doCopyResource to {}", relativePath); + actions.add(new CopyResourceToRelativePath(relativePath, resourceResolver)); + return this; + } + + public ContentUpgrade doMoveResourceToRelativePath(@Nonnull String relativePath) { + LOG.debug("doMoveResource to {}", relativePath); + actions.add(new MoveResourceToRelativePath(relativePath, resourceResolver)); + return this; + } + + public ContentUpgrade doDeleteResource() { + LOG.debug("doDeleteResource"); + actions.add(new DeleteResource(resourceResolver)); + return this; + } + + /** runner methods **/ public StringBuffer apply() throws PersistenceException { LOG.debug("apply content upgrade"); return apply(false); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java index e9c269ba..d0f637c4 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java @@ -16,6 +16,7 @@ */ package de.valtech.aecu.core.groovy.console.bindings.actions; +import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import javax.annotation.Nonnull; @@ -25,6 +26,6 @@ */ public interface Action { - String doAction(@Nonnull Resource resource); + String doAction(@Nonnull Resource resource) throws PersistenceException; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java deleted file mode 100644 index 8d0a1d28..00000000 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetBooleanProperty.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.valtech.aecu.core.groovy.console.bindings.actions; - -import javax.annotation.Nonnull; - -public class SetBooleanProperty extends SetStringProperty { - - public SetBooleanProperty(@Nonnull String name, Boolean value) { - this.name = name; - this.value = value; - } -} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java deleted file mode 100644 index 3da629d3..00000000 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetIntegerProperty.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.valtech.aecu.core.groovy.console.bindings.actions; - -import javax.annotation.Nonnull; - -public class SetIntegerProperty extends SetStringProperty { - - public SetIntegerProperty(@Nonnull String name, Integer value) { - this.name = name; - this.value = value; - } -} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java new file mode 100644 index 00000000..e7563caa --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.properties; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ValueMap; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class CopyPropertyToRelativePath implements Action { + + private String relativeResourcePath; + private String name; + private ResourceResolver resourceResolver; + + public CopyPropertyToRelativePath(@Nonnull String name, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { + this.name = name; + this.resourceResolver = resourceResolver; + this.relativeResourcePath = relativeResourcePath; + } + + @Override + public String doAction(@Nonnull Resource resource) { + ValueMap sourceProperties = resource.adaptTo(ValueMap.class); + + Resource destinationResource = resourceResolver.getResource(resource, relativeResourcePath); + ModifiableValueMap destinationProperties = destinationResource.adaptTo(ModifiableValueMap.class); + + Object propValue = sourceProperties.get(name); + destinationProperties.put(name, propValue); + + return "Coping property " + name + " from " + resource.getPath() + " to resource " + destinationResource.getPath(); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java similarity index 79% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java index 5a1abdc1..4bc096a0 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RemoveProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java @@ -14,8 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/> */ -package de.valtech.aecu.core.groovy.console.bindings.actions; +package de.valtech.aecu.core.groovy.console.bindings.actions.properties; +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; @@ -24,11 +25,11 @@ /** * @author Roxana Muresan */ -public class RemoveProperty implements Action { +public class DeleteProperty implements Action { private String name; - public RemoveProperty(@Nonnull String name) { + public DeleteProperty(@Nonnull String name) { this.name = name; } @@ -36,6 +37,6 @@ public RemoveProperty(@Nonnull String name) { public String doAction(@Nonnull Resource resource) { ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); properties.remove(name); - return "Removing property " + name + " for resource " + resource.getPath(); + return "Deleting property " + name + " for resource " + resource.getPath(); } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java new file mode 100644 index 00000000..293c6556 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.properties; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class MovePropertyToRelativePath implements Action { + + private String relativeResourcePath; + private String name; + private ResourceResolver resourceResolver; + + public MovePropertyToRelativePath(@Nonnull String name, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { + this.name = name; + this.resourceResolver = resourceResolver; + this.relativeResourcePath = relativeResourcePath; + } + + @Override + public String doAction(@Nonnull Resource resource) { + ModifiableValueMap sourceProperties = resource.adaptTo(ModifiableValueMap.class); + + Resource targetResource = resourceResolver.getResource(resource, relativeResourcePath); + ModifiableValueMap targetProperties = targetResource.adaptTo(ModifiableValueMap.class); + + Object propValue = sourceProperties.get(name); + targetProperties.put(name, propValue); + sourceProperties.remove(name); + + return "Moving property " + name + " from " + resource.getPath() + " to resource " + targetResource.getPath(); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java similarity index 91% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java index 2de91aa8..fdf8834b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/RenameProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java @@ -14,8 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/> */ -package de.valtech.aecu.core.groovy.console.bindings.actions; +package de.valtech.aecu.core.groovy.console.bindings.actions.properties; +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java new file mode 100644 index 00000000..dfb5ca48 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.properties; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class SetBooleanProperty extends SetStringProperty { + + public SetBooleanProperty(@Nonnull String name, Boolean value) { + this.name = name; + this.value = value; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java new file mode 100644 index 00000000..2ef65262 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.properties; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class SetIntegerProperty extends SetStringProperty { + + public SetIntegerProperty(@Nonnull String name, Integer value) { + this.name = name; + this.value = value; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java similarity index 91% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java index c0b00d99..fb1fcd87 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetStringProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java @@ -14,8 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/> */ -package de.valtech.aecu.core.groovy.console.bindings.actions; +package de.valtech.aecu.core.groovy.console.bindings.actions.properties; +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java new file mode 100644 index 00000000..2b876c98 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.resource; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class CopyResourceToRelativePath implements Action { + + private String relativePath; + private ResourceResolver resourceResolver; + + public CopyResourceToRelativePath(@Nonnull String relativePath, @Nonnull ResourceResolver resourceResolver) { + this.relativePath = relativePath; + this.resourceResolver = resourceResolver; + } + + @Override + public String doAction(@Nonnull Resource resource) throws PersistenceException { + Resource destinationResource = resourceResolver.getResource(resource, relativePath); + String sourceAbsPAth = resource.getPath(); + String destinationAsPath = destinationResource.getPath(); + resourceResolver.copy(sourceAbsPAth, destinationAsPath); + + return "Copied " + sourceAbsPAth + " to path " + destinationAsPath; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java new file mode 100644 index 00000000..58bd3c1d --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.resource; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class DeleteResource implements Action { + + private ResourceResolver resourceResolver; + + public DeleteResource(@Nonnull ResourceResolver resourceResolver) { + this.resourceResolver = resourceResolver; + } + + @Override + public String doAction(@Nonnull Resource resource) throws PersistenceException { + String path = resource.getPath(); + resourceResolver.delete(resource); + return "Deleted resource " + path; + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java new file mode 100644 index 00000000..aeb6a219 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.resource; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class MoveResourceToRelativePath implements Action { + + private String relativePath; + private ResourceResolver resourceResolver; + + public MoveResourceToRelativePath(@Nonnull String relativePath, @Nonnull ResourceResolver resourceResolver) { + this.relativePath = relativePath; + this.resourceResolver = resourceResolver; + } + + @Override + public String doAction(@Nonnull Resource resource) throws PersistenceException { + Resource destinationResource = resourceResolver.getResource(resource, relativePath); + String sourceAbsPAth = resource.getPath(); + String destinationAsPath = destinationResource.getPath(); + resourceResolver.move(sourceAbsPAth, destinationAsPath); + + return "Moved " + sourceAbsPAth + " to path " + destinationAsPath; + } +} From ee8445e5cb56946a09986e6dec444f0fc5488cc0 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 6 Jul 2018 17:41:41 +0200 Subject: [PATCH 085/122] bindings/improvements-1: merger left over --- .../bindings/actions/properties/SetStringProperty.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java index 6a3da522..886bf981 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java @@ -21,15 +21,12 @@ */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; -<<<<<<< HEAD:core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java import de.valtech.aecu.core.groovy.console.bindings.actions.Action; -======= -import javax.annotation.Nonnull; - ->>>>>>> 8a3edfd7f429d77f0ea258e43b5fdfb4b1b49a2e:core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/SetProperty.java import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; +import javax.annotation.Nonnull; + /** * @author Roxana Muresan */ From 28689f61be57daa1880a0384f2e3670fd4aec072 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 6 Jul 2018 17:46:29 +0200 Subject: [PATCH 086/122] bindings/improvements-1: added newName to copy and move preoperties --- .../aecu/core/groovy/console/bindings/ContentUpgrade.java | 8 ++++---- .../actions/properties/CopyPropertyToRelativePath.java | 6 ++++-- .../actions/properties/MovePropertyToRelativePath.java | 6 ++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index a7b898b8..8618f8c9 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -100,15 +100,15 @@ public ContentUpgrade doRenameProperty(@Nonnull String oldName, @Nonnull String return this; } - public ContentUpgrade doCopyPropertyToRelativePath(@Nonnull String name, @Nonnull String relativeResourcePath) { + public ContentUpgrade doCopyPropertyToRelativePath(@Nonnull String name, String newName, @Nonnull String relativeResourcePath) { LOG.debug("doCopyProperty: {} to {}", name, relativeResourcePath); - actions.add(new CopyPropertyToRelativePath(name, resourceResolver, relativeResourcePath)); + actions.add(new CopyPropertyToRelativePath(name, newName, resourceResolver, relativeResourcePath)); return this; } - public ContentUpgrade doMovePropertyToRelativePath(@Nonnull String name, @Nonnull String relativeResourcePath) { + public ContentUpgrade doMovePropertyToRelativePath(@Nonnull String name, String newName, @Nonnull String relativeResourcePath) { LOG.debug("doMoveProperty: {} to {}", name, relativeResourcePath); - actions.add(new MovePropertyToRelativePath(name, resourceResolver, relativeResourcePath)); + actions.add(new MovePropertyToRelativePath(name, newName, resourceResolver, relativeResourcePath)); return this; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java index e7563caa..a8e129c8 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java @@ -31,10 +31,12 @@ public class CopyPropertyToRelativePath implements Action { private String relativeResourcePath; private String name; + private String newName; private ResourceResolver resourceResolver; - public CopyPropertyToRelativePath(@Nonnull String name, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { + public CopyPropertyToRelativePath(@Nonnull String name, String newName, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { this.name = name; + this.newName = newName; this.resourceResolver = resourceResolver; this.relativeResourcePath = relativeResourcePath; } @@ -47,7 +49,7 @@ public String doAction(@Nonnull Resource resource) { ModifiableValueMap destinationProperties = destinationResource.adaptTo(ModifiableValueMap.class); Object propValue = sourceProperties.get(name); - destinationProperties.put(name, propValue); + destinationProperties.put((newName != null) ? newName : name, propValue); return "Coping property " + name + " from " + resource.getPath() + " to resource " + destinationResource.getPath(); } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java index 293c6556..e361b5d7 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java @@ -30,10 +30,12 @@ public class MovePropertyToRelativePath implements Action { private String relativeResourcePath; private String name; + private String newName; private ResourceResolver resourceResolver; - public MovePropertyToRelativePath(@Nonnull String name, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { + public MovePropertyToRelativePath(@Nonnull String name, String newName, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { this.name = name; + this.newName = newName; this.resourceResolver = resourceResolver; this.relativeResourcePath = relativeResourcePath; } @@ -46,7 +48,7 @@ public String doAction(@Nonnull Resource resource) { ModifiableValueMap targetProperties = targetResource.adaptTo(ModifiableValueMap.class); Object propValue = sourceProperties.get(name); - targetProperties.put(name, propValue); + targetProperties.put((newName != null) ? newName : name, propValue); sourceProperties.remove(name); return "Moving property " + name + " from " + resource.getPath() + " to resource " + targetResource.getPath(); From b001f6b7f847448779671bc7b5b6b9f71ae76cfd Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 6 Jul 2018 17:50:54 +0200 Subject: [PATCH 087/122] bindings/improvements-1: improved some logs --- .../actions/properties/CopyPropertyToRelativePath.java | 5 +++-- .../actions/properties/MovePropertyToRelativePath.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java index a8e129c8..b40e9f66 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java @@ -49,9 +49,10 @@ public String doAction(@Nonnull Resource resource) { ModifiableValueMap destinationProperties = destinationResource.adaptTo(ModifiableValueMap.class); Object propValue = sourceProperties.get(name); - destinationProperties.put((newName != null) ? newName : name, propValue); + String key = (newName != null) ? newName : name; + destinationProperties.put(key, propValue); - return "Coping property " + name + " from " + resource.getPath() + " to resource " + destinationResource.getPath(); + return "Coping property " + name + " from " + resource.getPath() + " to resource " + destinationResource.getPath() + " as " + key; } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java index e361b5d7..0686231b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java @@ -48,10 +48,11 @@ public String doAction(@Nonnull Resource resource) { ModifiableValueMap targetProperties = targetResource.adaptTo(ModifiableValueMap.class); Object propValue = sourceProperties.get(name); - targetProperties.put((newName != null) ? newName : name, propValue); + String key = (newName != null) ? newName : name; + targetProperties.put(key, propValue); sourceProperties.remove(name); - return "Moving property " + name + " from " + resource.getPath() + " to resource " + targetResource.getPath(); + return "Moving property " + name + " from " + resource.getPath() + " to resource " + targetResource.getPath() + " as " + key; } } From 2ba82a8b20dd122dea49319a24b4400c3f65b944 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Fri, 6 Jul 2018 18:23:28 +0200 Subject: [PATCH 088/122] bindings/improvements-1: added javascript for inserting aecu bindings and imports --- .../aecu/clientlibs/aecu/groovyconsole/.content.xml | 5 +++++ .../valtech/aecu/clientlibs/aecu/groovyconsole/js.txt | 2 ++ .../groovyconsole/js/aecu_groovyconsole_extension.js | 11 +++++++++++ 3 files changed, 18 insertions(+) create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js.txt create mode 100644 ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml new file mode 100644 index 00000000..d8cfcd9a --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" + jcr:primaryType="cq:ClientLibraryFolder" + allowProxy="{Boolean}true" + categories="[groovyconsole]"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js.txt b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js.txt new file mode 100644 index 00000000..86ac4e2a --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js.txt @@ -0,0 +1,2 @@ +#base=js +aecu_groovyconsole_extension.js diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js new file mode 100644 index 00000000..ad9b06ec --- /dev/null +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js @@ -0,0 +1,11 @@ +$(document).ready(function(){ + + if ($("#bindings").length != 0) { + $("#bindings ul").append("<li>aecu - de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate</li>"); // TODO: url to some javadoc available public + } + + if ($("#imports").length != 0) { + $("#imports ul").append("<li>de.valtech.aecu.core.groovy.console.bindings.filters</li>"); // TODO: url to some javadoc available public + } + +}); \ No newline at end of file From 856971a6be7739f70f1932541cdb98eb9ff7d44e Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 9 Jul 2018 15:11:04 +0200 Subject: [PATCH 089/122] added duration --- .../core/model/history/HistoryOverview.java | 71 +++++++++++-------- .../content/history/overview/overview.html | 7 +- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java index daefba74..6a537bd3 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.model.history; @@ -25,6 +22,7 @@ import java.math.MathContext; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.Duration; import javax.annotation.PostConstruct; @@ -48,17 +46,17 @@ */ @Model(adaptables = SlingHttpServletRequest.class) public class HistoryOverview { - + @SlingObject private SlingHttpServletRequest request; - + @SlingObject private ResourceResolver resolver; - + private HistoryEntry historyEntry; - + private final DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); - + /** * Reads the history entry from CRX. */ @@ -76,7 +74,7 @@ public void init() { HistoryUtil historyUtil = new HistoryUtil(); historyEntry = historyUtil.readHistoryEntry(historyResource); } - + /** * Returns the history entry. * @@ -97,7 +95,7 @@ public String getStart() { } return format.format(historyEntry.getStart()); } - + /** * Returns the end as formatted string. * @@ -109,9 +107,23 @@ public String getEnd() { } return format.format(historyEntry.getEnd()); } - + /** - * Returns the percentages of successful and failed scripts. + * Returns the duration. + * + * @return duration + */ + public String getDuration() { + Duration duration = Duration.between(historyEntry.getStart().toInstant(), historyEntry.getEnd().toInstant()); + long seconds = duration.getSeconds(); + if (seconds > 0) { + return duration.getSeconds() + "s"; + } + return (duration.getNano() / 1000000) + "ms"; + } + + /** + * Returns the percentages of successful and failed scripts. * * @return percentages (successful, failed) */ @@ -125,8 +137,7 @@ public Pair<String, String> getPercentages() { for (ExecutionResult result : historyEntry.getSingleResults()) { if (result.isSuccess()) { countOk++; - } - else { + } else { countFailed++; } } @@ -136,5 +147,5 @@ public Pair<String, String> getPercentages() { String valueFailed = percentageFailed.round(new MathContext(2)).toPlainString(); return Pair.of(valueOk, valueFailed); } - + } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html index 2a7f0af4..1cb95f20 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -3,7 +3,7 @@ <h1>Run details</h1> <table class="aecu-history-overview aecu-font-normal" width="100%"> <tr> <td>State: ${cmp.history.state.label}</td> - <td rowspan="4" align="right"> + <td rowspan="5" align="right"> <svg width="150px" height="150px" viewBox="0 0 50 50" class="donut"> <circle class="donut-ring" cx="25" cy="25" r="22" fill="transparent" stroke="grey" stroke-width="0.2"></circle> <circle class="donut-outerring" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="grey" stroke-width="8.5"></circle> @@ -23,9 +23,6 @@ <h1>Run details</h1> <td>Result: ${cmp.history.result.label}</td> </tr> <tr> - <td>Start: ${cmp.start}</td> - </tr> - <tr> - <td>End: ${cmp.end}</td> + <td>Duration: <span title="${cmp.start} - ${cmp.end}">${cmp.duration}</span></td> </tr> </table> From 1baa4f641fe6ccbb3b438efe47602293427200a2 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Mon, 9 Jul 2018 17:30:17 +0200 Subject: [PATCH 090/122] bindings/improvements-1: renamed apply and apllyDry to run and dryRun --- .../core/groovy/console/bindings/ContentUpgrade.java | 11 ++++++----- .../tests_for_simpleContentUpdates.groovy | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index 8618f8c9..fae35f08 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -70,6 +70,7 @@ public ContentUpgrade filterWith(@Nonnull FilterBy filter) { } /** properties edit methods **/ + // TODO test with Object and see type conversion!!! public ContentUpgrade doSetStringProperty(@Nonnull String name, String value) { LOG.debug("doSetStringProperty: {} = {}", name, value); actions.add(new SetStringProperty(name, value)); @@ -132,17 +133,17 @@ public ContentUpgrade doDeleteResource() { } /** runner methods **/ - public StringBuffer apply() throws PersistenceException { + public StringBuffer run() throws PersistenceException { LOG.debug("apply content upgrade"); - return apply(false); + return run(false); } - public StringBuffer applyDry() throws PersistenceException { + public StringBuffer dryRun() throws PersistenceException { LOG.debug("apply content upgrade dry"); - return apply(true); + return run(true); } - private StringBuffer apply(boolean dryRun) throws PersistenceException { + private StringBuffer run(boolean dryRun) throws PersistenceException { StringBuffer stringBuffer = new StringBuffer("Running content upgrade " + (dryRun ? "DRY" : "") + "...\n"); for (TraversData traversal : traversals) { for (Action action : actions) { diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index 6a6d5305..9bcac825 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -20,7 +20,7 @@ println aecu.contentUpgradeBuilder() .doSetIntegerProperty("newStringProperty", 123) .doRenameProperty("newStringProperty", "delete_me_later") // .removeProperty("delete_me_later") - .apply() + .run() @@ -46,4 +46,4 @@ println aecu.contentUpgradeBuilder() .doSetIntegerProperty("newStringProperty", 789) .doRenameProperty("newStringProperty", "delete_me_later") // .removeProperty("delete_me_later") - .apply() \ No newline at end of file + .run() \ No newline at end of file From 363a092287faf681c37e622d0ecc20861552c54b Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 10:29:42 +0200 Subject: [PATCH 091/122] bindings/improvements-1: applied common code formatter --- api/pom.xml | 2 +- .../valtech/aecu/service/AecuException.java | 16 +-- .../de/valtech/aecu/service/AecuService.java | 38 ++--- .../valtech/aecu/service/ExecutionResult.java | 44 +++--- .../de/valtech/aecu/service/HistoryEntry.java | 51 +++---- .../de/valtech/aecu/service/package-info.java | 4 +- bundle/pom.xml | 13 +- core/pom.xml | 10 +- .../console/bindings/ContentUpgrade.java | 34 +++-- .../console/bindings/SimpleContentUpdate.java | 5 +- .../console/bindings/actions/Action.java | 5 +- .../console/bindings/actions/PrintPath.java | 4 +- .../CopyPropertyToRelativePath.java | 5 +- .../actions/properties/DeleteProperty.java | 6 +- .../MovePropertyToRelativePath.java | 1 + .../actions/properties/RenameProperty.java | 6 +- .../actions/properties/SetStringProperty.java | 8 +- .../resource/CopyResourceToRelativePath.java | 1 + .../actions/resource/DeleteResource.java | 1 + .../resource/MoveResourceToRelativePath.java | 1 + .../console/bindings/filters/ANDFilter.java | 4 +- .../console/bindings/filters/FilterBy.java | 4 +- .../bindings/filters/FilterByProperties.java | 4 +- .../console/bindings/filters/NOTFilter.java | 4 +- .../console/bindings/filters/ORFilter.java | 4 +- .../AecuBindingExtensionProvider.java | 8 +- .../AecuStarImportExtensionProvider.java | 5 +- .../traversers/ForChildResourcesOf.java | 6 +- .../traversers/ForDescendantResourcesOf.java | 6 +- .../bindings/traversers/ForResources.java | 5 +- .../bindings/traversers/TraversData.java | 5 +- .../core/healthcheck/LastRunHealthCheck.java | 25 ++-- .../healthcheck/SelfCheckHealthCheck.java | 22 +-- .../aecu/core/history/HistoryUtil.java | 76 +++++----- .../core/installhook/AecuInstallHook.java | 4 +- .../core/installhook/AecuTrackerListener.java | 4 +- .../aecu/core/jmx/AecuServiceMBean.java | 19 ++- .../aecu/core/jmx/AecuServiceMBeanImpl.java | 12 +- .../PurgeHistoryConfiguration.java | 14 +- .../core/maintenance/PurgeHistoryTask.java | 24 ++-- .../core/model/execute/ExecuteDataSource.java | 14 +- .../core/model/history/HistoryDataItem.java | 30 ++-- .../core/model/history/HistoryDataSource.java | 24 ++-- .../core/model/history/HistoryOverview.java | 37 +++-- .../aecu/core/service/AecuServiceImpl.java | 67 ++++----- .../core/service/GroovyConsoleRequest.java | 12 +- .../aecu/core/service/HistoryEntryImpl.java | 28 ++-- .../ServiceResourceResolverService.java | 20 +-- .../aecu/core/servlets/BaseServlet.java | 12 +- .../aecu/core/servlets/ExecutionServlet.java | 36 +++-- .../aecu/core/history/HistoryUtilTest.java | 20 +-- .../core/service/AecuServiceImplTest.java | 26 ++-- examples/pom.xml | 3 +- .../project1/migrations.author/script2.groovy | 3 +- .../tests_for_simpleContentUpdates.groovy | 16 +-- pom.xml | 34 ++--- ui.apps/pom.xml | 3 +- .../src/main/content/jcr_root/_rep_policy.xml | 8 +- .../main/content/jcr_root/apps/.content.xml | 4 +- .../core/content/nav/tools/aecu/.content.xml | 6 +- .../nav/tools/aecu/execute/.content.xml | 10 +- .../nav/tools/aecu/history/.content.xml | 10 +- .../jcr_root/apps/settings/.content.xml | 2 +- .../apps/settings/granite/.content.xml | 2 +- .../settings/granite/operations/.content.xml | 2 +- .../granite/operations/hc/.content.xml | 2 +- .../granite/operations/hc/aecu/.content.xml | 6 +- .../operations/maintenance/.content.xml | 6 +- .../maintenance/granite_weekly/.content.xml | 6 +- .../aecu_history_purge/.content.xml | 8 +- .../aecu/clientlibs/aecu.editor/.content.xml | 8 +- .../aecu/clientlibs/aecu.editor/css/aecu.css | 44 +++--- .../clientlibs/aecu.editor/js/constants.js | 56 ++++---- .../clientlibs/aecu.editor/js/executor.js | 134 +++++++++--------- .../aecu/clientlibs/aecu.editor/js/history.js | 68 ++++----- .../aecu.editor/js/requestHandler.js | 15 +- .../aecu/clientlibs/aecu.editor/js/utils.js | 5 +- .../aecu/groovyconsole/.content.xml | 6 +- .../js/aecu_groovyconsole_extension.js | 12 +- .../executionResults/executionResults.html | 46 +++--- .../templates/executionResult.html | 59 ++++---- .../content/history/overview/.content.xml | 2 +- .../content/history/overview/overview.html | 61 ++++---- .../apps/valtech/aecu/tools/.content.xml | 7 +- .../aecu/tools/execute/dataitem/dataitem.html | 6 +- .../tools/execute/datasource/datasource.html | 2 +- .../aecu/tools/execute/page/.content.xml | 95 +++++++------ .../aecu/tools/history/dataitem/dataitem.html | 11 +- .../tools/history/datasource/datasource.html | 2 +- .../aecu/tools/history/details/.content.xml | 72 +++++----- .../aecu/tools/history/page/.content.xml | 116 +++++++-------- .../content/jcr_root/content/_rep_policy.xml | 8 +- .../groovyconsole/scripts/aecu/.content.xml | 2 +- .../home/users/system/aecu/.content.xml | 2 +- .../aecu/aecu-content-migrator/.content.xml | 8 +- .../system/aecu/aecu-service/.content.xml | 8 +- .../content/jcr_root/var/aecu/.content.xml | 2 +- .../content/jcr_root/var/aecu/_rep_policy.xml | 8 +- 98 files changed, 939 insertions(+), 893 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index d0729cdf..1193be53 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <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"> + 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> <parent> <groupId>de.valtech.aecu</groupId> diff --git a/api/src/main/java/de/valtech/aecu/service/AecuException.java b/api/src/main/java/de/valtech/aecu/service/AecuException.java index dc3128d6..b6b72b20 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuException.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuException.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,7 +23,7 @@ /** * Thrown when the AECU service faces an error. - * + * * @author Roland Gruber */ public class AecuException extends Exception { @@ -32,21 +32,21 @@ public class AecuException extends Exception { /** * Constructor - * + * * @param message error message - * @param e original exception + * @param e original exception */ public AecuException(String message, Throwable e) { super(message, e); } - + /** * Constructor - * + * * @param message error message */ public AecuException(String message) { super(message); } - + } diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 1f9910d6..5a18dbfc 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -27,69 +27,69 @@ /** * Service interface for AECU. - * + * * @author Roland Gruber */ @ProviderType public interface AecuService { - + /** * Returns the AECU version. - * + * * @return version */ String getVersion(); - + /** * Returns a list of files that can be executed in the given path. - * + * * @param path file or folder * @return list of files that are executable * @throws AecuException error finding files (e.g. invalid path) */ List<String> getFiles(String path) throws AecuException; - + /** * Executes the script at the given position. - * + * * @param path path of script * @return execution result * @throws AecuException error during execution */ ExecutionResult execute(String path) throws AecuException; - + /** * Starts a new history entry. - * + * * @return history entry * @throws AecuException error setting up entry */ HistoryEntry createHistoryEntry() throws AecuException; - + /** * Stores an execution run in existing history. - * + * * @param history history entry - * @param result script execution result + * @param result script execution result * @return updated history * @throws AecuException error inserting history entry */ HistoryEntry storeExecutionInHistory(HistoryEntry history, ExecutionResult result) throws AecuException; - + /** * Finishes the history entry. - * + * * @param history open history entry * @return history entry * @throws AecuException error saving state */ HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuException; - + /** * Returns the last history entries. The search starts at the newest entry. - * + * * @param startIndex start reading at this index (first is 0) - * @param count number of entries to read + * @param count number of entries to read * @return history entries (newest first) * @throws AecuException error reading history */ diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java index 8940df7e..1f1d0b73 100644 --- a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,7 +25,7 @@ /** * Result of a script execution. - * + * * @author Roland Gruber */ public class ExecutionResult { @@ -36,16 +36,16 @@ public class ExecutionResult { private String result; private ExecutionResult fallbackResult; private String path; - + /** * Constructor - * - * @param success execution was successful - * @param time execution time - * @param result result - * @param output script output + * + * @param success execution was successful + * @param time execution time + * @param result result + * @param output script output * @param fallbackResult fallback script result - * @param path script path + * @param path script path */ public ExecutionResult(boolean success, String time, String result, String output, ExecutionResult fallbackResult, String path) { this.success = success; @@ -55,10 +55,10 @@ public ExecutionResult(boolean success, String time, String result, String outpu this.fallbackResult = fallbackResult; this.path = path; } - + /** * Returns if execution was successful. - * + * * @return successful */ public boolean isSuccess() { @@ -67,25 +67,25 @@ public boolean isSuccess() { /** * Returns the script result. - * + * * @return output */ public String getResult() { return result; } - + /** * Returns the script output. - * + * * @return output */ public String getOutput() { return output; } - + /** * Returns the execution time. - * + * * @return time */ public String getTime() { @@ -94,16 +94,16 @@ public String getTime() { /** * Returns the fallback script result if any. - * + * * @return result */ public ExecutionResult getFallbackResult() { return fallbackResult; } - + /** * Returns the script path. - * + * * @return path */ public String getPath() { @@ -113,8 +113,8 @@ public String getPath() { @Override public String toString() { StringBuilder stringVal = new StringBuilder( - "Successful: " + Boolean.toString(success) + - "Path: " + path + "Successful: " + Boolean.toString(success) + + "Path: " + path ); if (StringUtils.isNotBlank(time)) { stringVal.append("\n" + "Execution time: " + time); diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java index 5c6307d1..9f8a92bb 100644 --- a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -26,30 +26,31 @@ /** * History entry for an execution run. - * - * @author Roland Gruber * + * @author Roland Gruber */ public interface HistoryEntry { - + /** * Execution state (e.g. running) */ public enum STATE { RUNNING("Running"), FINISHED("Finished"); - + private String label; private STATE(String label) { this.label = label; } - + public String getLabel() { return label; } - }; - + } + + ; + /** * Execution result (e.g. successful) */ @@ -63,52 +64,54 @@ public enum RESULT { private RESULT(String label) { this.label = label; } - + public String getLabel() { return label; } - }; - + } + + ; + /** * Returns the start time of the execution. - * + * * @return start */ Date getStart(); - + /** * Returns the end time of the execution. - * + * * @return end */ Date getEnd(); - + /** * Returns the single script runs. - * + * * @return single results */ List<ExecutionResult> getSingleResults(); - + /** * Returns the current state of the run. - * + * * @return state */ STATE getState(); - + /** * Returns the global result of the run. - * + * * @return result */ RESULT getResult(); - + /** * Returns the path in repository where the history is stored. - * + * * @return path */ String getRepositoryPath(); - + } diff --git a/api/src/main/java/de/valtech/aecu/service/package-info.java b/api/src/main/java/de/valtech/aecu/service/package-info.java index 747a9ee6..f7400584 100644 --- a/api/src/main/java/de/valtech/aecu/service/package-info.java +++ b/api/src/main/java/de/valtech/aecu/service/package-info.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/bundle/pom.xml b/bundle/pom.xml index a1eaa12a..c9bb9653 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -57,8 +58,8 @@ <group>Valtech</group> <subPackages> <subPackage> - <groupId>com.icfolson.aem.groovy.console</groupId> - <artifactId>aem-groovy-console</artifactId> + <groupId>com.icfolson.aem.groovy.console</groupId> + <artifactId>aem-groovy-console</artifactId> </subPackage> </subPackages> </configuration> @@ -73,9 +74,9 @@ <dependencies> <dependency> - <groupId>com.icfolson.aem.groovy.console</groupId> - <artifactId>aem-groovy-console</artifactId> - <type>zip</type> + <groupId>com.icfolson.aem.groovy.console</groupId> + <artifactId>aem-groovy-console</artifactId> + <type>zip</type> </dependency> </dependencies> </project> diff --git a/core/pom.xml b/core/pom.xml index 0ae50f4f..c39cb8a5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <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"> + 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> <parent> <groupId>de.valtech.aecu</groupId> @@ -85,10 +85,10 @@ <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.models.api</artifactId> </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index fae35f08..514f7a02 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -1,7 +1,13 @@ package de.valtech.aecu.core.groovy.console.bindings; -import de.valtech.aecu.core.groovy.console.bindings.actions.*; -import de.valtech.aecu.core.groovy.console.bindings.actions.properties.*; +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.CopyPropertyToRelativePath; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.DeleteProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.MovePropertyToRelativePath; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.RenameProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.SetBooleanProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.SetIntegerProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.SetStringProperty; import de.valtech.aecu.core.groovy.console.bindings.actions.resource.CopyResourceToRelativePath; import de.valtech.aecu.core.groovy.console.bindings.actions.resource.DeleteResource; import de.valtech.aecu.core.groovy.console.bindings.actions.resource.MoveResourceToRelativePath; @@ -11,17 +17,19 @@ import de.valtech.aecu.core.groovy.console.bindings.traversers.ForDescendantResourcesOf; import de.valtech.aecu.core.groovy.console.bindings.traversers.ForResources; import de.valtech.aecu.core.groovy.console.bindings.traversers.TraversData; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.ResourceResolver; import org.scribe.utils.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; + public class ContentUpgrade { private static Logger LOG = LoggerFactory.getLogger(ContentUpgrade.class); @@ -37,7 +45,9 @@ public ContentUpgrade(@Nonnull ResourceResolver resourceResolver) { this.resourceResolver = resourceResolver; } - /** content path filter methods **/ + /** + * content path filter methods + **/ public ContentUpgrade forResources(@Nonnull String[] paths) { LOG.debug("forResources: {}", paths.toString()); traversals.add(new ForResources(paths)); @@ -56,7 +66,9 @@ public ContentUpgrade forDescendantResourcesOf(@Nonnull String path) { return this; } - /** filters **/ + /** + * filters + **/ public ContentUpgrade filterByProperties(@Nonnull Map<String, String> conditionProperties) { LOG.debug("filterByProperties: {}", MapUtils.toString(conditionProperties)); filter = new FilterByProperties(conditionProperties); @@ -69,7 +81,9 @@ public ContentUpgrade filterWith(@Nonnull FilterBy filter) { return this; } - /** properties edit methods **/ + /** + * properties edit methods + **/ // TODO test with Object and see type conversion!!! public ContentUpgrade doSetStringProperty(@Nonnull String name, String value) { LOG.debug("doSetStringProperty: {} = {}", name, value); @@ -113,7 +127,9 @@ public ContentUpgrade doMovePropertyToRelativePath(@Nonnull String name, String return this; } - /** resource edit methods **/ + /** + * resource edit methods + **/ public ContentUpgrade doCopyResourceToRelativePath(@Nonnull String relativePath) { LOG.debug("doCopyResource to {}", relativePath); actions.add(new CopyResourceToRelativePath(relativePath, resourceResolver)); @@ -132,7 +148,9 @@ public ContentUpgrade doDeleteResource() { return this; } - /** runner methods **/ + /** + * runner methods + **/ public StringBuffer run() throws PersistenceException { LOG.debug("apply content upgrade"); return run(false); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 3206d9b8..7e73c37e 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,6 +25,7 @@ /** * Groovy Console Bindings: Simple Content Update + * * @author Roxana Muresan */ public class SimpleContentUpdate { diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java index e9157b9b..fc39d038 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,6 +23,7 @@ import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; + import javax.annotation.Nonnull; /** diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java index af9a4f2e..b805d457 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java index b40e9f66..93971dd4 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java @@ -17,6 +17,7 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; @@ -45,8 +46,8 @@ public CopyPropertyToRelativePath(@Nonnull String name, String newName, @Nonnull public String doAction(@Nonnull Resource resource) { ValueMap sourceProperties = resource.adaptTo(ValueMap.class); - Resource destinationResource = resourceResolver.getResource(resource, relativeResourcePath); - ModifiableValueMap destinationProperties = destinationResource.adaptTo(ModifiableValueMap.class); + Resource destinationResource = resourceResolver.getResource(resource, relativeResourcePath);// TODO null check!!!! + ModifiableValueMap destinationProperties = destinationResource.adaptTo(ModifiableValueMap.class);// TODO null check!!!! Object propValue = sourceProperties.get(name); String key = (newName != null) ? newName : name; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java index c6f3135c..748acecb 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -22,7 +22,9 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import javax.annotation.Nonnull; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java index 0686231b..f1bba661 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java @@ -17,6 +17,7 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java index 84ee3605..4141aa3b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -22,7 +22,9 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import javax.annotation.Nonnull; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java index 886bf981..e2335756 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -22,6 +22,7 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import org.apache.sling.api.resource.ModifiableValueMap; import org.apache.sling.api.resource.Resource; @@ -35,7 +36,8 @@ public class SetStringProperty implements Action { protected String name; protected Object value; - protected SetStringProperty() {} + protected SetStringProperty() { + } public SetStringProperty(@Nonnull String name, String value) { this.name = name; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java index 2b876c98..84a4623e 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java @@ -17,6 +17,7 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java index 58bd3c1d..d2a672c8 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java @@ -17,6 +17,7 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java index aeb6a219..0b7d3eb6 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java @@ -17,6 +17,7 @@ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java index a4d9fc6d..3c847dd5 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java index 82a62357..f893aa49 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java index f7aed48f..b486136b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java index 7924c67b..fae3a298 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java index 5777e4ad..34dd09c5 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java index 8482e0ef..e860f92c 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -22,9 +22,12 @@ package de.valtech.aecu.core.groovy.console.bindings.provider; import com.icfolson.aem.groovy.console.api.BindingExtensionProvider; + import de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate; import de.valtech.aecu.core.serviceuser.ServiceResourceResolverService; + import groovy.lang.Binding; + import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.LoginException; import org.osgi.service.component.annotations.Component; @@ -34,6 +37,7 @@ /** * Provides additional AECU Bindings for the Groovy Console + * * @author Roxana Muresan */ @Component(immediate = true) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java index 81e32a64..8b7e2b07 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,6 +23,7 @@ import com.icfolson.aem.groovy.console.api.StarImportExtensionProvider; import com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants; + import org.osgi.service.component.annotations.Component; import java.util.Set; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java index 78f83750..be871479 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,11 +23,13 @@ import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import javax.annotation.Nonnull; + import java.util.Iterator; /** diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java index 2bd9306e..a31e3165 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,11 +23,13 @@ import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import javax.annotation.Nonnull; + import java.util.Iterator; /** diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java index c50eefbb..e22bb5fe 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,6 +23,7 @@ import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java index 45942155..0bb0fa8a 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -23,6 +23,7 @@ import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; + import org.apache.sling.api.resource.PersistenceException; import org.apache.sling.api.resource.ResourceResolver; diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java index cff8744f..daee91ed 100644 --- a/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -35,20 +35,20 @@ /** * Checks if the last script run was ok. - * + * * @author Roland Gruber */ @Component( - immediate = true, - service = HealthCheck.class, - property = { - HealthCheck.TAGS + "=aecu", - HealthCheck.NAME + "=AECU Last Run", - HealthCheck.MBEAN_NAME + "=aecuLastRunHCmBean" - } + immediate = true, + service = HealthCheck.class, + property = { + HealthCheck.TAGS + "=aecu", + HealthCheck.NAME + "=AECU Last Run", + HealthCheck.MBEAN_NAME + "=aecuLastRunHCmBean" + } ) public class LastRunHealthCheck implements HealthCheck { - + @Reference private AecuService aecuService; @@ -59,8 +59,7 @@ public Result execute() { List<HistoryEntry> history = aecuService.getHistory(0, 1); if (history.isEmpty()) { resultLog.info("No runs found"); - } - else { + } else { HistoryEntry entry = history.get(0); switch (entry.getResult()) { case FAILURE: diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java index ddc85b4e..baf9728e 100644 --- a/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -33,20 +33,20 @@ /** * Checks if the internal service user is ok. - * + * * @author Roland Gruber */ @Component( - immediate = true, - service = HealthCheck.class, - property = { - HealthCheck.TAGS + "=aecu", - HealthCheck.NAME + "=AECU Self Check", - HealthCheck.MBEAN_NAME + "=aecuSelfCheckHCmBean" - } + immediate = true, + service = HealthCheck.class, + property = { + HealthCheck.TAGS + "=aecu", + HealthCheck.NAME + "=AECU Self Check", + HealthCheck.MBEAN_NAME + "=aecuSelfCheckHCmBean" + } ) public class SelfCheckHealthCheck implements HealthCheck { - + @Reference private ServiceResourceResolverService resolverService; diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index 06c6c83b..b6124e58 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -53,11 +53,11 @@ /** * Reads and writes history entries. - * + * * @author Roland Gruber */ public class HistoryUtil { - + private static final Logger LOG = LoggerFactory.getLogger(HistoryUtil.class); private static final String HISTORY_BASE = "/var/aecu"; @@ -76,7 +76,7 @@ public class HistoryUtil { /** * Starts a new history entry. - * + * * @param resolver resource resolver * @return history entry * @throws AecuException error setting up entry @@ -102,9 +102,9 @@ public HistoryEntry createHistoryEntry(ResourceResolver resolver) throws AecuExc /** * Stores an execution run in existing history. - * - * @param history history entry - * @param result script execution result + * + * @param history history entry + * @param result script execution result * @param resolver resource resolver * @throws AecuException error inserting history entry */ @@ -115,8 +115,8 @@ public void storeExecutionInHistory(HistoryEntry history, ExecutionResult result /** * Finishes the history entry. - * - * @param history open history entry + * + * @param history open history entry * @param resolver resource resolver * @return history entry */ @@ -133,10 +133,10 @@ public void finishHistoryEntry(HistoryEntry history, ResourceResolver resolver) /** * Returns the last history entries. The search starts at the newest entry. - * + * * @param startIndex start reading at this index (first is 0) - * @param count number of entries to read - * @param resolver resource resolver + * @param count number of entries to read + * @param resolver resource resolver * @return history entries (newest first) */ public List<HistoryEntry> getHistory(int startIndex, int count, ResourceResolver resolver) { @@ -165,8 +165,8 @@ public List<HistoryEntry> getHistory(int startIndex, int count, ResourceResolver /** * Returns the run before the given one. - * - * @param current current run + * + * @param current current run * @return previous run */ private Resource getPreviousHistoryEntry(Resource current) { @@ -180,10 +180,10 @@ private Resource getPreviousHistoryEntry(Resource current) { // go back up the folders return ascendToLastRun(base); } - + /** * Gos up the folders to last run. - * + * * @param resource current node * @return last run */ @@ -206,7 +206,7 @@ private Resource ascendToLastRun(Resource resource) { /** * Descends in history till a previous sibling is found. * Descending stops at history base level - * + * * @param current current resource * @return previous sibling */ @@ -224,7 +224,7 @@ private Resource descendToPreviousSiblingInHistory(Resource current) { /** * Returns the previous sibling of the given node. - * + * * @param resource current node * @return last sibling or null */ @@ -245,7 +245,7 @@ private Resource getPreviousSibling(Resource resource) { /** * Returns the latest history entry. - * + * * @param base base resource * @return latest run resource */ @@ -255,10 +255,10 @@ private Resource getLatestHistoryEntry(Resource base) { } return ascendToLastRun(base); } - + /** * Returns the last child of the given resource. - * + * * @param resource resource * @return last child */ @@ -276,10 +276,10 @@ private Resource getLastChild(Resource resource) { } return last; } - + /** * Reads a history entry from JCR. - * + * * @param resource history resource * @return history entry */ @@ -305,7 +305,7 @@ public HistoryEntry readHistoryEntry(Resource resource) { /** * Reads a single script run from history. - * + * * @param resource resource * @return result */ @@ -348,9 +348,9 @@ private void saveExecutionResultInHistory(ExecutionResult result, String path, R /** * Creates the folder at the given path if not yet existing. - * - * @param path path - * @param resolver resource resolver + * + * @param path path + * @param resolver resource resolver * @param primaryType primary type * @throws AecuException error creating folder */ @@ -374,7 +374,7 @@ protected void createPath(String path, ResourceResolver resolver, String primary /** * Generates the node name for a history entry. - * + * * @return name */ private String generateHistoryNodeName() { @@ -384,8 +384,8 @@ private String generateHistoryNodeName() { /** * Purges the history by keeping only entries within the set number of days. - * - * @param resolver resource resolver + * + * @param resolver resource resolver * @param daysToKeep number of days to keep * @throws PersistenceException error deleting node */ @@ -394,15 +394,15 @@ public void purgeHistory(ResourceResolver resolver, int daysToKeep) throws Persi Calendar calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_MONTH, -daysToKeep); LOG.debug("Starting purge with limit " + calendar.getTime().toString()); - deleteRecursive(base.listChildren(), calendar, new int[] {Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH}); + deleteRecursive(base.listChildren(), calendar, new int[]{Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH}); } /** * Deletes the year resources that are too old. - * + * * @param resources resources - * @param calendar time limit - * @param fields calendar fields + * @param calendar time limit + * @param fields calendar fields * @throws PersistenceException error deleting node */ private void deleteRecursive(Iterator<Resource> resources, Calendar calendar, int[] fields) throws PersistenceException { @@ -423,8 +423,7 @@ private void deleteRecursive(Iterator<Resource> resources, Calendar calendar, in } if (nodeValue > limit) { LOG.debug("Skipping purge of too young node: " + resource.getPath()); - } - else if (nodeValue == limit) { + } else if (nodeValue == limit) { LOG.debug("Skipping purge of too young node: " + resource.getPath()); // check next level if (fields.length == 1) { @@ -433,8 +432,7 @@ else if (nodeValue == limit) { int[] fieldsNew = new int[fields.length - 1]; System.arraycopy(fields, 1, fieldsNew, 0, fieldsNew.length); deleteRecursive(resource.listChildren(), calendar, fieldsNew); - } - else { + } else { LOG.debug("Purging node: " + resource.getPath()); BatchResourceRemover remover = ResourceUtil.getBatchResourceRemover(1000); remover.delete(resource); diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java index de6b8c30..58d9f886 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java index 97969d6e..4618139e 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index e79e7545..1938a9fb 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -30,7 +30,7 @@ /** * JMX service interface. - * + * * @author Roland Gruber */ @Description("AEM Easy Content Upgrade") @@ -38,15 +38,15 @@ public interface AecuServiceMBean { /** * Returns the AECU version. - * + * * @return version */ @Description("Version") public String getVersion(); - + /** * Returns a list of files that can be executed in the given path. - * + * * @param path file or folder * @return list of files that are executable * @throws AecuException error finding files (e.g. invalid path) @@ -56,7 +56,7 @@ public interface AecuServiceMBean { /** * Executes the script at the given position. - * + * * @param path path of script * @return execution result * @throws AecuException error during execution @@ -66,13 +66,12 @@ public interface AecuServiceMBean { /** * Returns history entries. - * + * * @param start start index (0 is last run) * @param count number of entries to return * @return history entries - * @throws AecuException */ @Description("Returns the last history entries") String getHistory(@Name("Start index") int start, @Name("Count") int count) throws AecuException; - + } diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index ea81ca34..68ed516d 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -36,18 +36,16 @@ import de.valtech.aecu.service.HistoryEntry; @Component(service = {AecuServiceMBean.class}, immediate = true, property = { - "jmx.objectname=de.valtech:type=AECU", - "pattern=/.*" + "jmx.objectname=de.valtech:type=AECU", + "pattern=/.*" }) public class AecuServiceMBeanImpl extends AnnotatedStandardMBean implements AecuServiceMBean { - + @Reference AecuService aecuService; /** * Constructor - * - * @throws NotCompliantMBeanException */ public AecuServiceMBeanImpl() throws NotCompliantMBeanException { super(AecuServiceMBean.class); diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java index 69e331c3..4c81496e 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -27,17 +27,17 @@ /** * Configuration for purge task. - * + * * @author Roland Gruber */ @ObjectClassDefinition(name = "AECU Purge history configuration") public @interface PurgeHistoryConfiguration { @AttributeDefinition( - type = AttributeType.INTEGER, - name = "Days to keep", - description = "Entries younger than this will not be removed" + type = AttributeType.INTEGER, + name = "Days to keep", + description = "Entries younger than this will not be removed" ) int daysToKeep(); - + } diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java index f7beecf8..29a838e5 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -40,27 +40,27 @@ /** * Purges old entries from the history. - * + * * @author Roland Gruber */ @Component( - property = { - MaintenanceConstants.PROPERTY_TASK_NAME + "=AECUPurgeHistory", - MaintenanceConstants.PROPERTY_TASK_TITLE + "=AECU Purge History", - JobExecutor.PROPERTY_TOPICS + "=" + MaintenanceConstants.TASK_TOPIC_PREFIX + "AECUPurgeHistory", - } + property = { + MaintenanceConstants.PROPERTY_TASK_NAME + "=AECUPurgeHistory", + MaintenanceConstants.PROPERTY_TASK_TITLE + "=AECU Purge History", + JobExecutor.PROPERTY_TOPICS + "=" + MaintenanceConstants.TASK_TOPIC_PREFIX + "AECUPurgeHistory", + } ) @Designate(ocd = PurgeHistoryConfiguration.class) public class PurgeHistoryTask implements JobExecutor { - + private PurgeHistoryConfiguration config; - + @Reference private ServiceResourceResolverService resolverService; - + /** * Activates the service. - * + * * @param config configuration */ @Activate diff --git a/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java index 508dc3f7..da15dbac 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java +++ b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -28,8 +28,10 @@ import javax.inject.Inject; import com.adobe.granite.ui.components.ds.ValueMapResource; + import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; + import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; @@ -46,7 +48,7 @@ * * @author Bryan Chavez */ -@Model(adaptables=SlingHttpServletRequest.class) +@Model(adaptables = SlingHttpServletRequest.class) public class ExecuteDataSource { private static final String ITEM_TYPE = "valtech/aecu/tools/execute/dataitem"; @@ -59,15 +61,15 @@ public class ExecuteDataSource { private AecuService aecuService; @PostConstruct - public void setup() throws AecuException{ + public void setup() throws AecuException { String path = request.getParameter("searchPath"); List<Resource> entries = new ArrayList<>(); - if(path!=null && StringUtils.isNotEmpty(path) && path.startsWith(ALLOWED_PATH)){ + if (path != null && StringUtils.isNotEmpty(path) && path.startsWith(ALLOWED_PATH)) { List<String> allowedScripts = aecuService.getFiles(path); ResourceResolver resourceResolver = request.getResourceResolver(); - for(String scriptPath : allowedScripts){ + for (String scriptPath : allowedScripts) { entries.add(new ValueMapResource(resourceResolver, scriptPath, ITEM_TYPE, null)); } } diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java index 1337c2cb..9612414c 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -38,36 +38,36 @@ /** * Model class for a single history item. - * + * * @author Roland Gruber */ @Model(adaptables = Resource.class) public class HistoryDataItem { - + private final DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); - + @SlingObject private Resource resource; - + private HistoryEntry history = null; - + @PostConstruct public void setup() { history = resource.adaptTo(ValueMap.class).get(HistoryDataSource.ATTR_HISTORY, HistoryEntry.class); } - + /** * Returns the date of the run. - * + * * @return date */ public String getDate() { return format.format(history.getEnd()); } - + /** * Returns the duration of the run. - * + * * @return duration */ public String getDuration() { @@ -81,10 +81,10 @@ public String getDuration() { } return (duration.getNano() / 1000000) + "ms"; } - + /** * Returns the status icon of the run. - * + * * @return icon */ public String getStatusIcon() { @@ -99,7 +99,7 @@ public String getStatusIcon() { /** * Returns the status color of the run. - * + * * @return icon */ public String getStatusColor() { @@ -114,7 +114,7 @@ public String getStatusColor() { /** * Returns the path of the run. - * + * * @return path */ public String getPath() { diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java index 393df55b..fab84ad3 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -48,23 +48,23 @@ /** * Datasource model for history overview page. - * + * * @author Roland Gruber */ -@Model(adaptables=SlingHttpServletRequest.class) +@Model(adaptables = SlingHttpServletRequest.class) public class HistoryDataSource { - + private static final String ITEM_TYPE = "valtech/aecu/tools/history/dataitem"; public static final String ATTR_HISTORY = "history"; private Logger LOG = LoggerFactory.getLogger(DataSource.class); - + @SlingObject SlingHttpServletRequest request; - + @OSGiService AecuService aecuService; - + @PostConstruct public void setup() { String[] selectors = request.getRequestPathInfo().getSelectors(); @@ -79,14 +79,14 @@ public void setup() { /** * Returns the history entries. - * + * * @param offset offset where to start reading - * @param limit maximum number of entries to return + * @param limit maximum number of entries to return * @return entries */ private DataSource getResourceIterator(int offset, int limit) { return new AbstractDataSource() { - + @Override public Iterator<Resource> iterator() { List<Resource> entries = new ArrayList<>(); @@ -102,7 +102,7 @@ public Iterator<Resource> iterator() { } return entries.iterator(); } - + }; } diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java index daefba74..f5a347f2 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -43,22 +43,22 @@ /** * Sling model for history overview area. - * + * * @author Roland Gruber */ @Model(adaptables = SlingHttpServletRequest.class) public class HistoryOverview { - + @SlingObject private SlingHttpServletRequest request; - + @SlingObject private ResourceResolver resolver; - + private HistoryEntry historyEntry; - + private final DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss"); - + /** * Reads the history entry from CRX. */ @@ -76,10 +76,10 @@ public void init() { HistoryUtil historyUtil = new HistoryUtil(); historyEntry = historyUtil.readHistoryEntry(historyResource); } - + /** * Returns the history entry. - * + * * @return history */ public HistoryEntry getHistory() { @@ -88,7 +88,7 @@ public HistoryEntry getHistory() { /** * Returns the start as formatted string. - * + * * @return start date */ public String getStart() { @@ -97,10 +97,10 @@ public String getStart() { } return format.format(historyEntry.getStart()); } - + /** * Returns the end as formatted string. - * + * * @return end date */ public String getEnd() { @@ -109,10 +109,10 @@ public String getEnd() { } return format.format(historyEntry.getEnd()); } - + /** - * Returns the percentages of successful and failed scripts. - * + * Returns the percentages of successful and failed scripts. + * * @return percentages (successful, failed) */ public Pair<String, String> getPercentages() { @@ -125,8 +125,7 @@ public Pair<String, String> getPercentages() { for (ExecutionResult result : historyEntry.getSingleResults()) { if (result.isSuccess()) { countOk++; - } - else { + } else { countFailed++; } } @@ -136,5 +135,5 @@ public Pair<String, String> getPercentages() { String valueFailed = percentageFailed.round(new MathContext(2)).toPlainString(); return Pair.of(valueOk, valueFailed); } - + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index f9c6c766..ac393296 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -51,18 +51,18 @@ /** * AECU service. - * + * * @author Roland Gruber */ -@Component(service=AecuService.class) +@Component(service = AecuService.class) public class AecuServiceImpl implements AecuService { @Reference private ServiceResourceResolverService resolverService; - + @Reference private SlingSettingsService slingSettings; - + @Reference private GroovyConsoleService groovyConsoleService; @@ -75,17 +75,16 @@ public String getVersion() { public List<String> getFiles(String path) throws AecuException { try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { return findCandidates(resolver, path); - } - catch (LoginException e) { + } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); } } /** * Finds all candidates for scripts to run. - * + * * @param resolver service resource resolver - * @param path starting path + * @param path starting path * @return candidate list * @throws AecuException error finding candidates */ @@ -102,8 +101,7 @@ private List<String> findCandidates(ResourceResolver resolver, String path) thro for (Resource child : resource.getChildren()) { candidates.addAll(findCandidates(resolver, child.getPath())); } - } - else if (isValidScriptName(resource.getName())) { + } else if (isValidScriptName(resource.getName())) { candidates.add(path); } return candidates; @@ -111,20 +109,20 @@ else if (isValidScriptName(resource.getName())) { /** * Checks if the resource is a folder. - * + * * @param resource resource * @return is folder */ private boolean isFolder(Resource resource) { String type = resource.getValueMap().get(JcrConstants.JCR_PRIMARYTYPE, String.class); return JcrResourceConstants.NT_SLING_FOLDER.equals(type) - || JcrResourceConstants.NT_SLING_ORDERED_FOLDER.equals(type) - || JcrConstants.NT_FOLDER.equals(type); + || JcrResourceConstants.NT_SLING_ORDERED_FOLDER.equals(type) + || JcrConstants.NT_FOLDER.equals(type); } /** * Checks if the folder matches the system's run modes if specified in folder name. - * + * * @param name resource name * @return matches run modes */ @@ -146,7 +144,7 @@ protected boolean matchesRunmodes(String name) { /** * Checks if the name is a valid script. - * + * * @param name file name * @return is valid */ @@ -172,17 +170,16 @@ public ExecutionResult execute(String path) throws AecuException { } ExecutionResult result = executeScript(resolver, path); return result; - } - catch (LoginException e) { + } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); } } /** * Executes the script. - * + * * @param resolver resource resolver - * @param path path + * @param path path * @return result */ private ExecutionResult executeScript(ResourceResolver resolver, String path) { @@ -196,12 +193,12 @@ private ExecutionResult executeScript(ResourceResolver resolver, String path) { } return new ExecutionResult(success, response.getRunningTime(), result, response.getOutput() + response.getExceptionStackTrace(), fallbackResult, path); } - + /** * Returns the fallback script name if any exists. - * + * * @param resolver resource resolver - * @param path original script path + * @param path original script path * @return fallback script path */ protected String getFallbackScript(ResourceResolver resolver, String path) { @@ -227,8 +224,7 @@ public HistoryEntry createHistoryEntry() throws AecuException { return entry; } catch (PersistenceException e) { throw new AecuException("Unable to create history", e); - } - catch (LoginException e) { + } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); } } @@ -240,11 +236,9 @@ public HistoryEntry finishHistoryEntry(HistoryEntry history) throws AecuExceptio historyUtil.finishHistoryEntry(history, resolver); resolver.commit(); return history; - } - catch (LoginException e) { + } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); - } - catch (PersistenceException e) { + } catch (PersistenceException e) { throw new AecuException("Unable to finish history " + history.getRepositoryPath(), e); } } @@ -260,24 +254,21 @@ public HistoryEntry storeExecutionInHistory(HistoryEntry history, ExecutionResul historyUtil.storeExecutionInHistory(history, result, resolver); resolver.commit(); return history; - } - catch (LoginException e) { + } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); - } - catch (PersistenceException e) { + } catch (PersistenceException e) { throw new AecuException("Unable to add history entry " + history.getRepositoryPath(), e); } } - + @Override public List<HistoryEntry> getHistory(int startIndex, int count) throws AecuException { try (ResourceResolver resolver = resolverService.getServiceResourceResolver()) { HistoryUtil historyUtil = new HistoryUtil(); return historyUtil.getHistory(startIndex, count, resolver); - } - catch (LoginException e) { + } catch (LoginException e) { throw new AecuException("Unable to get service resource resolver", e); } } - + } diff --git a/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java index 853a2bfc..7e67218a 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java +++ b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -47,16 +47,16 @@ /** * Dummy request that is used to execute the script. - * + * * @author Roland Gruber */ public class GroovyConsoleRequest implements SlingHttpServletRequest { - + private ResourceResolver resolver; - + /** * Constructor - * + * * @param resolver resource resolver */ public GroovyConsoleRequest(ResourceResolver resolver) { diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index 7cc9ba1b..3865f9d1 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -30,7 +30,7 @@ /** * Implementation of history entry. - * + * * @author Roland Gruber */ public class HistoryEntryImpl implements HistoryEntry { @@ -45,22 +45,22 @@ public class HistoryEntryImpl implements HistoryEntry { public Date getStart() { return start; } - + @Override public Date getEnd() { return end; } - + @Override public List<ExecutionResult> getSingleResults() { return singleResults; } - + @Override public STATE getState() { return state; } - + @Override public RESULT getResult() { if (singleResults.isEmpty()) { @@ -75,15 +75,15 @@ public RESULT getResult() { } return result; } - + @Override public String getRepositoryPath() { return path; } - + /** * Sets the start date. - * + * * @param start start date */ public void setStart(Date start) { @@ -92,7 +92,7 @@ public void setStart(Date start) { /** * Sets the end date. - * + * * @param end end date */ public void setEnd(Date end) { @@ -101,17 +101,17 @@ public void setEnd(Date end) { /** * Sets the node path. - * + * * @param path node path */ public void setRepositoryPath(String path) { this.path = path; } - + public void setState(STATE state) { this.state = state; } - + @Override public String toString() { StringBuilder output = new StringBuilder(); diff --git a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java index 3890cfd1..8e7c54d5 100644 --- a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java +++ b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -32,21 +32,21 @@ /** * Provides the service resource resolver. - * + * * @author Roland Gruber */ -@Component(service=ServiceResourceResolverService.class) +@Component(service = ServiceResourceResolverService.class) public class ServiceResourceResolverService { - + private static final String SUBSERVICE_AECU = "aecu"; private static final String SUBSERVICE_AECU_CONTENT_MIGRATION = "aecu-content-migrator"; - + @Reference ResourceResolverFactory resolverFactory; - + /** - * Returns a resource resolver of the AECU service user. - * + * Returns a resource resolver of the AECU service user. + * * @return service resource resolver * @throws LoginException error opening resource resolver */ @@ -61,7 +61,7 @@ public ResourceResolver getServiceResourceResolver() throws LoginException { * * @return service resource resolver * @throws LoginException error opening resource resolver - */ + */ // TODO: add /apps write rights!!! public ResourceResolver getContentMigratorResourceResolver() throws LoginException { final Map<String, Object> authenticationInfo = new HashMap<>(); authenticationInfo.put(ResourceResolverFactory.SUBSERVICE, SUBSERVICE_AECU_CONTENT_MIGRATION); diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java index 5c0c77ba..fe3b6d67 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -53,15 +53,15 @@ protected void writeResult(SlingHttpServletResponse response, String json, int s } protected void writeResult(SlingHttpServletResponse response, String json) throws IOException { - writeResult(response,json,HttpServletResponse.SC_OK); + writeResult(response, json, HttpServletResponse.SC_OK); } protected void sendInternalServerError(SlingHttpServletResponse response) throws IOException { - writeResult(response,ERROR_MESSAGE_INTERNAL_SERVER, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + writeResult(response, ERROR_MESSAGE_INTERNAL_SERVER, HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } - protected boolean validateParameter(String param){ - return param != null && StringUtils.isNotEmpty(param); + protected boolean validateParameter(String param) { + return param != null && StringUtils.isNotEmpty(param); } } diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java index 00cac50a..32a87393 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -48,12 +48,12 @@ */ @Component(immediate = true, -service = {Servlet.class}, -property = { - "sling.servlet.paths=/bin/public/valtech/aecu/execute", - "sling.servlet.extensions=json", - "sling.servlet.methods=GET" -}) + service = {Servlet.class}, + property = { + "sling.servlet.paths=/bin/public/valtech/aecu/execute", + "sling.servlet.extensions=json", + "sling.servlet.methods=GET" + }) public class ExecutionServlet extends BaseServlet { private static final long serialVersionUID = 1L; @@ -72,7 +72,7 @@ protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse r String historyEntryAction = request.getParameter("historyEntryAction"); String aecuScriptPath = request.getParameter("aecuScriptPath"); - if(!this.validateParameter(aecuScriptPath) || !this.validateParameter(historyEntryAction)){ + if (!this.validateParameter(aecuScriptPath) || !this.validateParameter(historyEntryAction)) { writeResult(response, ERROR_MESSAGE_MANDATORY); return; } @@ -81,17 +81,17 @@ protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse r HistoryEntry historyEntry = this.getHistoryEntry(request, response, historyEntryAction); ExecutionResult executionResult = aecuService.execute(aecuScriptPath); aecuService.storeExecutionInHistory(historyEntry, executionResult); - this.finishHistoryEntry(historyEntry,historyEntryAction); - writeResult(response, this.prepareJson(executionResult.isSuccess(),historyEntry.getRepositoryPath())); + this.finishHistoryEntry(historyEntry, historyEntryAction); + writeResult(response, this.prepareJson(executionResult.isSuccess(), historyEntry.getRepositoryPath())); - }catch (AecuException e){ + } catch (AecuException e) { this.sendInternalServerError(response); } } protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHttpServletResponse response, String historyEntryAction) - throws AecuException, IOException{ + throws AecuException, IOException { HistoryEntry historyEntry; @@ -100,7 +100,7 @@ protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHtt case "close": //Used for "use" and "close" String historyEntryPath = request.getParameter("historyEntryPath"); - if(!this.validateParameter(historyEntryPath)){ + if (!this.validateParameter(historyEntryPath)) { writeResult(response, ERROR_MESSAGE_MANDATORY); return null; } @@ -118,7 +118,7 @@ protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHtt return historyEntry; } - protected HistoryEntry finishHistoryEntry(HistoryEntry historyEntry, String historyEntryAction) throws AecuException{ + protected HistoryEntry finishHistoryEntry(HistoryEntry historyEntry, String historyEntryAction) throws AecuException { switch (historyEntryAction.toLowerCase()) { case "single": @@ -136,13 +136,11 @@ protected HistoryEntry finishHistoryEntry(HistoryEntry historyEntry, String hist * This method builds the JSON String for the response. * Eg: {"success": true,"historyEntryPath":"/var/aecu/2018/6/13/152892696338961314"} * - * @param status - * @param historyEntryPath * @return json String */ - protected String prepareJson (boolean status, String historyEntryPath) { + protected String prepareJson(boolean status, String historyEntryPath) { JsonObject json = new JsonObject(); - json.addProperty("success",status); + json.addProperty("success", status); json.addProperty("historyEntryPath", historyEntryPath); return json.toString(); } diff --git a/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java index 2d4f4e97..d8d8c099 100644 --- a/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java +++ b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -43,25 +43,25 @@ /** * Tests HistoryUtil - * + * * @author Roland Gruber */ -@RunWith(value=MockitoJUnitRunner.class) +@RunWith(value = MockitoJUnitRunner.class) public class HistoryUtilTest { - + @Spy private HistoryUtil historyUtil; @Mock private ResourceResolver resolver; - + @Test public void createPath_Existing() throws AecuException { String path = "/var/aecu/2018/5"; when(resolver.getResource(path)).thenReturn(mock(Resource.class)); - + historyUtil.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); - + verify(historyUtil, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); } @@ -69,9 +69,9 @@ public void createPath_Existing() throws AecuException { public void createPath_NotExisting() throws AecuException, PersistenceException { String path = "/var/aecu/2018/5"; when(resolver.getResource("/var/aecu/2018")).thenReturn(mock(Resource.class)); - + historyUtil.createPath(path, resolver, JcrResourceConstants.NT_SLING_FOLDER); - + verify(historyUtil, times(1)).createPath(anyString(), eq(resolver), eq(JcrResourceConstants.NT_SLING_FOLDER)); verify(resolver, times(1)).create(any(Resource.class), eq("5"), any()); } diff --git a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java index 37440b41..ef812963 100644 --- a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java +++ b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java @@ -7,10 +7,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -46,22 +46,22 @@ /** * Tests AecuServiceImpl - * + * * @author Roland Gruber */ -@RunWith(value=MockitoJUnitRunner.class) +@RunWith(value = MockitoJUnitRunner.class) public class AecuServiceImplTest { - + @InjectMocks @Spy private AecuServiceImpl service; - + @Mock private SlingSettingsService settingsService; - + @Mock private ResourceResolver resolver; - + @Before public void setup() { Set<String> runModes = new HashSet<>(); @@ -71,7 +71,7 @@ public void setup() { runModes.add("test3"); when(settingsService.getRunModes()).thenReturn(runModes); } - + @Test public void matchesRunmodes_noMode() { assertTrue(service.matchesRunmodes("name")); @@ -116,11 +116,11 @@ public void isValidScriptName_invalidExtension() { public void isValidScriptName_fallback() { assertFalse(service.isValidScriptName("test.fallback.groovy")); } - + @Test public void getFallbackScript_Exists() { when(resolver.getResource("/path/to/script.fallback.groovy")).thenReturn(mock(Resource.class)); - + assertEquals("/path/to/script.fallback.groovy", service.getFallbackScript(resolver, "/path/to/script.always.groovy")); assertEquals("/path/to/script.fallback.groovy", service.getFallbackScript(resolver, "/path/to/script.groovy")); } @@ -134,8 +134,8 @@ public void getFallbackScript_NotExists() { @Test public void getFallbackScript_Fallback() { verify(resolver, never()).getResource("/path/to/script.fallback.groovy"); - + assertNull(service.getFallbackScript(resolver, "/path/to/script.fallback.groovy")); } - + } diff --git a/examples/pom.xml b/examples/pom.xml index 625e4a7f..aa608396 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy index 7dd6cfd2..b7b40bf7 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.groovy @@ -1,2 +1,3 @@ println "Executing project1 - script2" -This is a syntax error \ No newline at end of file +This is +a syntax error \ No newline at end of file diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index 9bcac825..c0ba035e 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -9,7 +9,7 @@ conditionMap_Page['jcr:primaryType'] = "cq:PageContent" println aecu.contentUpgradeBuilder() // traversers - .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" + .forResources((String[]) ["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") .forDescendantResourcesOf("/content/we-retail/ca/en/women") // filters @@ -25,17 +25,17 @@ println aecu.contentUpgradeBuilder() -def complexFilter = new ORFilter( - [ new FilterByProperties(conditionMap_Page), - new ANDFilter( [ - new FilterByProperties(conditionMap_Hero1), - new FilterByProperties(conditionMap_Hero2) - ] ) +def complexFilter = new ORFilter( + [new FilterByProperties(conditionMap_Page), + new ANDFilter([ + new FilterByProperties(conditionMap_Hero1), + new FilterByProperties(conditionMap_Hero2) + ]) ]) println aecu.contentUpgradeBuilder() // traversers - .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" + .forResources((String[]) ["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") .forDescendantResourcesOf("/content/we-retail/ca/en/women") // filters diff --git a/pom.xml b/pom.xml index 59b76b64..89720d03 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> @@ -215,7 +216,7 @@ </goals> </pluginExecutionFilter> <action> - <ignore /> + <ignore/> </action> </pluginExecution> <pluginExecution> @@ -235,7 +236,7 @@ </goals> </pluginExecutionFilter> <action> - <ignore /> + <ignore/> </action> </pluginExecution> <pluginExecution> @@ -256,7 +257,7 @@ </goals> </pluginExecutionFilter> <action> - <ignore /> + <ignore/> </action> </pluginExecution> </pluginExecutions> @@ -339,7 +340,8 @@ <goal>install</goal> </goals> <configuration> - <targetURL>http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp</targetURL> + <targetURL>http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp + </targetURL> </configuration> </execution> </executions> @@ -428,17 +430,17 @@ <scope>provided</scope> </dependency> <dependency> - <groupId>com.icfolson.aem.groovy.console</groupId> - <artifactId>aem-groovy-console</artifactId> - <version>11.3.0</version> - <scope>provided</scope> - <!-- exclude dependencies --> - <exclusions> - <exclusion> - <groupId>*</groupId> - <artifactId>*</artifactId> - </exclusion> - </exclusions> + <groupId>com.icfolson.aem.groovy.console</groupId> + <artifactId>aem-groovy-console</artifactId> + <version>11.3.0</version> + <scope>provided</scope> + <!-- exclude dependencies --> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>com.icfolson.aem.groovy.console</groupId> diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index 6d31b9d8..1d6801ab 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> diff --git a/ui.apps/src/main/content/jcr_root/_rep_policy.xml b/ui.apps/src/main/content/jcr_root/_rep_policy.xml index 70150516..3b0dc6d0 100644 --- a/ui.apps/src/main/content/jcr_root/_rep_policy.xml +++ b/ui.apps/src/main/content/jcr_root/_rep_policy.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="rep:ACL"> + jcr:primaryType="rep:ACL"> <allow - jcr:primaryType="rep:GrantACE" - rep:principalName="aecu-service" - rep:privileges="{Name}[jcr:read]"/> + jcr:primaryType="rep:GrantACE" + rep:principalName="aecu-service" + rep:privileges="{Name}[jcr:read]"/> </jcr:root> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/.content.xml b/ui.apps/src/main/content/jcr_root/apps/.content.xml index 792d2ead..84ee7452 100644 --- a/ui.apps/src/main/content/jcr_root/apps/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/.content.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:rep="internal" - jcr:mixinTypes="[rep:AccessControllable]" - jcr:primaryType="nt:folder"/> + jcr:mixinTypes="[rep:AccessControllable]" + jcr:primaryType="nt:folder"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml index 6124a6ed..cd148fc1 100644 --- a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/.content.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="sling:OrderedFolder" - id="aecu" - jcr:title="AEM Easy Content Upgrade" + jcr:primaryType="sling:OrderedFolder" + id="aecu" + jcr:title="AEM Easy Content Upgrade" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml index 17915990..850dabde 100644 --- a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/execute/.content.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="nt:unstructured" - jcr:title="Execute" - jcr:description="Execute one or more scripts" - href="/apps/valtech/aecu/tools/execute/page.html" - icon="playCircle" + jcr:primaryType="nt:unstructured" + jcr:title="Execute" + jcr:description="Execute one or more scripts" + href="/apps/valtech/aecu/tools/execute/page.html" + icon="playCircle" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml index 7df113d8..10517193 100644 --- a/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/aecu/history/.content.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="nt:unstructured" - jcr:title="History" - jcr:description="Show history of last runs" - href="/apps/valtech/aecu/tools/history/page.html" - icon="history" + jcr:primaryType="nt:unstructured" + jcr:title="History" + jcr:description="Show history of last runs" + href="/apps/valtech/aecu/tools/history/page.html" + icon="history" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/.content.xml index 1db66005..dfac52e3 100644 --- a/ui.apps/src/main/content/jcr_root/apps/settings/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/.content.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="nt:folder" + jcr:primaryType="nt:folder" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml index 491392d5..3d0c31ab 100644 --- a/ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/.content.xml @@ -1,3 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="sling:Folder"/> + jcr:primaryType="sling:Folder"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml index 5c9a5d2b..9ef5e220 100644 --- a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/.content.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="sling:Folder" + jcr:primaryType="sling:Folder" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml index c6ad70be..4210640b 100644 --- a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/.content.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="sling:OrderedFolder" + jcr:primaryType="sling:OrderedFolder" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml index 00e94271..ef5c15d2 100644 --- a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/hc/aecu/.content.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/operations/components/mbean" - resource="/system/sling/monitoring/mbeans/org/apache/sling/healthcheck/HealthCheck/aecuHealthCheckmBean" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/operations/components/mbean" + resource="/system/sling/monitoring/mbeans/org/apache/sling/healthcheck/HealthCheck/aecuHealthCheckmBean" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml index ee344538..9722c012 100755 --- a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/.content.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="sling:OrderedFolder" - sling:configCollectionInherit="true" - sling:configPropertyInherit="true"> + jcr:primaryType="sling:OrderedFolder" + sling:configCollectionInherit="true" + sling:configPropertyInherit="true"> </jcr:root> diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml index ee344538..9722c012 100755 --- a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/.content.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="sling:OrderedFolder" - sling:configCollectionInherit="true" - sling:configPropertyInherit="true"> + jcr:primaryType="sling:OrderedFolder" + sling:configCollectionInherit="true" + sling:configPropertyInherit="true"> </jcr:root> diff --git a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml index 8873d456..920997cf 100644 --- a/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/settings/granite/operations/maintenance/granite_weekly/aecu_history_purge/.content.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="nt:unstructured" - name="/libs/granite/operations/content/maintenanceWindow.html/apps/settings/granite/operations/maintenance/granite_weekly" - sling:resourceType="granite/operations/components/maintenance/task" - granite.maintenance.name="AECUPurgeHistory" + jcr:primaryType="nt:unstructured" + name="/libs/granite/operations/content/maintenanceWindow.html/apps/settings/granite/operations/maintenance/granite_weekly" + sling:resourceType="granite/operations/components/maintenance/task" + granite.maintenance.name="AECUPurgeHistory" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml index 5476047b..788411b1 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/.content.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="cq:ClientLibraryFolder" - allowProxy="{Boolean}true" - categories="[aecu.editor]" - embed="[]"/> + jcr:primaryType="cq:ClientLibraryFolder" + allowProxy="{Boolean}true" + categories="[aecu.editor]" + embed="[]"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css index 823282a3..950e601a 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/css/aecu.css @@ -1,61 +1,61 @@ .base-container { - margin: 2rem; + margin: 2rem; } .aecu-searchfield { - margin-top: 1rem; - margin-bottom: 1rem; + margin-top: 1rem; + margin-bottom: 1rem; } table.aecu-history-overview td { - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.2rem; - padding-bottom: 0.2rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + padding-top: 0.2rem; + padding-bottom: 0.2rem; } table.aecu-history-detail td { - padding-top: 0.5rem; - padding-bottom: 0.5rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; } .icon-color-ok { - color: green; + color: green; } .icon-color-fail { - color: red; + color: red; } .icon-color-inprogress { - color: blue; + color: blue; } .aecu-color-ok { - color: green; + color: green; } .aecu-color-fail { - color: red; + color: red; } .aecu-chart-text { - line-height: 1; - text-anchor: middle; - font-size: 0.5em; - transform: translateY(0.35em); + line-height: 1; + text-anchor: middle; + font-size: 0.5em; + transform: translateY(0.35em); } .aecu-font-normal { - font-size: 1rem; + font-size: 1rem; } .aecu-font-large { - font-size: 1.25rem; + font-size: 1.25rem; } .aecu-padding-sides5 { - padding-left: 0.5rem; - padding-right: 0.5rem; + padding-left: 0.5rem; + padding-right: 0.5rem; } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js index 5e66a67a..72ade47d 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/constants.js @@ -23,46 +23,46 @@ AECU.Constants = {}; AECU.Constants.Executor = { - servletPath : "/bin/public/valtech/aecu/execute.json?aecuScriptPath={0}&historyEntryAction={1}&historyEntryPath={2}", - historyPath : "/apps/valtech/aecu/tools/history/details.html?entry={0}&aecuScriptPath={1}" + servletPath: "/bin/public/valtech/aecu/execute.json?aecuScriptPath={0}&historyEntryAction={1}&historyEntryPath={2}", + historyPath: "/apps/valtech/aecu/tools/history/details.html?entry={0}&aecuScriptPath={1}" } AECU.Constants.Executor.Status = { - ready : { - icon: "helpCircle", - className: "", - text: "Ready to run" + ready: { + icon: "helpCircle", + className: "", + text: "Ready to run" }, - inProgress : { - icon: "playCircle", - className: "icon-color-inprogress", - text: "In progress" + inProgress: { + icon: "playCircle", + className: "icon-color-inprogress", + text: "In progress" }, - fail : { - icon: "closeCircle", - className: "icon-color-fail", - text: "Failed" + fail: { + icon: "closeCircle", + className: "icon-color-fail", + text: "Failed" }, - pending : { - icon: "pending", - className: "icon-color-inprogress", - text: "Pending" + pending: { + icon: "pending", + className: "icon-color-inprogress", + text: "Pending" }, executed: { - icon: "checkCircle", - className: "icon-color-ok", - text: "Ok" + icon: "checkCircle", + className: "icon-color-ok", + text: "Ok" }, internalError: { - icon: "sentimentNegative", - className: "icon-color-fail", - text: "Internal error" + icon: "sentimentNegative", + className: "icon-color-fail", + text: "Internal error" } } AECU.Constants.Executor.HistoryEntryActions = { - single : "single", - create : "create", - use : "use", - close : "close" + single: "single", + create: "create", + use: "use", + close: "close" } \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js index 6c4184f5..4d2c477c 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/executor.js @@ -22,138 +22,132 @@ AECU.Executor = {}; - AECU.Executor.historyEntryPath; - -AECU.Executor.doGET = function(getProps){ +AECU.Executor.doGET = function (getProps) { /* ADD HERE YOUR COMMON EXECUTOR AJAX PROPERTIES AND MERGE THEM WITH getPros */ var props = { async: false } - var executorGetProps = $.extend({},props, getProps); + var executorGetProps = $.extend({}, props, getProps); AECU.RequestHandler.GET(executorGetProps); } - -AECU.Executor.executeAll = function(tableRows) { +AECU.Executor.executeAll = function (tableRows) { AECU.Executor.changeAllStatus(AECU.Constants.Executor.Status.pending); var historyEntryAction; for (var i = 0, length = tableRows.length; i < length; i++) { - if(i == 0){ + if (i == 0) { historyEntryAction = AECU.Constants.Executor.HistoryEntryActions.create; - }else if(i == tableRows.length-1){ + } else if (i == tableRows.length - 1) { historyEntryAction = AECU.Constants.Executor.HistoryEntryActions.close; - }else{ + } else { historyEntryAction = AECU.Constants.Executor.HistoryEntryActions.use; } - AECU.Executor.execute(tableRows[i],historyEntryAction,AECU.Executor.historyEntryPath); + AECU.Executor.execute(tableRows[i], historyEntryAction, AECU.Executor.historyEntryPath); } AECU.Executor.disableButton(); AECU.Executor.historyEntryPath = undefined; } - -AECU.Executor.execute = function(row,historyEntryAction,historyEntryPath) { +AECU.Executor.execute = function (row, historyEntryAction, historyEntryPath) { this.doGET({ - url : AECU.Constants.Executor.servletPath.format(row.dataset.aecuExecuteScript,historyEntryAction,historyEntryPath), - beforeSend: function(){ - AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.inProgress); - AECU.Executor.disableButton(row); - }, - success: function( json ) { - AECU.Executor.historyEntryPath = json.historyEntryPath; - AECU.Executor.addHistoryLink(row,json.historyEntryPath); - if(json.success){ - AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.executed); - }else{ - AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.fail); - } - }, - error: function (jqXHR, textStatus, errorThrown) { - AECU.Executor.changeRowStatus(row,AECU.Constants.Executor.Status.internalError); - } - }); + url: AECU.Constants.Executor.servletPath.format(row.dataset.aecuExecuteScript, historyEntryAction, + historyEntryPath), + beforeSend: function () { + AECU.Executor.changeRowStatus(row, AECU.Constants.Executor.Status.inProgress); + AECU.Executor.disableButton(row); + }, + success: function (json) { + AECU.Executor.historyEntryPath = json.historyEntryPath; + AECU.Executor.addHistoryLink(row, json.historyEntryPath); + if (json.success) { + AECU.Executor.changeRowStatus(row, AECU.Constants.Executor.Status.executed); + } else { + AECU.Executor.changeRowStatus(row, AECU.Constants.Executor.Status.fail); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + AECU.Executor.changeRowStatus(row, AECU.Constants.Executor.Status.internalError); + } + }); } -AECU.Executor.addHistoryLink = function(row, historyEntryPath){ +AECU.Executor.addHistoryLink = function (row, historyEntryPath) { var historyLink = $(row).find("[data-aecu-execute-script-history]")[0]; historyLink.href = AECU.Constants.Executor.historyPath.format(historyEntryPath, row.dataset.aecuExecuteScript); historyLink.text = "Go to history"; } -AECU.Executor.changeRowStatus = function(row, value){ - AECU.Executor.changeStatus($(row).find("[data-aecu-execute-script-status]"), value); - AECU.Executor.changeScriptColor($(row).find("[data-aecu-execute-script-path]"), value); +AECU.Executor.changeRowStatus = function (row, value) { + AECU.Executor.changeStatus($(row).find("[data-aecu-execute-script-status]"), value); + AECU.Executor.changeScriptColor($(row).find("[data-aecu-execute-script-path]"), value); } - -AECU.Executor.changeAllStatus = function(value){ - AECU.Executor.changeStatus($("[data-aecu-execute-script-status]"), value); - AECU.Executor.changeScriptColor($("[data-aecu-execute-script-path]"), value); +AECU.Executor.changeAllStatus = function (value) { + AECU.Executor.changeStatus($("[data-aecu-execute-script-status]"), value); + AECU.Executor.changeScriptColor($("[data-aecu-execute-script-path]"), value); } -AECU.Executor.changeStatus = function(items, value) { - var icon = value.icon; - var title = value.text; - var className = value.className; - var iconTags = items.children("coral-icon"); - iconTags.each(function() { - this.set('icon', icon); - this.set('title', title); - this._syncDOM(); - }); - iconTags.removeClass('icon-color-inprogress'); - iconTags.addClass(className); +AECU.Executor.changeStatus = function (items, value) { + var icon = value.icon; + var title = value.text; + var className = value.className; + var iconTags = items.children("coral-icon"); + iconTags.each(function () { + this.set('icon', icon); + this.set('title', title); + this._syncDOM(); + }); + iconTags.removeClass('icon-color-inprogress'); + iconTags.addClass(className); } -AECU.Executor.changeScriptColor = function(items, value) { - var className = value.className; - items.removeClass('icon-color-inprogress'); - items.addClass(className); +AECU.Executor.changeScriptColor = function (items, value) { + var className = value.className; + items.removeClass('icon-color-inprogress'); + items.addClass(className); } -AECU.Executor.disableButton = function(row){ - if(row != undefined){ +AECU.Executor.disableButton = function (row) { + if (row != undefined) { $(row).find("[data-aecu-execute-script-button]").prop('disabled', true); - }else{ + } else { /* The only button not in a row. */ $("#aecu-execute-button-all").prop('disabled', true); } } - - -$(document).ready(function(){ +$(document).ready(function () { /* Disable executeAll button is there are no scripts displayed. */ - if($('[data-aecu-execute-script]').length == 0){ + if ($('[data-aecu-execute-script]').length == 0) { AECU.Executor.disableButton(); } /* Event for executing all scrips displayed in screen. */ - $("#aecu-execute-button-all").on('click', function(e) { + $("#aecu-execute-button-all").on('click', function (e) { var tableRows = $('[data-aecu-execute-script]'); - if(tableRows.length > 0){ + if (tableRows.length > 0) { AECU.Executor.executeAll(tableRows); } }); /* Event for each row (script) displayed in screen. */ - $('[data-aecu-execute-script-button]').on('click', function(event) { + $('[data-aecu-execute-script-button]').on('click', function (event) { AECU.Executor.disableButton(); AECU.Executor.execute( this.closest('[data-aecu-execute-script]'), - AECU.Constants.Executor.HistoryEntryActions.single,null); + AECU.Constants.Executor.HistoryEntryActions.single, null); }); - + /* open rail tab */ - var button = $('coral-cyclebutton'); + var button = $('coral-cyclebutton'); if (button) { - Coral.commons.ready(button[0], function() { - button.find('button').click(); - }); + Coral.commons.ready(button[0], function () { + button.find('button').click(); + }); } }); \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js index 20ffb92b..12e29c7c 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/history.js @@ -20,38 +20,38 @@ * SOFTWARE. */ -(function($, ns, channel, window) { - "use strict"; - - AECU.History = {}; - - /** - * Select the accordion item based on the GET parameter. - */ - AECU.History.selectAccordion = function() { - var search = window.location.search; - if (search && search.includes('aecuScriptPath')) { - search = search.substring(1); - var params = search.split('&'); - for (var i = 0; i < params.length; i++) { - var param = params[i]; - var parts = param.split('='); - if (parts[0] == 'aecuScriptPath') { - var name = parts[1]; - var item = jQuery("coral-accordion-item[data-path='" + name + "']"); - Coral.commons.ready(item[0], function() { - item[0].selected = true; - }); - } - } - } - }; - - /** - * Initial actions - */ - $(document).ready(function() { - AECU.History.selectAccordion(); - }); - +(function ($, ns, channel, window) { + "use strict"; + + AECU.History = {}; + + /** + * Select the accordion item based on the GET parameter. + */ + AECU.History.selectAccordion = function () { + var search = window.location.search; + if (search && search.includes('aecuScriptPath')) { + search = search.substring(1); + var params = search.split('&'); + for (var i = 0; i < params.length; i++) { + var param = params[i]; + var parts = param.split('='); + if (parts[0] == 'aecuScriptPath') { + var name = parts[1]; + var item = jQuery("coral-accordion-item[data-path='" + name + "']"); + Coral.commons.ready(item[0], function () { + item[0].selected = true; + }); + } + } + } + }; + + /** + * Initial actions + */ + $(document).ready(function () { + AECU.History.selectAccordion(); + }); + })(jQuery, Granite.author, jQuery(document), this); diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js index 231be4e7..b276aaa8 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/requestHandler.js @@ -23,14 +23,17 @@ AECU.RequestHandler = {}; AECU.RequestHandler.getProps = { - type : 'GET', + type: 'GET', cache: false, - success : function(data){}, - error : function(jqXHR, textStatus, errorThrown){}, - complete: function (jqXHR, textStatus) {} + success: function (data) { + }, + error: function (jqXHR, textStatus, errorThrown) { + }, + complete: function (jqXHR, textStatus) { + } } -AECU.RequestHandler.GET = function(props){ - var finalProps = $.extend({},this.getProps, props); +AECU.RequestHandler.GET = function (props) { + var finalProps = $.extend({}, this.getProps, props); $.ajax(finalProps); } \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js index 0d1106a4..a0b9a712 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu.editor/js/utils.js @@ -25,11 +25,10 @@ * Output: "Hello World!" * */ -String.prototype.format = function(){ +String.prototype.format = function () { var content = this; var length = arguments.length; - for (var i=0; i < length; i++) - { + for (var i = 0; i < length; i++) { var replacement = '{' + i + '}'; content = content.replace(replacement, arguments[i]); } diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml index d8cfcd9a..c3011352 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/.content.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="cq:ClientLibraryFolder" - allowProxy="{Boolean}true" - categories="[groovyconsole]"/> + jcr:primaryType="cq:ClientLibraryFolder" + allowProxy="{Boolean}true" + categories="[groovyconsole]"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js index ad9b06ec..93b39286 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js @@ -1,11 +1,17 @@ -$(document).ready(function(){ +$(document).ready(function () { if ($("#bindings").length != 0) { - $("#bindings ul").append("<li>aecu - de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate</li>"); // TODO: url to some javadoc available public + $("#bindings ul").append("<li>aecu - de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate</li>"); // TODO: + // url to + // some + // javadoc + // available + // public } if ($("#imports").length != 0) { - $("#imports ul").append("<li>de.valtech.aecu.core.groovy.console.bindings.filters</li>"); // TODO: url to some javadoc available public + $("#imports ul").append("<li>de.valtech.aecu.core.groovy.console.bindings.filters</li>"); // TODO: url to some javadoc + // available public } }); \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html index aea50281..31b63913 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/executionResults.html @@ -1,29 +1,29 @@ -<sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> +<sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview"/> <sly data-sly-test.empty="${cmp.history.singleResults.empty}"> - <h2>No scripts executed</h2> + <h2>No scripts executed</h2> </sly> <sly data-sly-test="${!empty}"> - <sly data-sly-use.details="templates/executionResult.html" /> - <sly data-sly-test="${cmp.history.singleResults.size == 1}"> - <h2 class="aecu-font-large">Execution details</h2> - <sly data-sly-list="${cmp.history.singleResults}"> - <sly data-sly-call="${details.details @ result = item}" /> + <sly data-sly-use.details="templates/executionResult.html"/> + <sly data-sly-test="${cmp.history.singleResults.size == 1}"> + <h2 class="aecu-font-large">Execution details</h2> + <sly data-sly-list="${cmp.history.singleResults}"> + <sly data-sly-call="${details.details @ result = item}"/> + </sly> + </sly> + <sly data-sly-test="${cmp.history.singleResults.size > 1}"> + <h2 class="aecu-font-large">Execution details for ${cmp.history.singleResults.size} scripts</h2> + <coral-accordion> + <sly data-sly-list="${cmp.history.singleResults}"> + <coral-accordion-item data-path="${item.path}"> + <coral-accordion-item-label class="aecu-color-${item.success ? 'ok' : 'fail'}"> + ${item.path} + </coral-accordion-item-label> + <coral-accordion-item-content> + <sly data-sly-call="${details.details @ result = item}"/> + </coral-accordion-item-content> + </coral-accordion-item> + </sly> + </coral-accordion> </sly> - </sly> - <sly data-sly-test="${cmp.history.singleResults.size > 1}"> - <h2 class="aecu-font-large">Execution details for ${cmp.history.singleResults.size} scripts</h2> - <coral-accordion> - <sly data-sly-list="${cmp.history.singleResults}"> - <coral-accordion-item data-path="${item.path}"> - <coral-accordion-item-label class="aecu-color-${item.success ? 'ok' : 'fail'}"> - ${item.path} - </coral-accordion-item-label> - <coral-accordion-item-content> - <sly data-sly-call="${details.details @ result = item}" /> - </coral-accordion-item-content> - </coral-accordion-item> - </sly> - </coral-accordion> - </sly> </sly> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html index d06b5bb4..527e3603 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/executionResults/templates/executionResult.html @@ -1,31 +1,32 @@ <template data-sly-template.details="${ @ result, isFallback=false}"> -<div class="aecu-padding-sides5"> - <table class="aecu-history-detail aecu-font-normal" width="100%"> - <tr> - <td>Path: ${result.path}</td> - <td rowspan="2"> - <coral-icon icon="${result.success ? 'checkCircle' : 'closeCircle'}" size="L" class="icon-color-${result.success ? 'ok' : 'fail'}" > - </coral-icon> - </td> - </tr> - <tr> - <td>Execution time: ${result.time}</td> - </tr> - </table> - <sly data-sly-test="${result.result}"> - <h3 data-sly-test="${!isFallback}" class="aecu-font-large">Result</h3> - <h4 data-sly-test="${isFallback}" class="aecu-font-large">Result</h4> - <pre class="aecu-font-normal">${result.result}</pre> - </sly> - <sly data-sly-test="${result.output}"> - <h3 data-sly-test="${!isFallback}" class="aecu-font-large">Output</h3> - <h4 data-sly-test="${isFallback}" class="aecu-font-large">Output</h4> - <pre class="aecu-font-normal">${result.output}</pre> - </sly> - - <sly data-sly-test="${result.fallbackResult}"> - <h3 class="aecu-font-large">Fallback script result</h3> - <sly data-sly-call="${details @ result = result.fallbackResult, isFallback = true}" /> - </sly> -</div> + <div class="aecu-padding-sides5"> + <table class="aecu-history-detail aecu-font-normal" width="100%"> + <tr> + <td>Path: ${result.path}</td> + <td rowspan="2"> + <coral-icon icon="${result.success ? 'checkCircle' : 'closeCircle'}" size="L" + class="icon-color-${result.success ? 'ok' : 'fail'}"> + </coral-icon> + </td> + </tr> + <tr> + <td>Execution time: ${result.time}</td> + </tr> + </table> + <sly data-sly-test="${result.result}"> + <h3 data-sly-test="${!isFallback}" class="aecu-font-large">Result</h3> + <h4 data-sly-test="${isFallback}" class="aecu-font-large">Result</h4> + <pre class="aecu-font-normal">${result.result}</pre> + </sly> + <sly data-sly-test="${result.output}"> + <h3 data-sly-test="${!isFallback}" class="aecu-font-large">Output</h3> + <h4 data-sly-test="${isFallback}" class="aecu-font-large">Output</h4> + <pre class="aecu-font-normal">${result.output}</pre> + </sly> + + <sly data-sly-test="${result.fallbackResult}"> + <h3 class="aecu-font-large">Fallback script result</h3> + <sly data-sly-call="${details @ result = result.fallbackResult, isFallback = true}"/> + </sly> + </div> </template> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml index 5b0bece8..d1363777 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/.content.xml @@ -1,3 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="cq:Component"/> + jcr:primaryType="cq:Component"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html index 2a7f0af4..c2dbfdec 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -1,31 +1,36 @@ -<sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> +<sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview"/> <h1>Run details</h1> <table class="aecu-history-overview aecu-font-normal" width="100%"> - <tr> - <td>State: ${cmp.history.state.label}</td> - <td rowspan="4" align="right"> - <svg width="150px" height="150px" viewBox="0 0 50 50" class="donut"> - <circle class="donut-ring" cx="25" cy="25" r="22" fill="transparent" stroke="grey" stroke-width="0.2"></circle> - <circle class="donut-outerring" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="grey" stroke-width="8.5"></circle> - <circle class="donut-hole" cx="25" cy="25" r="15.91549430918954" fill="#fff"></circle> - <circle class="donut-innerring" cx="25" cy="25" r="12.5" fill="transparent" stroke="grey" stroke-width="2"></circle> - <circle class="donut-red" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#ef1616" stroke-width="8"></circle> - <circle class="donut-green" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#4bb43d" stroke-width="8" stroke-dasharray="${cmp.percentages.left} ${cmp.percentages.right}" stroke-dashoffset="25"></circle> - <g> - <text x="50%" y="50%" class="aecu-chart-text"> - ${cmp.percentages.left}% - </text> - </g> - </svg> - </td> - </tr> - <tr> - <td>Result: ${cmp.history.result.label}</td> - </tr> - <tr> - <td>Start: ${cmp.start}</td> - </tr> - <tr> - <td>End: ${cmp.end}</td> - </tr> + <tr> + <td>State: ${cmp.history.state.label}</td> + <td rowspan="4" align="right"> + <svg width="150px" height="150px" viewBox="0 0 50 50" class="donut"> + <circle class="donut-ring" cx="25" cy="25" r="22" fill="transparent" stroke="grey" stroke-width="0.2"></circle> + <circle class="donut-outerring" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="grey" + stroke-width="8.5"></circle> + <circle class="donut-hole" cx="25" cy="25" r="15.91549430918954" fill="#fff"></circle> + <circle class="donut-innerring" cx="25" cy="25" r="12.5" fill="transparent" stroke="grey" + stroke-width="2"></circle> + <circle class="donut-red" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#ef1616" + stroke-width="8"></circle> + <circle class="donut-green" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#4bb43d" + stroke-width="8" stroke-dasharray="${cmp.percentages.left} ${cmp.percentages.right}" + stroke-dashoffset="25"></circle> + <g> + <text x="50%" y="50%" class="aecu-chart-text"> + ${cmp.percentages.left}% + </text> + </g> + </svg> + </td> + </tr> + <tr> + <td>Result: ${cmp.history.result.label}</td> + </tr> + <tr> + <td>Start: ${cmp.start}</td> + </tr> + <tr> + <td>End: ${cmp.end}</td> + </tr> </table> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/.content.xml index 07aadeab..56d6dc70 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/.content.xml @@ -1,4 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" - jcr:primaryType="sling:Folder" - /> +<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" + xmlns:jcr="http://www.jcp.org/jcr/1.0" + jcr:primaryType="sling:Folder" +/> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html index 26a5bf64..2dbd93cf 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/dataitem/dataitem.html @@ -7,10 +7,10 @@ <td is="coral-table-cell" data-aecu-execute-script-path>${resource.path}</td> <td is="coral-table-cell"><a target="_blank" data-aecu-execute-script-history>* not executed *</a></td> <td is="coral-table-cell" data-aecu-execute-script-status> - <coral-icon icon="helpCircle" size="M" title="Not run"> - </coral-icon> + <coral-icon icon="helpCircle" size="M" title="Not run"> + </coral-icon> </td> - <td is="coral-table-cell" > + <td is="coral-table-cell"> <button is="coral-button" type="button" variant="minimal" icon="dragHandle" coral-table-roworder></button> </td> </tr> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html index 8384f71d..d76dd992 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/datasource/datasource.html @@ -1 +1 @@ -<sly data-sly-use.datasource="de.valtech.aecu.core.model.execute.ExecuteDataSource" /> \ No newline at end of file +<sly data-sly-use.datasource="de.valtech.aecu.core.model.execute.ExecuteDataSource"/> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml index ab89ac26..7d69c927 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/execute/page/.content.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> -<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" - jcr:primaryType="cq:Page"> +<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" + xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" + jcr:primaryType="cq:Page"> <jcr:content jcr:mixinTypes="[sling:VanityPath]" jcr:primaryType="nt:unstructured" @@ -22,62 +23,62 @@ jcr:primaryType="nt:unstructured" jcr:title="Search" sling:resourceType="granite/ui/components/coral/foundation/panel/railpanel" - > + > <items jcr:primaryType="nt:unstructured"> <content - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/container" - granite:class="base-container" - > - <items jcr:primaryType="nt:unstructured"> - <form - granite:id="aecu-execute-scripts-search-form" - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/form" - action="/apps/valtech/aecu/tools/execute/page.html" - modeGroup="aecu-execute-scripts-search" - searchResultTitle="Scripts to execute" - targetCollection="#aecu-execute-scripts-search"> - <successresponse - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/form/responses/reload"/> - <items jcr:primaryType="nt:unstructured"> - <searchPath - granite:class="aecu-searchfield" - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/form/pathfield" - fieldLabel="Select the folder or script" - rootPath="/etc/groovyconsole/scripts" - required="{Boolean}true" - filter="hierarchy" - name="searchPath"/> - <submit - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/foundation/form/submit" - text="Search"/> - </items> - </form> - </items> + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/container" + granite:class="base-container" + > + <items jcr:primaryType="nt:unstructured"> + <form + granite:id="aecu-execute-scripts-search-form" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form" + action="/apps/valtech/aecu/tools/execute/page.html" + modeGroup="aecu-execute-scripts-search" + searchResultTitle="Scripts to execute" + targetCollection="#aecu-execute-scripts-search"> + <successresponse + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form/responses/reload"/> + <items jcr:primaryType="nt:unstructured"> + <searchPath + granite:class="aecu-searchfield" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/form/pathfield" + fieldLabel="Select the folder or script" + rootPath="/etc/groovyconsole/scripts" + required="{Boolean}true" + filter="hierarchy" + name="searchPath"/> + <submit + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/foundation/form/submit" + text="Search"/> + </items> + </form> + </items> </content> </items> </search> </rails> <views jcr:primaryType="nt:unstructured"> <list - granite:rel="aecu-execute-scripts" - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/table" - selectionMode="none" - orderable="{Boolean}true" - src="/mnt/overlay/valtech/aecu/tools/execute/page/jcr:content/views/list{.offset,limit}.html" - stateId="shell.collectionpage"> + granite:rel="aecu-execute-scripts" + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/table" + selectionMode="none" + orderable="{Boolean}true" + src="/mnt/overlay/valtech/aecu/tools/execute/page/jcr:content/views/list{.offset,limit}.html" + stateId="shell.collectionpage"> <columns jcr:primaryType="nt:unstructured"> <button - jcr:primaryType="nt:unstructured" - jcr:title="Action"/> + jcr:primaryType="nt:unstructured" + jcr:title="Action"/> <script - jcr:primaryType="nt:unstructured" - jcr:title="Script"/> + jcr:primaryType="nt:unstructured" + jcr:title="Script"/> <history jcr:primaryType="nt:unstructured" jcr:title="History"/> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html index ba98c2e2..d12b6bad 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/dataitem/dataitem.html @@ -1,12 +1,13 @@ -<sly data-sly-use.dataItem="de.valtech.aecu.core.model.history.HistoryDataItem" /> +<sly data-sly-use.dataItem="de.valtech.aecu.core.model.history.HistoryDataItem"/> <!--/* TODO: investigate why we need the class for the Paginator to work */--> <tr is="coral-table-row" class="foundation-collection-item"> - <td is="coral-table-cell"><a href="/apps/valtech/aecu/tools/history/details.html?entry=${dataItem.path}">${dataItem.date}</a></td> + <td is="coral-table-cell"><a href="/apps/valtech/aecu/tools/history/details.html?entry=${dataItem.path}">${dataItem.date}</a> + </td> <td is="coral-table-cell"> - ${dataItem.duration} + ${dataItem.duration} </td> <td is="coral-table-cell"> - <coral-icon icon="${dataItem.statusIcon}" size="M" class="icon-color-${dataItem.statusColor}" > - </coral-icon> + <coral-icon icon="${dataItem.statusIcon}" size="M" class="icon-color-${dataItem.statusColor}"> + </coral-icon> </td> </tr> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html index 0fbb654f..63b9f05c 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/datasource/datasource.html @@ -1 +1 @@ -<sly data-sly-use.datasource="de.valtech.aecu.core.model.history.HistoryDataSource" /> \ No newline at end of file +<sly data-sly-use.datasource="de.valtech.aecu.core.model.history.HistoryDataSource"/> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml index 1b138e2b..2737cb03 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/details/.content.xml @@ -1,43 +1,43 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root - xmlns:jcr="http://www.jcp.org/jcr/1.0" - xmlns:rep="internal" - xmlns:sling="http://sling.apache.org/jcr/sling/1.0" - xmlns:granite="http://www.adobe.com/jcr/granite/1.0" - jcr:primaryType="cq:Page"> + xmlns:jcr="http://www.jcp.org/jcr/1.0" + xmlns:rep="internal" + xmlns:sling="http://sling.apache.org/jcr/sling/1.0" + xmlns:granite="http://www.adobe.com/jcr/granite/1.0" + jcr:primaryType="cq:Page"> <jcr:content - jcr:primaryType="nt:unstructured" - jcr:title="AEM Easy Content Upgrade - History details" - sling:resourceType="granite/ui/components/shell/page" - consoleId="aecu-history-details" + jcr:primaryType="nt:unstructured" + jcr:title="AEM Easy Content Upgrade - History details" + sling:resourceType="granite/ui/components/shell/page" + consoleId="aecu-history-details" > - <head jcr:primaryType="nt:unstructured"> - <clientlibs - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/foundation/includeclientlibs" - categories="[coralui3,granite.ui.coral.foundation,aecu.editor]" - /> - </head> - <title - jcr:primaryType="nt:unstructured" - text="AEM Easy Content Upgrade - History details" - sling:resourceType="granite/ui/components/coral/foundation/text" - /> - <content - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/coral/foundation/container" - granite:class="base-container" - > - <items jcr:primaryType="nt:unstructured"> - <overview - jcr:primaryType="nt:unstructured" - sling:resourceType="valtech/aecu/components/content/history/overview" - /> - <details - jcr:primaryType="nt:unstructured" - sling:resourceType="valtech/aecu/components/content/history/executionResults" + <head jcr:primaryType="nt:unstructured"> + <clientlibs + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/foundation/includeclientlibs" + categories="[coralui3,granite.ui.coral.foundation,aecu.editor]" + /> + </head> + <title + jcr:primaryType="nt:unstructured" + text="AEM Easy Content Upgrade - History details" + sling:resourceType="granite/ui/components/coral/foundation/text" /> - </items> - </content> + <content + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/coral/foundation/container" + granite:class="base-container" + > + <items jcr:primaryType="nt:unstructured"> + <overview + jcr:primaryType="nt:unstructured" + sling:resourceType="valtech/aecu/components/content/history/overview" + /> + <details + jcr:primaryType="nt:unstructured" + sling:resourceType="valtech/aecu/components/content/history/executionResults" + /> + </items> + </content> </jcr:content> </jcr:root> diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml index b407cfec..ddaaf633 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/tools/history/page/.content.xml @@ -1,65 +1,65 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root - xmlns:jcr="http://www.jcp.org/jcr/1.0" - xmlns:rep="internal" - xmlns:sling="http://sling.apache.org/jcr/sling/1.0" - xmlns:granite="http://www.adobe.com/jcr/granite/1.0" - jcr:primaryType="cq:Page"> + xmlns:jcr="http://www.jcp.org/jcr/1.0" + xmlns:rep="internal" + xmlns:sling="http://sling.apache.org/jcr/sling/1.0" + xmlns:granite="http://www.adobe.com/jcr/granite/1.0" + jcr:primaryType="cq:Page"> <jcr:content - jcr:primaryType="nt:unstructured" - jcr:title="AEM Easy Content Upgrade - History" - consoleId="aecu-history" - sling:resourceType="granite/ui/components/shell/collectionpage" - targetCollection=".aecu-history-entries" - modeGroup="aecu-history-entries" - > - <head jcr:primaryType="nt:unstructured"> - <clientlibs - jcr:primaryType="nt:unstructured" - sling:resourceType="granite/ui/components/foundation/includeclientlibs" - categories="[coralui3,granite.ui.coral.foundation,aecu.editor]" - /> - </head> - <title - jcr:primaryType="nt:unstructured" - text="AEM Easy Content Upgrade - History" - sling:resourceType="granite/ui/components/coral/foundation/text" - /> - <views jcr:primaryType="nt:unstructured"> - <list - jcr:primaryType="nt:unstructured" - layoutId="list" - sling:resourceType="granite/ui/components/coral/foundation/table" - limit="50" - size="${empty requestPathInfo.selectors[1] ? "50" : requestPathInfo.selectors[1]}" - src="/apps/valtech/aecu/tools/history/page/jcr:content/views/list{.offset,limit}.html?wcmmode=disabled" - path="${requestPathInfo.suffix}" - sortMode="remote" - stateId="shell.collectionpage" - modeGroup="aecu-history-entries" - granite:rel="aecu-history-entries" - > - <columns jcr:primaryType="nt:unstructured"> - <date - jcr:primaryType="nt:unstructured" - jcr:title="Date" - /> - <duration jcr:primaryType="nt:unstructured" - jcr:title="Duration" - /> - <status - jcr:primaryType="nt:unstructured" - jcr:title="Status" - /> - </columns> - <datasource - jcr:primaryType="nt:unstructured" - path="${requestPathInfo.suffix}" - sling:resourceType="valtech/aecu/tools/history/datasource" - itemResourceType="valtech/aecu/tools/history/dataitem" + jcr:title="AEM Easy Content Upgrade - History" + consoleId="aecu-history" + sling:resourceType="granite/ui/components/shell/collectionpage" + targetCollection=".aecu-history-entries" + modeGroup="aecu-history-entries" + > + <head jcr:primaryType="nt:unstructured"> + <clientlibs + jcr:primaryType="nt:unstructured" + sling:resourceType="granite/ui/components/foundation/includeclientlibs" + categories="[coralui3,granite.ui.coral.foundation,aecu.editor]" + /> + </head> + <title + jcr:primaryType="nt:unstructured" + text="AEM Easy Content Upgrade - History" + sling:resourceType="granite/ui/components/coral/foundation/text" /> - </list> - </views> + <views jcr:primaryType="nt:unstructured"> + <list + jcr:primaryType="nt:unstructured" + layoutId="list" + sling:resourceType="granite/ui/components/coral/foundation/table" + limit="50" + size="${empty requestPathInfo.selectors[1] ? "50" : requestPathInfo.selectors[1]}" + src="/apps/valtech/aecu/tools/history/page/jcr:content/views/list{.offset,limit}.html?wcmmode=disabled" + path="${requestPathInfo.suffix}" + sortMode="remote" + stateId="shell.collectionpage" + modeGroup="aecu-history-entries" + granite:rel="aecu-history-entries" + > + <columns jcr:primaryType="nt:unstructured"> + <date + jcr:primaryType="nt:unstructured" + jcr:title="Date" + /> + <duration + jcr:primaryType="nt:unstructured" + jcr:title="Duration" + /> + <status + jcr:primaryType="nt:unstructured" + jcr:title="Status" + /> + </columns> + <datasource + jcr:primaryType="nt:unstructured" + path="${requestPathInfo.suffix}" + sling:resourceType="valtech/aecu/tools/history/datasource" + itemResourceType="valtech/aecu/tools/history/dataitem" + /> + </list> + </views> </jcr:content> </jcr:root> diff --git a/ui.apps/src/main/content/jcr_root/content/_rep_policy.xml b/ui.apps/src/main/content/jcr_root/content/_rep_policy.xml index 5a61f173..11af9391 100644 --- a/ui.apps/src/main/content/jcr_root/content/_rep_policy.xml +++ b/ui.apps/src/main/content/jcr_root/content/_rep_policy.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="rep:ACL"> + jcr:primaryType="rep:ACL"> <allow - jcr:primaryType="rep:GrantACE" - rep:principalName="aecu-content-migrator" - rep:privileges="{Name}[jcr:all]"/> + jcr:primaryType="rep:GrantACE" + rep:principalName="aecu-content-migrator" + rep:privileges="{Name}[jcr:all]"/> </jcr:root> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml index 1db66005..dfac52e3 100644 --- a/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml +++ b/ui.apps/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/.content.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="nt:folder" + jcr:primaryType="nt:folder" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml index 44a6008e..5ea6a383 100644 --- a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml +++ b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/.content.xml @@ -1,3 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" -jcr:primaryType="rep:AuthorizableFolder"/> \ No newline at end of file + jcr:primaryType="rep:AuthorizableFolder"/> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml index 4d165d6f..e96c6857 100644 --- a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml +++ b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-content-migrator/.content.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="rep:SystemUser" - jcr:uuid="0597301b-4690-30ea-8cba-217f5a66faf6" - rep:authorizableId="aecu-content-migrator" - rep:principalName="aecu-content-migrator"/> + jcr:primaryType="rep:SystemUser" + jcr:uuid="0597301b-4690-30ea-8cba-217f5a66faf6" + rep:authorizableId="aecu-content-migrator" + rep:principalName="aecu-content-migrator"/> diff --git a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml index 13021631..e4f2bf48 100644 --- a/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml +++ b/ui.apps/src/main/content/jcr_root/home/users/system/aecu/aecu-service/.content.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="rep:SystemUser" - jcr:uuid="168a3a96-12ee-3756-8113-34157ebc31c3" - rep:authorizableId="aecu-service" - rep:principalName="aecu-service" + jcr:primaryType="rep:SystemUser" + jcr:uuid="168a3a96-12ee-3756-8113-34157ebc31c3" + rep:authorizableId="aecu-service" + rep:principalName="aecu-service" /> diff --git a/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml b/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml index c6ad70be..4210640b 100644 --- a/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml +++ b/ui.apps/src/main/content/jcr_root/var/aecu/.content.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="sling:OrderedFolder" + jcr:primaryType="sling:OrderedFolder" /> \ No newline at end of file diff --git a/ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml b/ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml index 118b223d..46868b48 100644 --- a/ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml +++ b/ui.apps/src/main/content/jcr_root/var/aecu/_rep_policy.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" - jcr:primaryType="rep:ACL"> + jcr:primaryType="rep:ACL"> <allow - jcr:primaryType="rep:GrantACE" - rep:principalName="aecu-service" - rep:privileges="{Name}[jcr:all]"/> + jcr:primaryType="rep:GrantACE" + rep:principalName="aecu-service" + rep:privileges="{Name}[jcr:all]"/> </jcr:root> \ No newline at end of file From 01006f90f0e0a6f578c8c44e74e496cca02b6dc6 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 10:37:50 +0200 Subject: [PATCH 092/122] bindings/improvements-1: merged conflicts with develop last one --- .../content/history/overview/overview.html | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html index 1cb95f20..4b3c1566 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/components/content/history/overview/overview.html @@ -1,28 +1,28 @@ <sly data-sly-use.cmp="de.valtech.aecu.core.model.history.HistoryOverview" /> <h1>Run details</h1> <table class="aecu-history-overview aecu-font-normal" width="100%"> - <tr> - <td>State: ${cmp.history.state.label}</td> - <td rowspan="5" align="right"> - <svg width="150px" height="150px" viewBox="0 0 50 50" class="donut"> - <circle class="donut-ring" cx="25" cy="25" r="22" fill="transparent" stroke="grey" stroke-width="0.2"></circle> - <circle class="donut-outerring" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="grey" stroke-width="8.5"></circle> - <circle class="donut-hole" cx="25" cy="25" r="15.91549430918954" fill="#fff"></circle> - <circle class="donut-innerring" cx="25" cy="25" r="12.5" fill="transparent" stroke="grey" stroke-width="2"></circle> - <circle class="donut-red" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#ef1616" stroke-width="8"></circle> - <circle class="donut-green" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#4bb43d" stroke-width="8" stroke-dasharray="${cmp.percentages.left} ${cmp.percentages.right}" stroke-dashoffset="25"></circle> - <g> - <text x="50%" y="50%" class="aecu-chart-text"> - ${cmp.percentages.left}% - </text> - </g> - </svg> - </td> - </tr> - <tr> - <td>Result: ${cmp.history.result.label}</td> - </tr> - <tr> - <td>Duration: <span title="${cmp.start} - ${cmp.end}">${cmp.duration}</span></td> - </tr> + <tr> + <td>State: ${cmp.history.state.label}</td> + <td rowspan="5" align="right"> + <svg width="150px" height="150px" viewBox="0 0 50 50" class="donut"> + <circle class="donut-ring" cx="25" cy="25" r="22" fill="transparent" stroke="grey" stroke-width="0.2"></circle> + <circle class="donut-outerring" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="grey" stroke-width="8.5"></circle> + <circle class="donut-hole" cx="25" cy="25" r="15.91549430918954" fill="#fff"></circle> + <circle class="donut-innerring" cx="25" cy="25" r="12.5" fill="transparent" stroke="grey" stroke-width="2"></circle> + <circle class="donut-red" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#ef1616" stroke-width="8"></circle> + <circle class="donut-green" cx="25" cy="25" r="15.91549430918954" fill="transparent" stroke="#4bb43d" stroke-width="8" stroke-dasharray="${cmp.percentages.left} ${cmp.percentages.right}" stroke-dashoffset="25"></circle> + <g> + <text x="50%" y="50%" class="aecu-chart-text"> + ${cmp.percentages.left}% + </text> + </g> + </svg> + </td> + </tr> + <tr> + <td>Result: ${cmp.history.result.label}</td> + </tr> + <tr> + <td>Duration: <span title="${cmp.start} - ${cmp.end}">${cmp.duration}</span></td> + </tr> </table> From 01b6f8cbc3e1d978138ae245f529575e95cbb223 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 11:51:42 +0200 Subject: [PATCH 093/122] bindings/improvements-1: set mvn dependency to compile scope --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 89720d03..93dcd2e9 100644 --- a/pom.xml +++ b/pom.xml @@ -494,6 +494,7 @@ <groupId>com.google.code.findbugs</groupId> <artifactId>jsr305</artifactId> <version>2.0.1</version> + <scope>compile</scope> </dependency> </dependencies> </dependencyManagement> From fb822ad902e37c25c948b42e5998f36434660db7 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 11:52:20 +0200 Subject: [PATCH 094/122] bindings/improvements-1: updated sample groovy script --- .../tests_for_simpleContentUpdates.groovy | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index c0ba035e..28e06452 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -9,41 +9,41 @@ conditionMap_Page['jcr:primaryType'] = "cq:PageContent" println aecu.contentUpgradeBuilder() // traversers - .forResources((String[]) ["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" + .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") .forDescendantResourcesOf("/content/we-retail/ca/en/women") // filters .filterByProperties(conditionMap_Page) // actions - .doSetStringProperty("newStringProperty", "aecu test with conditionMap_Page") - .doSetBooleanProperty("newBooleanProperty", true) - .doSetIntegerProperty("newStringProperty", 123) - .doRenameProperty("newStringProperty", "delete_me_later") + .doSetStringProperty("newStringProperty1", "aecu test with conditionMap_Page") + .doSetBooleanProperty("newBooleanProperty1", true) + .doSetIntegerProperty("newIntegerProperty1", 123) + .doRenameProperty("newStringProperty1", "delete_me_later") // .removeProperty("delete_me_later") - .run() + .dryRun() -def complexFilter = new ORFilter( - [new FilterByProperties(conditionMap_Page), - new ANDFilter([ - new FilterByProperties(conditionMap_Hero1), - new FilterByProperties(conditionMap_Hero2) - ]) +def complexFilter = new ORFilter( + [ new FilterByProperties(conditionMap_Page), + new ANDFilter( [ + new FilterByProperties(conditionMap_Hero1), + new FilterByProperties(conditionMap_Hero2) + ] ) ]) println aecu.contentUpgradeBuilder() // traversers - .forResources((String[]) ["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" + .forResources((String[])["/content/we-retail/ca/en/jcr:content", "/content/we-retail/ca/en/experience/jcr:content"]) //,"/invalid/path" .forChildResourcesOf("/content/we-retail/ca/en/men") .forDescendantResourcesOf("/content/we-retail/ca/en/women") // filters .filterWith(complexFilter) // actions - .doSetProperty("newStringProperty", "aecu test with conditionMap_Hero") - .doSetBooleanProperty("newBooleanProperty", false) - .doSetIntegerProperty("newStringProperty", 789) - .doRenameProperty("newStringProperty", "delete_me_later") + .doSetStringProperty("newStringProperty2", "aecu test with conditionMap_Hero") + .doSetBooleanProperty("newBooleanProperty2", false) + .doSetIntegerProperty("newIntegerProperty2", 789) + .doRenameProperty("newStringProperty2", "delete_me_later2") // .removeProperty("delete_me_later") - .run() \ No newline at end of file + .dryRun() \ No newline at end of file From 728882df1c10b35afb050614a1a7020b4381029b Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 11:53:04 +0200 Subject: [PATCH 095/122] bindings/improvements-1: add binding and imports if not already added in the groovyconsole view --- .../js/aecu_groovyconsole_extension.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js index 93b39286..9bf22eaf 100644 --- a/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js +++ b/ui.apps/src/main/content/jcr_root/apps/valtech/aecu/clientlibs/aecu/groovyconsole/js/aecu_groovyconsole_extension.js @@ -1,17 +1,13 @@ $(document).ready(function () { - if ($("#bindings").length != 0) { - $("#bindings ul").append("<li>aecu - de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate</li>"); // TODO: - // url to - // some - // javadoc - // available - // public + if ($("#bindings").length != 0 && $("#bindings ul li.aecu-binding").length == 0) { + // TODO url to some public available javadoc + $("#bindings ul").append("<li class='aecu-binding'>aecu - de.valtech.aecu.core.groovy.console.bindings.SimpleContentUpdate</li>"); } - if ($("#imports").length != 0) { - $("#imports ul").append("<li>de.valtech.aecu.core.groovy.console.bindings.filters</li>"); // TODO: url to some javadoc - // available public + if ($("#imports").length != 0 && $("#bindings ul li.aecu-import").length == 0) { + // TODO url to some public available javadoc + $("#imports ul").append("<li class='aecu-import'>de.valtech.aecu.core.groovy.console.bindings.filters</li>"); } }); \ No newline at end of file From a0effae05185b0b8629e120e21101142b42deba2 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Thu, 12 Jul 2018 13:05:26 +0200 Subject: [PATCH 096/122] added sleep --- .../aecu-examples/project1/migrations.author/script1.groovy | 3 ++- .../project1/migrations.author/script2.fallback.groovy | 3 ++- .../scripts/aecu/aecu-examples/project2/script1.groovy | 1 + .../scripts/aecu/aecu-examples/project2/script2.always.groovy | 4 +++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy index 1dd6b740..63bec6eb 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script1.groovy @@ -1 +1,2 @@ -println "Executing project1 - script1" \ No newline at end of file +println "Sample project1 - script1" +Thread.sleep(2000); diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy index 9afe049e..5a64c6f8 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/script2.fallback.groovy @@ -1 +1,2 @@ -println "Executing fallback project1 - script2" \ No newline at end of file +// Scripts with extension ".fallback.groovy" will be executed if the non-fallback script fails +println "Executing fallback script for project1 - script2" \ No newline at end of file diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy index dc9ea89f..aec4fa7f 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script1.groovy @@ -1,2 +1,3 @@ println "Executing project2 - script1" +Thread.sleep(2000); return "Done" diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy index ba5a3d0f..4e49522e 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project2/script2.always.groovy @@ -1 +1,3 @@ -println "Executing project2 - script2" \ No newline at end of file +// If you name your script ".always.groovy the it will be executed by install hook on each package deploy" +println "Executing a script with 'always' option" +Thread.sleep(2000); \ No newline at end of file From 50b3c792b2746649b85adc24f86d9ee1db3ee5f9 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 13:36:09 +0200 Subject: [PATCH 097/122] bindings/improvements-1: remover SetIntegerProperty and SetBooleanProperty - groove does the type conversion right therefore SetProperty with Object value covers all types --- .../console/bindings/ContentUpgrade.java | 23 +++----------- .../properties/SetBooleanProperty.java | 30 ------------------- .../properties/SetIntegerProperty.java | 30 ------------------- ...etStringProperty.java => SetProperty.java} | 7 ++--- .../tests_for_simpleContentUpdates.groovy | 16 +++++----- 5 files changed, 14 insertions(+), 92 deletions(-) delete mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java delete mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java rename core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/{SetStringProperty.java => SetProperty.java} (92%) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index 514f7a02..2b883e0f 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -5,9 +5,7 @@ import de.valtech.aecu.core.groovy.console.bindings.actions.properties.DeleteProperty; import de.valtech.aecu.core.groovy.console.bindings.actions.properties.MovePropertyToRelativePath; import de.valtech.aecu.core.groovy.console.bindings.actions.properties.RenameProperty; -import de.valtech.aecu.core.groovy.console.bindings.actions.properties.SetBooleanProperty; -import de.valtech.aecu.core.groovy.console.bindings.actions.properties.SetIntegerProperty; -import de.valtech.aecu.core.groovy.console.bindings.actions.properties.SetStringProperty; +import de.valtech.aecu.core.groovy.console.bindings.actions.properties.SetProperty; import de.valtech.aecu.core.groovy.console.bindings.actions.resource.CopyResourceToRelativePath; import de.valtech.aecu.core.groovy.console.bindings.actions.resource.DeleteResource; import de.valtech.aecu.core.groovy.console.bindings.actions.resource.MoveResourceToRelativePath; @@ -84,22 +82,9 @@ public ContentUpgrade filterWith(@Nonnull FilterBy filter) { /** * properties edit methods **/ - // TODO test with Object and see type conversion!!! - public ContentUpgrade doSetStringProperty(@Nonnull String name, String value) { - LOG.debug("doSetStringProperty: {} = {}", name, value); - actions.add(new SetStringProperty(name, value)); - return this; - } - - public ContentUpgrade doSetBooleanProperty(@Nonnull String name, Boolean value) { - LOG.debug("doSetBooleanProperty: {} = {}", name, value); - actions.add(new SetBooleanProperty(name, value)); - return this; - } - - public ContentUpgrade doSetIntegerProperty(@Nonnull String name, int value) { - LOG.debug("doSetIntegerProperty: {} = {}", name, value); - actions.add(new SetIntegerProperty(name, value)); + public ContentUpgrade doSetProperty(@Nonnull String name, Object value) { + LOG.debug("doSetProperty: {} = {}", name, value); + actions.add(new SetProperty(name, value)); return this; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java deleted file mode 100644 index dfb5ca48..00000000 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetBooleanProperty.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 Valtech GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> - */ -package de.valtech.aecu.core.groovy.console.bindings.actions.properties; - -import javax.annotation.Nonnull; - -/** - * @author Roxana Muresan - */ -public class SetBooleanProperty extends SetStringProperty { - - public SetBooleanProperty(@Nonnull String name, Boolean value) { - this.name = name; - this.value = value; - } -} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java deleted file mode 100644 index 2ef65262..00000000 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetIntegerProperty.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 Valtech GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> - */ -package de.valtech.aecu.core.groovy.console.bindings.actions.properties; - -import javax.annotation.Nonnull; - -/** - * @author Roxana Muresan - */ -public class SetIntegerProperty extends SetStringProperty { - - public SetIntegerProperty(@Nonnull String name, Integer value) { - this.name = name; - this.value = value; - } -} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetProperty.java similarity index 92% rename from core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java rename to core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetProperty.java index e2335756..3cd838a6 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetStringProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetProperty.java @@ -31,15 +31,12 @@ /** * @author Roxana Muresan */ -public class SetStringProperty implements Action { +public class SetProperty implements Action { protected String name; protected Object value; - protected SetStringProperty() { - } - - public SetStringProperty(@Nonnull String name, String value) { + public SetProperty(@Nonnull String name, Object value) { this.name = name; this.value = value; } diff --git a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy index 28e06452..646cc3a5 100644 --- a/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy +++ b/examples/src/main/content/jcr_root/etc/groovyconsole/scripts/aecu/aecu-examples/project1/migrations.author/tests_for_simpleContentUpdates.groovy @@ -15,10 +15,10 @@ println aecu.contentUpgradeBuilder() // filters .filterByProperties(conditionMap_Page) // actions - .doSetStringProperty("newStringProperty1", "aecu test with conditionMap_Page") - .doSetBooleanProperty("newBooleanProperty1", true) - .doSetIntegerProperty("newIntegerProperty1", 123) - .doRenameProperty("newStringProperty1", "delete_me_later") + .doSetProperty("newStringProperty1", "aecu test with conditionMap_Page") + .doSetProperty("newBooleanProperty1", true) + .doSetProperty("newIntegerProperty1", 123) +// .doRenameProperty("newStringProperty1", "delete_me_later") // .removeProperty("delete_me_later") .dryRun() @@ -41,9 +41,9 @@ println aecu.contentUpgradeBuilder() // filters .filterWith(complexFilter) // actions - .doSetStringProperty("newStringProperty2", "aecu test with conditionMap_Hero") - .doSetBooleanProperty("newBooleanProperty2", false) - .doSetIntegerProperty("newIntegerProperty2", 789) - .doRenameProperty("newStringProperty2", "delete_me_later2") + .doSetProperty("newStringProperty2", "aecu test with conditionMap_Hero") + .doSetProperty("newBooleanProperty2", false) + .doSetProperty("newIntegerProperty2", 789) +// .doRenameProperty("newStringProperty2", "delete_me_later2") // .removeProperty("delete_me_later") .dryRun() \ No newline at end of file From adda8c24e11cdd8635c5cf5fc9185ccfc96255db Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 16:22:10 +0200 Subject: [PATCH 098/122] bindings/improvements-1: added filters for node name check --- .../bindings/filters/FilterByNodeName.java | 38 +++++++++++++++++++ .../filters/FilterByNodeNameRegex.java | 38 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java new file mode 100644 index 00000000..79d5d4e7 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.filters; + +import org.apache.sling.api.resource.Resource; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class FilterByNodeName implements FilterBy { + + private String name; + + public FilterByNodeName(@Nonnull String name) { + this.name = name; + } + + @Override + public boolean filter(@Nonnull Resource resource) { + return resource.getName().equals(this.name); + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java new file mode 100644 index 00000000..9f59355a --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Valtech GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ +package de.valtech.aecu.core.groovy.console.bindings.filters; + +import org.apache.sling.api.resource.Resource; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class FilterByNodeNameRegex implements FilterBy { + + private String regex; + + public FilterByNodeNameRegex(@Nonnull String regex) { + this.regex = regex; + } + + @Override + public boolean filter(@Nonnull Resource resource) { + return resource.getName().matches(regex); + } +} From 8aedeeb4a9334413232f17fb18d95fa4e25988eb Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 17:09:16 +0200 Subject: [PATCH 099/122] bindings/improvements-1: added actions for the manipulation of multi-value properties --- .../console/bindings/ContentUpgrade.java | 22 ++++++ .../actions/multivalue/AddMultiValues.java | 67 +++++++++++++++++ .../actions/multivalue/RemoveMultiValues.java | 68 +++++++++++++++++ .../multivalue/ReplaceMultiValues.java | 74 +++++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java create mode 100644 core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index 2b883e0f..e4b81687 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -1,6 +1,9 @@ package de.valtech.aecu.core.groovy.console.bindings; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.actions.multivalue.AddMultiValues; +import de.valtech.aecu.core.groovy.console.bindings.actions.multivalue.RemoveMultiValues; +import de.valtech.aecu.core.groovy.console.bindings.actions.multivalue.ReplaceMultiValues; import de.valtech.aecu.core.groovy.console.bindings.actions.properties.CopyPropertyToRelativePath; import de.valtech.aecu.core.groovy.console.bindings.actions.properties.DeleteProperty; import de.valtech.aecu.core.groovy.console.bindings.actions.properties.MovePropertyToRelativePath; @@ -23,6 +26,7 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -112,6 +116,24 @@ public ContentUpgrade doMovePropertyToRelativePath(@Nonnull String name, String return this; } + public ContentUpgrade doAddValuesToMultiValueProperty(@Nonnull String name, @Nonnull String[] values) { + LOG.debug("doAddToMultiValueProperty: {} + {}", name, Arrays.toString(values)); + actions.add(new AddMultiValues(name, values)); + return this; + } + + public ContentUpgrade doRemoveValuesOfMultiValueProperty(@Nonnull String name, @Nonnull String[] values) { + LOG.debug("doRemoveValuesFromMultiValueProperty: {} - {}", name, Arrays.toString(values)); + actions.add(new RemoveMultiValues(name, values)); + return this; + } + + public ContentUpgrade doReplaceValuesOfMultiValueProperty(@Nonnull String name, @Nonnull String[] oldValues, @Nonnull String[] newValues) { + LOG.debug("doReplaceValuesOfMultiValueProperty: {} - {}", name, Arrays.toString(oldValues) + " + " + Arrays.toString(newValues)); + actions.add(new ReplaceMultiValues(name, oldValues, newValues)); + return this; + } + /** * resource edit methods **/ diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java new file mode 100644 index 00000000..fa3ef4d2 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.multivalue; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class AddMultiValues implements Action { + + private String name; + private String[] values; + + public AddMultiValues(@Nonnull String name, @Nonnull String[] values) { + this.name = name; + this.values = Arrays.stream(values).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); + } + + @Override + public String doAction(@Nonnull Resource resource) throws PersistenceException { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + if (properties != null) { + String[] currentValues = properties.get(name, String[].class); + List<String> valuesList = new ArrayList<>(); + if (currentValues != null && currentValues.length > 0) { + Collections.addAll(valuesList, currentValues); + } + Collections.addAll(valuesList, values); + properties.put(name, valuesList.toArray(new String[]{})); + + return "Adding values " + Arrays.toString(values) + " to multi-value property " + name + ": " + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); + } + return "WARNING: could not get ModifiableValueMap for resource " + resource.getPath(); + } +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java new file mode 100644 index 00000000..0345987b --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.multivalue; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class RemoveMultiValues implements Action { + + private String name; + private String[] values; + + public RemoveMultiValues(@Nonnull String name, @Nonnull String[] values) { + this.name = name; + this.values = Arrays.stream(values).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); + } + + @Override + public String doAction(@Nonnull Resource resource) throws PersistenceException { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + if (properties != null) { + String[] currentValues = properties.get(name, String[].class); + List<String> valuesList = new ArrayList<>(); + if (currentValues != null && currentValues.length > 0) { + Collections.addAll(valuesList, currentValues); + } + valuesList.removeAll(Arrays.asList(values)); + properties.put(name, valuesList.toArray(new String[]{})); + + return "Removing values " + Arrays.toString(values) + " from multi-value property " + name + ": " + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); + } + return "WARNING: could not get ModifiableValueMap for resource " + resource.getPath(); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java new file mode 100644 index 00000000..ba3db781 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package de.valtech.aecu.core.groovy.console.bindings.actions.multivalue; + +import de.valtech.aecu.core.groovy.console.bindings.actions.Action; + +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +/** + * @author Roxana Muresan + */ +public class ReplaceMultiValues implements Action { + + private String name; + private String[] oldValues; + private String[] newValues; + + public ReplaceMultiValues(@Nonnull String name, @Nonnull String[] oldValues, @Nonnull String[] newValues) { + this.name = name; + this.oldValues = Arrays.stream(oldValues).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); + this.newValues = Arrays.stream(newValues).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); + } + + @Override + public String doAction(@Nonnull Resource resource) throws PersistenceException { + ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); + if (properties != null) { + String[] currentValues = properties.get(name, String[].class); + List<String> valuesList = new ArrayList<>(); + if (currentValues != null && currentValues.length > 0) { + Collections.addAll(valuesList, currentValues); + } + + String warning = (oldValues.length != newValues.length) ? "WARNING: old values and new values length mismatch (old: " + Arrays.toString(oldValues) + " , new: " + Arrays.toString(newValues) + ")" + " -> the smaller length will be considered\n" : ""; + + for (int i = 0; i < oldValues.length && i < newValues.length; i++) { + Collections.replaceAll(valuesList, oldValues[i], newValues[i]); + } + properties.put(name, valuesList.toArray(new String[]{})); + + return warning + "Replacing values " + Arrays.toString(oldValues) + " with values " + Arrays.toString(newValues) + " for multi-value property " + name + ": " + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); + } + return "WARNING: could not get ModifiableValueMap for resource " + resource.getPath(); + } +} From a16d51006c39d99df22a61e3cf48ea2050a3782c Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 17:20:37 +0200 Subject: [PATCH 100/122] bindings/improvements-1: added methods for node name filtering in ContentUpgrade and added back printPath method --- .../console/bindings/ContentUpgrade.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index e4b81687..9b5b5a0f 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -1,6 +1,7 @@ package de.valtech.aecu.core.groovy.console.bindings; import de.valtech.aecu.core.groovy.console.bindings.actions.Action; +import de.valtech.aecu.core.groovy.console.bindings.actions.PrintPath; import de.valtech.aecu.core.groovy.console.bindings.actions.multivalue.AddMultiValues; import de.valtech.aecu.core.groovy.console.bindings.actions.multivalue.RemoveMultiValues; import de.valtech.aecu.core.groovy.console.bindings.actions.multivalue.ReplaceMultiValues; @@ -13,6 +14,8 @@ import de.valtech.aecu.core.groovy.console.bindings.actions.resource.DeleteResource; import de.valtech.aecu.core.groovy.console.bindings.actions.resource.MoveResourceToRelativePath; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterBy; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByNodeName; +import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByNodeNameRegex; import de.valtech.aecu.core.groovy.console.bindings.filters.FilterByProperties; import de.valtech.aecu.core.groovy.console.bindings.traversers.ForChildResourcesOf; import de.valtech.aecu.core.groovy.console.bindings.traversers.ForDescendantResourcesOf; @@ -77,6 +80,18 @@ public ContentUpgrade filterByProperties(@Nonnull Map<String, String> conditionP return this; } + public ContentUpgrade filterByNodeName(@Nonnull String nodeName) { + LOG.debug("filterByNodeName: {}", nodeName); + filter = new FilterByNodeName(nodeName); + return this; + } + + public ContentUpgrade filterByNodeNameRegex(@Nonnull String regex) { + LOG.debug("filterByNodeNameRegex: {}", regex); + filter = new FilterByNodeNameRegex(regex); + return this; + } + public ContentUpgrade filterWith(@Nonnull FilterBy filter) { LOG.debug("filterWith: {}", filter); this.filter = filter; @@ -155,6 +170,15 @@ public ContentUpgrade doDeleteResource() { return this; } + /** + * Print path + */ + public ContentUpgrade printPath() { + LOG.debug("printPath"); + actions.add(new PrintPath()); + return this; + } + /** * runner methods **/ From eae2da982ae7ff262746a53367eb9812b5567db3 Mon Sep 17 00:00:00 2001 From: Roxana Muresan <roxana.muresan@valtech.de> Date: Thu, 12 Jul 2018 17:27:40 +0200 Subject: [PATCH 101/122] bindings/improvements-1: updated the copyright header to the latest --- .../CopyPropertyToRelativePath.java | 25 ++++++++++------- .../MovePropertyToRelativePath.java | 25 ++++++++++------- .../resource/CopyResourceToRelativePath.java | 25 ++++++++++------- .../actions/resource/DeleteResource.java | 25 ++++++++++------- .../resource/MoveResourceToRelativePath.java | 25 ++++++++++------- .../bindings/filters/FilterByNodeName.java | 27 +++++++++++-------- .../filters/FilterByNodeNameRegex.java | 27 +++++++++++-------- 7 files changed, 107 insertions(+), 72 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java index 93971dd4..1109ca65 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java index f1bba661..5401bbce 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java index 84a4623e..2976d4bb 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java index d2a672c8..9cfe9c06 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java index 0b7d3eb6..df8eeec6 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java @@ -1,18 +1,23 @@ /* * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java index 79d5d4e7..ae329a27 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java @@ -1,18 +1,23 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java index 9f59355a..afc8b021 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java @@ -1,18 +1,23 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * This program 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 General Public License for more details. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; From 03d0d7f43c7034ca293a80bf09cfdd4177275250 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 13 Jul 2018 15:11:42 +0200 Subject: [PATCH 102/122] JavaDoc --- .../de/valtech/aecu/service/AecuService.java | 12 ++++++++- .../de/valtech/aecu/service/HistoryEntry.java | 25 +++++++++++++++++++ .../de/valtech/aecu/service/package-info.java | 7 ++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 5a18dbfc..9d940bcc 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -26,7 +26,17 @@ import org.osgi.annotation.versioning.ProviderType; /** - * Service interface for AECU. + * Service interface for AECU. Use this to execute scripts or query the history. + * <br> + * <br> + * How to perform an execution: + * <ol> + * <li>Get a list of files to execute using {@link #getFiles(String) getFiles}. This will filter all files that do not match the run mode and any fallback scripts.</li> + * <li>Start a new history entry to store your results using {@link #createHistoryEntry() createHistoryEntry}. This store a new run with in-progress state.</li> + * <li>Execute your files one by one with {@link #execute(String) execute}</li> + * <li>Store each script run in history using {@link #storeExecutionInHistory(HistoryEntry, ExecutionResult) storeExecutionInHistory}</li> + * <li>Mark the run as done by closing the history with {@link #finishHistoryEntry(HistoryEntry) finishHistoryEntry}</li> + * </ol> * * @author Roland Gruber */ diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java index 9f8a92bb..5039823e 100644 --- a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -35,15 +35,27 @@ public interface HistoryEntry { * Execution state (e.g. running) */ public enum STATE { + /** Execution ongoing */ RUNNING("Running"), + /** Execution finished */ FINISHED("Finished"); private String label; + /** + * Constructor + * + * @param label label + */ private STATE(String label) { this.label = label; } + /** + * Returns the human-readable label for this result. + * + * @return label + */ public String getLabel() { return label; } @@ -55,16 +67,29 @@ public String getLabel() { * Execution result (e.g. successful) */ public enum RESULT { + /** All scripts executed successfully */ SUCCESS("Success"), + /** Execution of one or more scripts failed */ FAILURE("Failed"), + /** Execution not yet finished */ UNKNOWN("Unknown"); private String label; + /** + * Constructor + * + * @param label label + */ private RESULT(String label) { this.label = label; } + /** + * Returns the human-readable label for this result. + * + * @return label + */ public String getLabel() { return label; } diff --git a/api/src/main/java/de/valtech/aecu/service/package-info.java b/api/src/main/java/de/valtech/aecu/service/package-info.java index f7400584..e5a36b36 100644 --- a/api/src/main/java/de/valtech/aecu/service/package-info.java +++ b/api/src/main/java/de/valtech/aecu/service/package-info.java @@ -20,6 +20,13 @@ * SOFTWARE. */ +/** + * This package contains the service API for AEM Easy Content Upgrade (AECU). + * You can use this to integrate AECU into your own software. + * See {@link de.valtech.aecu.service.AecuService} for a starting point. + * + * @author Roland Gruber + */ @Version("1.0") package de.valtech.aecu.service; From 09ae1d0fbc0311117e73a8cc824e0e11f99293a3 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 13 Jul 2018 15:51:52 +0200 Subject: [PATCH 103/122] formatting --- .../valtech/aecu/service/AecuException.java | 29 ++++++------ .../de/valtech/aecu/service/AecuService.java | 46 +++++++++---------- .../valtech/aecu/service/ExecutionResult.java | 37 +++++++-------- .../de/valtech/aecu/service/HistoryEntry.java | 29 ++++++------ .../de/valtech/aecu/service/package-info.java | 35 +++++++------- 5 files changed, 81 insertions(+), 95 deletions(-) diff --git a/api/src/main/java/de/valtech/aecu/service/AecuException.java b/api/src/main/java/de/valtech/aecu/service/AecuException.java index b6b72b20..02a8746e 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuException.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuException.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.service; diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index 9d940bcc..b7e9c155 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.service; @@ -26,16 +23,19 @@ import org.osgi.annotation.versioning.ProviderType; /** - * Service interface for AECU. Use this to execute scripts or query the history. - * <br> + * Service interface for AECU. Use this to execute scripts or query the history. <br> * <br> * How to perform an execution: * <ol> - * <li>Get a list of files to execute using {@link #getFiles(String) getFiles}. This will filter all files that do not match the run mode and any fallback scripts.</li> - * <li>Start a new history entry to store your results using {@link #createHistoryEntry() createHistoryEntry}. This store a new run with in-progress state.</li> - * <li>Execute your files one by one with {@link #execute(String) execute}</li> - * <li>Store each script run in history using {@link #storeExecutionInHistory(HistoryEntry, ExecutionResult) storeExecutionInHistory}</li> - * <li>Mark the run as done by closing the history with {@link #finishHistoryEntry(HistoryEntry) finishHistoryEntry}</li> + * <li>Get a list of files to execute using {@link #getFiles(String) getFiles}. This will filter all + * files that do not match the run mode and any fallback scripts.</li> + * <li>Start a new history entry to store your results using {@link #createHistoryEntry() + * createHistoryEntry}. This store a new run with in-progress state.</li> + * <li>Execute your files one by one with {@link #execute(String) execute}</li> + * <li>Store each script run in history using + * {@link #storeExecutionInHistory(HistoryEntry, ExecutionResult) storeExecutionInHistory}</li> + * <li>Mark the run as done by closing the history with {@link #finishHistoryEntry(HistoryEntry) + * finishHistoryEntry}</li> * </ol> * * @author Roland Gruber diff --git a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java index 1f1d0b73..d23bd6fd 100644 --- a/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java +++ b/api/src/main/java/de/valtech/aecu/service/ExecutionResult.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.service; @@ -47,7 +44,8 @@ public class ExecutionResult { * @param fallbackResult fallback script result * @param path script path */ - public ExecutionResult(boolean success, String time, String result, String output, ExecutionResult fallbackResult, String path) { + public ExecutionResult(boolean success, String time, String result, String output, ExecutionResult fallbackResult, + String path) { this.success = success; this.output = output; this.time = time; @@ -112,10 +110,7 @@ public String getPath() { @Override public String toString() { - StringBuilder stringVal = new StringBuilder( - "Successful: " + Boolean.toString(success) + - "Path: " + path - ); + StringBuilder stringVal = new StringBuilder("Successful: " + Boolean.toString(success) + "Path: " + path); if (StringUtils.isNotBlank(time)) { stringVal.append("\n" + "Execution time: " + time); } diff --git a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java index 5039823e..e3940e98 100644 --- a/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java +++ b/api/src/main/java/de/valtech/aecu/service/HistoryEntry.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.service; diff --git a/api/src/main/java/de/valtech/aecu/service/package-info.java b/api/src/main/java/de/valtech/aecu/service/package-info.java index e5a36b36..e514cdd1 100644 --- a/api/src/main/java/de/valtech/aecu/service/package-info.java +++ b/api/src/main/java/de/valtech/aecu/service/package-info.java @@ -1,29 +1,26 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** - * This package contains the service API for AEM Easy Content Upgrade (AECU). - * You can use this to integrate AECU into your own software. - * See {@link de.valtech.aecu.service.AecuService} for a starting point. + * This package contains the service API for AEM Easy Content Upgrade (AECU). You can use this to + * integrate AECU into your own software. See {@link de.valtech.aecu.service.AecuService} for a + * starting point. * * @author Roland Gruber */ From aef0662f8e992295c57d91e7002f12acf26288fc Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 13 Jul 2018 15:53:42 +0200 Subject: [PATCH 104/122] Eclipse formatter --- docs/formatter/eclipse-aecu.xml | 318 ++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 docs/formatter/eclipse-aecu.xml diff --git a/docs/formatter/eclipse-aecu.xml b/docs/formatter/eclipse-aecu.xml new file mode 100644 index 00000000..a7317795 --- /dev/null +++ b/docs/formatter/eclipse-aecu.xml @@ -0,0 +1,318 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<profiles version="14"> +<profile kind="CodeFormatterProfile" name="AECU" version="14"> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/> +<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.release" value="enabled"/> +<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/> +<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/> +<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/> +<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="3"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> +<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/> +<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/> +<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/> +<setting id="org.eclipse.jdt.core.compiler.source" value="10"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="10"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.compliance" value="10"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="130"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> +</profile> +</profiles> From e3b1f5f269fad42c845f360cf9ce69a612b691c9 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 13 Jul 2018 15:58:30 +0200 Subject: [PATCH 105/122] formatting --- .../console/bindings/ContentUpgrade.java | 12 ++-- .../console/bindings/SimpleContentUpdate.java | 31 +++++----- .../console/bindings/actions/Action.java | 29 ++++----- .../console/bindings/actions/PrintPath.java | 29 ++++----- .../actions/multivalue/AddMultiValues.java | 36 ++++++----- .../actions/multivalue/RemoveMultiValues.java | 36 ++++++----- .../multivalue/ReplaceMultiValues.java | 44 +++++++------- .../CopyPropertyToRelativePath.java | 43 ++++++------- .../actions/properties/DeleteProperty.java | 29 ++++----- .../MovePropertyToRelativePath.java | 35 ++++++----- .../actions/properties/RenameProperty.java | 29 ++++----- .../actions/properties/SetProperty.java | 32 +++++----- .../resource/CopyResourceToRelativePath.java | 29 ++++----- .../actions/resource/DeleteResource.java | 29 ++++----- .../resource/MoveResourceToRelativePath.java | 29 ++++----- .../console/bindings/filters/ANDFilter.java | 34 +++++------ .../console/bindings/filters/FilterBy.java | 29 ++++----- .../bindings/filters/FilterByNodeName.java | 29 ++++----- .../filters/FilterByNodeNameRegex.java | 29 ++++----- .../bindings/filters/FilterByProperties.java | 32 +++++----- .../console/bindings/filters/NOTFilter.java | 29 ++++----- .../console/bindings/filters/ORFilter.java | 34 +++++------ .../AecuBindingExtensionProvider.java | 32 +++++----- .../AecuStarImportExtensionProvider.java | 29 ++++----- .../traversers/ForChildResourcesOf.java | 32 +++++----- .../traversers/ForDescendantResourcesOf.java | 35 ++++++----- .../bindings/traversers/ForResources.java | 32 +++++----- .../bindings/traversers/TraversData.java | 32 +++++----- .../core/healthcheck/LastRunHealthCheck.java | 40 +++++-------- .../healthcheck/SelfCheckHealthCheck.java | 40 +++++-------- .../aecu/core/history/HistoryUtil.java | 43 +++++++------ .../core/installhook/AecuInstallHook.java | 35 ++++++----- .../core/installhook/AecuTrackerListener.java | 29 ++++----- .../aecu/core/jmx/AecuServiceMBean.java | 29 ++++----- .../aecu/core/jmx/AecuServiceMBeanImpl.java | 35 +++++------ .../PurgeHistoryConfiguration.java | 36 +++++------ .../core/maintenance/PurgeHistoryTask.java | 39 +++++------- .../core/model/execute/ExecuteDataSource.java | 29 ++++----- .../core/model/history/HistoryDataItem.java | 29 ++++----- .../core/model/history/HistoryDataSource.java | 32 +++++----- .../core/model/history/HistoryOverview.java | 29 ++++----- .../aecu/core/service/AecuServiceImpl.java | 35 +++++------ .../core/service/GroovyConsoleRequest.java | 38 +++++------- .../aecu/core/service/HistoryEntryImpl.java | 29 ++++----- .../ServiceResourceResolverService.java | 29 ++++----- .../aecu/core/servlets/BaseServlet.java | 29 ++++----- .../aecu/core/servlets/ExecutionServlet.java | 60 +++++++++---------- .../aecu/core/history/HistoryUtilTest.java | 29 ++++----- .../core/service/AecuServiceImplTest.java | 29 ++++----- 49 files changed, 728 insertions(+), 875 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index 9b5b5a0f..ec107801 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -119,13 +119,15 @@ public ContentUpgrade doRenameProperty(@Nonnull String oldName, @Nonnull String return this; } - public ContentUpgrade doCopyPropertyToRelativePath(@Nonnull String name, String newName, @Nonnull String relativeResourcePath) { + public ContentUpgrade doCopyPropertyToRelativePath(@Nonnull String name, String newName, + @Nonnull String relativeResourcePath) { LOG.debug("doCopyProperty: {} to {}", name, relativeResourcePath); actions.add(new CopyPropertyToRelativePath(name, newName, resourceResolver, relativeResourcePath)); return this; } - public ContentUpgrade doMovePropertyToRelativePath(@Nonnull String name, String newName, @Nonnull String relativeResourcePath) { + public ContentUpgrade doMovePropertyToRelativePath(@Nonnull String name, String newName, + @Nonnull String relativeResourcePath) { LOG.debug("doMoveProperty: {} to {}", name, relativeResourcePath); actions.add(new MovePropertyToRelativePath(name, newName, resourceResolver, relativeResourcePath)); return this; @@ -143,8 +145,10 @@ public ContentUpgrade doRemoveValuesOfMultiValueProperty(@Nonnull String name, @ return this; } - public ContentUpgrade doReplaceValuesOfMultiValueProperty(@Nonnull String name, @Nonnull String[] oldValues, @Nonnull String[] newValues) { - LOG.debug("doReplaceValuesOfMultiValueProperty: {} - {}", name, Arrays.toString(oldValues) + " + " + Arrays.toString(newValues)); + public ContentUpgrade doReplaceValuesOfMultiValueProperty(@Nonnull String name, @Nonnull String[] oldValues, + @Nonnull String[] newValues) { + LOG.debug("doReplaceValuesOfMultiValueProperty: {} - {}", name, + Arrays.toString(oldValues) + " + " + Arrays.toString(newValues)); actions.add(new ReplaceMultiValues(name, oldValues, newValues)); return this; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java index 7e73c37e..e3019216 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/SimpleContentUpdate.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings; @@ -41,4 +38,4 @@ public ContentUpgrade contentUpgradeBuilder() { return new ContentUpgrade(resourceResolver); } -} \ No newline at end of file +} diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java index fc39d038..9be0adba 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/Action.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java index b805d457..b527af8d 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/PrintPath.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java index fa3ef4d2..90cb88df 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/AddMultiValues.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.multivalue; @@ -45,7 +42,7 @@ public class AddMultiValues implements Action { public AddMultiValues(@Nonnull String name, @Nonnull String[] values) { this.name = name; - this.values = Arrays.stream(values).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); + this.values = Arrays.stream(values).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[] {}); } @Override @@ -58,9 +55,10 @@ public String doAction(@Nonnull Resource resource) throws PersistenceException { Collections.addAll(valuesList, currentValues); } Collections.addAll(valuesList, values); - properties.put(name, valuesList.toArray(new String[]{})); + properties.put(name, valuesList.toArray(new String[] {})); - return "Adding values " + Arrays.toString(values) + " to multi-value property " + name + ": " + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); + return "Adding values " + Arrays.toString(values) + " to multi-value property " + name + ": " + + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); } return "WARNING: could not get ModifiableValueMap for resource " + resource.getPath(); } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java index 0345987b..93928cd0 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/RemoveMultiValues.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.multivalue; @@ -45,7 +42,7 @@ public class RemoveMultiValues implements Action { public RemoveMultiValues(@Nonnull String name, @Nonnull String[] values) { this.name = name; - this.values = Arrays.stream(values).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); + this.values = Arrays.stream(values).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[] {}); } @Override @@ -58,9 +55,10 @@ public String doAction(@Nonnull Resource resource) throws PersistenceException { Collections.addAll(valuesList, currentValues); } valuesList.removeAll(Arrays.asList(values)); - properties.put(name, valuesList.toArray(new String[]{})); + properties.put(name, valuesList.toArray(new String[] {})); - return "Removing values " + Arrays.toString(values) + " from multi-value property " + name + ": " + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); + return "Removing values " + Arrays.toString(values) + " from multi-value property " + name + ": " + + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); } return "WARNING: could not get ModifiableValueMap for resource " + resource.getPath(); } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java index ba3db781..b975158e 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/multivalue/ReplaceMultiValues.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.multivalue; @@ -46,8 +43,8 @@ public class ReplaceMultiValues implements Action { public ReplaceMultiValues(@Nonnull String name, @Nonnull String[] oldValues, @Nonnull String[] newValues) { this.name = name; - this.oldValues = Arrays.stream(oldValues).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); - this.newValues = Arrays.stream(newValues).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[]{}); + this.oldValues = Arrays.stream(oldValues).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[] {}); + this.newValues = Arrays.stream(newValues).filter(f -> f != null).collect(Collectors.toList()).toArray(new String[] {}); } @Override @@ -60,14 +57,19 @@ public String doAction(@Nonnull Resource resource) throws PersistenceException { Collections.addAll(valuesList, currentValues); } - String warning = (oldValues.length != newValues.length) ? "WARNING: old values and new values length mismatch (old: " + Arrays.toString(oldValues) + " , new: " + Arrays.toString(newValues) + ")" + " -> the smaller length will be considered\n" : ""; + String warning = (oldValues.length != newValues.length) + ? "WARNING: old values and new values length mismatch (old: " + Arrays.toString(oldValues) + " , new: " + + Arrays.toString(newValues) + ")" + " -> the smaller length will be considered\n" + : ""; for (int i = 0; i < oldValues.length && i < newValues.length; i++) { Collections.replaceAll(valuesList, oldValues[i], newValues[i]); } - properties.put(name, valuesList.toArray(new String[]{})); + properties.put(name, valuesList.toArray(new String[] {})); - return warning + "Replacing values " + Arrays.toString(oldValues) + " with values " + Arrays.toString(newValues) + " for multi-value property " + name + ": " + Arrays.toString(currentValues) + " results in " + valuesList + " for resource " + resource.getPath(); + return warning + "Replacing values " + Arrays.toString(oldValues) + " with values " + Arrays.toString(newValues) + + " for multi-value property " + name + ": " + Arrays.toString(currentValues) + " results in " + valuesList + + " for resource " + resource.getPath(); } return "WARNING: could not get ModifiableValueMap for resource " + resource.getPath(); } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java index 1109ca65..74719c2b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/CopyPropertyToRelativePath.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; @@ -40,7 +37,8 @@ public class CopyPropertyToRelativePath implements Action { private String newName; private ResourceResolver resourceResolver; - public CopyPropertyToRelativePath(@Nonnull String name, String newName, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { + public CopyPropertyToRelativePath(@Nonnull String name, String newName, @Nonnull ResourceResolver resourceResolver, + @Nonnull String relativeResourcePath) { this.name = name; this.newName = newName; this.resourceResolver = resourceResolver; @@ -51,14 +49,19 @@ public CopyPropertyToRelativePath(@Nonnull String name, String newName, @Nonnull public String doAction(@Nonnull Resource resource) { ValueMap sourceProperties = resource.adaptTo(ValueMap.class); - Resource destinationResource = resourceResolver.getResource(resource, relativeResourcePath);// TODO null check!!!! - ModifiableValueMap destinationProperties = destinationResource.adaptTo(ModifiableValueMap.class);// TODO null check!!!! + Resource destinationResource = resourceResolver.getResource(resource, relativeResourcePath);// TODO + // null + // check!!!! + ModifiableValueMap destinationProperties = destinationResource.adaptTo(ModifiableValueMap.class);// TODO + // null + // check!!!! Object propValue = sourceProperties.get(name); String key = (newName != null) ? newName : name; destinationProperties.put(key, propValue); - return "Coping property " + name + " from " + resource.getPath() + " to resource " + destinationResource.getPath() + " as " + key; + return "Coping property " + name + " from " + resource.getPath() + " to resource " + destinationResource.getPath() + + " as " + key; } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java index 748acecb..5a391702 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/DeleteProperty.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java index 5401bbce..60f5c818 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/MovePropertyToRelativePath.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; @@ -39,7 +36,8 @@ public class MovePropertyToRelativePath implements Action { private String newName; private ResourceResolver resourceResolver; - public MovePropertyToRelativePath(@Nonnull String name, String newName, @Nonnull ResourceResolver resourceResolver, @Nonnull String relativeResourcePath) { + public MovePropertyToRelativePath(@Nonnull String name, String newName, @Nonnull ResourceResolver resourceResolver, + @Nonnull String relativeResourcePath) { this.name = name; this.newName = newName; this.resourceResolver = resourceResolver; @@ -58,7 +56,8 @@ public String doAction(@Nonnull Resource resource) { targetProperties.put(key, propValue); sourceProperties.remove(name); - return "Moving property " + name + " from " + resource.getPath() + " to resource " + targetResource.getPath() + " as " + key; + return "Moving property " + name + " from " + resource.getPath() + " to resource " + targetResource.getPath() + " as " + + key; } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java index 4141aa3b..dc284eed 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/RenameProperty.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetProperty.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetProperty.java index 3cd838a6..f3471682 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetProperty.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/properties/SetProperty.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.properties; @@ -45,6 +42,7 @@ public SetProperty(@Nonnull String name, Object value) { public String doAction(@Nonnull Resource resource) { ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class); properties.put(name, value); - return "Setting " + value.getClass().getSimpleName() + " property " + name + "=" + value + " for resource " + resource.getPath(); + return "Setting " + value.getClass().getSimpleName() + " property " + name + "=" + value + " for resource " + + resource.getPath(); } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java index 2976d4bb..1d44c3fc 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/CopyResourceToRelativePath.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java index 9cfe9c06..fd04374d 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/DeleteResource.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java index df8eeec6..1b094705 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/actions/resource/MoveResourceToRelativePath.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.actions.resource; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java index 3c847dd5..154eaea8 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ANDFilter.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; @@ -41,10 +38,7 @@ public ANDFilter(@Nonnull List<FilterBy> filters) { @Override public boolean filter(@Nonnull Resource resource) { - boolean foundFalse = filters - .parallelStream() - .filter(f -> f.filter(resource) == false) - .findAny().isPresent(); + boolean foundFalse = filters.parallelStream().filter(f -> f.filter(resource) == false).findAny().isPresent(); return !foundFalse; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java index f893aa49..99f316f1 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterBy.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java index ae329a27..d66cc60c 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeName.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java index afc8b021..1bba5942 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByNodeNameRegex.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java index b486136b..6c11bd8b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/FilterByProperties.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; @@ -47,7 +44,8 @@ public boolean filter(@Nonnull Resource resource) { String conditionValue = conditionProperties.get(key); String propertiesValue = properties.get(key, String.class); - if ((conditionValue == null && propertiesValue != null) || (conditionValue != null && !conditionValue.equals(propertiesValue))) { + if ((conditionValue == null && propertiesValue != null) + || (conditionValue != null && !conditionValue.equals(propertiesValue))) { return false; } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java index fae3a298..ba87296b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/NOTFilter.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java index 34dd09c5..bb637d02 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/filters/ORFilter.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.filters; @@ -41,10 +38,7 @@ public ORFilter(List<FilterBy> filters) { @Override public boolean filter(@Nonnull Resource resource) { - boolean foundTrue = filters - .parallelStream() - .filter(f -> f.filter(resource)) - .findAny().isPresent(); + boolean foundTrue = filters.parallelStream().filter(f -> f.filter(resource)).findAny().isPresent(); return foundTrue; } } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java index e860f92c..de08676b 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuBindingExtensionProvider.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.provider; @@ -57,7 +54,8 @@ public Binding getBinding(SlingHttpServletRequest request) { try { binding.setVariable("aecu", new SimpleContentUpdate(resourceResolverService.getContentMigratorResourceResolver())); } catch (LoginException e) { - LOG.error("Failed to get resource resolver for aecu-content-migrator, make sure you all the configurations needed for this system user are deployed."); + LOG.error( + "Failed to get resource resolver for aecu-content-migrator, make sure you all the configurations needed for this system user are deployed."); } return binding; } diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java index 8b7e2b07..15147d97 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/provider/AecuStarImportExtensionProvider.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.provider; diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java index be871479..86f7d690 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForChildResourcesOf.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; @@ -45,7 +42,8 @@ public ForChildResourcesOf(@Nonnull String path) { @Override - public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, + @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { Resource parentResource = resourceResolver.getResource(path); if (parentResource != null) { Iterator<Resource> resourceIterator = resourceResolver.listChildren(parentResource); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java index a31e3165..71cf7dce 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForDescendantResourcesOf.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; @@ -45,14 +42,16 @@ public ForDescendantResourcesOf(@Nonnull String path) { @Override - public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, + @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { Resource parentResource = resourceResolver.getResource(path); if (parentResource != null) { traverseChildResourcesRecursive(resourceResolver, parentResource, filter, action, stringBuffer, dryRun); } } - private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, Resource resource, FilterBy filter, Action action, StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { + private void traverseChildResourcesRecursive(ResourceResolver resourceResolver, Resource resource, FilterBy filter, + Action action, StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { if (resource != null && resource.hasChildren()) { Iterator<Resource> childResources = resource.listChildren(); while (childResources.hasNext()) { diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java index e22bb5fe..a4f2fe41 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/ForResources.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; @@ -42,7 +39,8 @@ public ForResources(@Nonnull String[] paths) { } @Override - public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { + public void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, + @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException { for (String path : paths) { if (path != null) { Resource resource = resourceResolver.getResource(path); diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java index 0bb0fa8a..5f0e75e1 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/traversers/TraversData.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.groovy.console.bindings.traversers; @@ -34,6 +31,7 @@ */ public interface TraversData { - void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException; + void traverse(@Nonnull ResourceResolver resourceResolver, FilterBy filter, @Nonnull Action action, + @Nonnull StringBuffer stringBuffer, boolean dryRun) throws PersistenceException; } diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java index daee91ed..76fa6f92 100644 --- a/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/LastRunHealthCheck.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.healthcheck; @@ -38,15 +35,8 @@ * * @author Roland Gruber */ -@Component( - immediate = true, - service = HealthCheck.class, - property = { - HealthCheck.TAGS + "=aecu", - HealthCheck.NAME + "=AECU Last Run", - HealthCheck.MBEAN_NAME + "=aecuLastRunHCmBean" - } -) +@Component(immediate = true, service = HealthCheck.class, property = {HealthCheck.TAGS + "=aecu", + HealthCheck.NAME + "=AECU Last Run", HealthCheck.MBEAN_NAME + "=aecuLastRunHCmBean"}) public class LastRunHealthCheck implements HealthCheck { @Reference diff --git a/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java index baf9728e..74d2a107 100644 --- a/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java +++ b/core/src/main/java/de/valtech/aecu/core/healthcheck/SelfCheckHealthCheck.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.healthcheck; @@ -36,15 +33,8 @@ * * @author Roland Gruber */ -@Component( - immediate = true, - service = HealthCheck.class, - property = { - HealthCheck.TAGS + "=aecu", - HealthCheck.NAME + "=AECU Self Check", - HealthCheck.MBEAN_NAME + "=aecuSelfCheckHCmBean" - } -) +@Component(immediate = true, service = HealthCheck.class, property = {HealthCheck.TAGS + "=aecu", + HealthCheck.NAME + "=AECU Self Check", HealthCheck.MBEAN_NAME + "=aecuSelfCheckHCmBean"}) public class SelfCheckHealthCheck implements HealthCheck { @Reference diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index b6124e58..185ac9d6 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.history; @@ -84,7 +81,8 @@ public class HistoryUtil { public HistoryEntry createHistoryEntry(ResourceResolver resolver) throws AecuException { HistoryEntryImpl history = new HistoryEntryImpl(); Calendar start = new GregorianCalendar(); - String basePath = HISTORY_BASE + "/" + start.get(Calendar.YEAR) + "/" + (start.get(Calendar.MONTH) + 1) + "/" + start.get(Calendar.DAY_OF_MONTH); + String basePath = HISTORY_BASE + "/" + start.get(Calendar.YEAR) + "/" + (start.get(Calendar.MONTH) + 1) + "/" + + start.get(Calendar.DAY_OF_MONTH); String nodeName = generateHistoryNodeName(); String nodePath = basePath + "/" + nodeName; createPath(basePath, resolver, JcrResourceConstants.NT_SLING_ORDERED_FOLDER); @@ -108,7 +106,8 @@ public HistoryEntry createHistoryEntry(ResourceResolver resolver) throws AecuExc * @param resolver resource resolver * @throws AecuException error inserting history entry */ - public void storeExecutionInHistory(HistoryEntry history, ExecutionResult result, ResourceResolver resolver) throws AecuException { + public void storeExecutionInHistory(HistoryEntry history, ExecutionResult result, ResourceResolver resolver) + throws AecuException { String path = history.getRepositoryPath() + "/" + history.getSingleResults().size(); saveExecutionResultInHistory(result, path, resolver); } @@ -204,8 +203,7 @@ private Resource ascendToLastRun(Resource resource) { } /** - * Descends in history till a previous sibling is found. - * Descending stops at history base level + * Descends in history till a previous sibling is found. Descending stops at history base level * * @param current current resource * @return previous sibling @@ -325,7 +323,8 @@ private ExecutionResult readHistorySingleResult(Resource resource) { return result; } - private void saveExecutionResultInHistory(ExecutionResult result, String path, ResourceResolver resolver) throws AecuException { + private void saveExecutionResultInHistory(ExecutionResult result, String path, ResourceResolver resolver) + throws AecuException { createPath(path, resolver, "nt:unstructured"); Resource entry = resolver.getResource(path); ModifiableValueMap values = entry.adaptTo(ModifiableValueMap.class); @@ -394,7 +393,7 @@ public void purgeHistory(ResourceResolver resolver, int daysToKeep) throws Persi Calendar calendar = new GregorianCalendar(); calendar.add(Calendar.DAY_OF_MONTH, -daysToKeep); LOG.debug("Starting purge with limit " + calendar.getTime().toString()); - deleteRecursive(base.listChildren(), calendar, new int[]{Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH}); + deleteRecursive(base.listChildren(), calendar, new int[] {Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH}); } /** diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java index 58d9f886..b30e7da2 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.installhook; @@ -95,9 +92,11 @@ public void execute(InstallContext installContext) throws PackageException { LOG.info("Executed script {}: {}", groovyScriptPath, result.getOutput()); } aecuService.finishHistoryEntry(installationHistory); - // TODO: from my point of view the installation should not be failed in case a fallback script was executed successfully + // TODO: from my point of view the installation should not be failed in case + // a fallback script was executed successfully if (!installationHistory.getResult().equals(HistoryEntry.RESULT.SUCCESS)) { - throw new PackageException("Failed installation, check installation history at " + installationHistory.getRepositoryPath()); + throw new PackageException("Failed installation, check installation history at " + + installationHistory.getRepositoryPath()); } } break; diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java index 4618139e..f1be7a95 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.installhook; diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index 1938a9fb..c6802db8 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.jmx; diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 68ed516d..41f8b22f 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.jmx; @@ -35,10 +32,8 @@ import de.valtech.aecu.service.ExecutionResult; import de.valtech.aecu.service.HistoryEntry; -@Component(service = {AecuServiceMBean.class}, immediate = true, property = { - "jmx.objectname=de.valtech:type=AECU", - "pattern=/.*" -}) +@Component(service = {AecuServiceMBean.class}, immediate = true, + property = {"jmx.objectname=de.valtech:type=AECU", "pattern=/.*"}) public class AecuServiceMBeanImpl extends AnnotatedStandardMBean implements AecuServiceMBean { @Reference diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java index 4c81496e..e49dbf77 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryConfiguration.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.maintenance; @@ -33,11 +30,8 @@ @ObjectClassDefinition(name = "AECU Purge history configuration") public @interface PurgeHistoryConfiguration { - @AttributeDefinition( - type = AttributeType.INTEGER, - name = "Days to keep", - description = "Entries younger than this will not be removed" - ) + @AttributeDefinition(type = AttributeType.INTEGER, name = "Days to keep", + description = "Entries younger than this will not be removed") int daysToKeep(); } diff --git a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java index 29a838e5..d47cd755 100644 --- a/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java +++ b/core/src/main/java/de/valtech/aecu/core/maintenance/PurgeHistoryTask.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.maintenance; @@ -43,13 +40,9 @@ * * @author Roland Gruber */ -@Component( - property = { - MaintenanceConstants.PROPERTY_TASK_NAME + "=AECUPurgeHistory", - MaintenanceConstants.PROPERTY_TASK_TITLE + "=AECU Purge History", - JobExecutor.PROPERTY_TOPICS + "=" + MaintenanceConstants.TASK_TOPIC_PREFIX + "AECUPurgeHistory", - } -) +@Component(property = {MaintenanceConstants.PROPERTY_TASK_NAME + "=AECUPurgeHistory", + MaintenanceConstants.PROPERTY_TASK_TITLE + "=AECU Purge History", + JobExecutor.PROPERTY_TOPICS + "=" + MaintenanceConstants.TASK_TOPIC_PREFIX + "AECUPurgeHistory",}) @Designate(ocd = PurgeHistoryConfiguration.class) public class PurgeHistoryTask implements JobExecutor { diff --git a/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java index da15dbac..459da67d 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java +++ b/core/src/main/java/de/valtech/aecu/core/model/execute/ExecuteDataSource.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.model.execute; diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java index 9612414c..1a353ee2 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataItem.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.model.history; diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java index fab84ad3..1a53dba2 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryDataSource.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.model.history; @@ -95,7 +92,8 @@ public Iterator<Resource> iterator() { for (HistoryEntry historyEntry : historyEntries) { ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>()); vm.put(ATTR_HISTORY, historyEntry); - entries.add(new ValueMapResource(request.getResourceResolver(), historyEntry.getRepositoryPath(), ITEM_TYPE, vm)); + entries.add(new ValueMapResource(request.getResourceResolver(), historyEntry.getRepositoryPath(), + ITEM_TYPE, vm)); } } catch (AecuException e) { LOG.error("Unable to read history entries", e); diff --git a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java index 4472e94e..02db4c7a 100644 --- a/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java +++ b/core/src/main/java/de/valtech/aecu/core/model/history/HistoryOverview.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.model.history; diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index ac393296..886505a6 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.service; @@ -115,8 +112,7 @@ private List<String> findCandidates(ResourceResolver resolver, String path) thro */ private boolean isFolder(Resource resource) { String type = resource.getValueMap().get(JcrConstants.JCR_PRIMARYTYPE, String.class); - return JcrResourceConstants.NT_SLING_FOLDER.equals(type) - || JcrResourceConstants.NT_SLING_ORDERED_FOLDER.equals(type) + return JcrResourceConstants.NT_SLING_FOLDER.equals(type) || JcrResourceConstants.NT_SLING_ORDERED_FOLDER.equals(type) || JcrConstants.NT_FOLDER.equals(type); } @@ -191,7 +187,8 @@ private ExecutionResult executeScript(ResourceResolver resolver, String path) { if (!success && (getFallbackScript(resolver, path) != null)) { fallbackResult = executeScript(resolver, getFallbackScript(resolver, path)); } - return new ExecutionResult(success, response.getRunningTime(), result, response.getOutput() + response.getExceptionStackTrace(), fallbackResult, path); + return new ExecutionResult(success, response.getRunningTime(), result, + response.getOutput() + response.getExceptionStackTrace(), fallbackResult, path); } /** diff --git a/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java index 7e67218a..097634a2 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java +++ b/core/src/main/java/de/valtech/aecu/core/service/GroovyConsoleRequest.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.service; @@ -319,16 +316,13 @@ public boolean isSecure() { } @Override - public void removeAttribute(String arg0) { - } + public void removeAttribute(String arg0) {} @Override - public void setAttribute(String arg0, Object arg1) { - } + public void setAttribute(String arg0, Object arg1) {} @Override - public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException { - } + public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException {} @Override public <AdapterType> AdapterType adaptTo(Class<AdapterType> arg0) { diff --git a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java index 3865f9d1..815b078f 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/HistoryEntryImpl.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.service; diff --git a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java index 8e7c54d5..f84c28ce 100644 --- a/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java +++ b/core/src/main/java/de/valtech/aecu/core/serviceuser/ServiceResourceResolverService.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.serviceuser; diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java index fe3b6d67..4be2c234 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/BaseServlet.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.servlets; diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java index 32a87393..3cee1359 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.servlets; @@ -47,26 +44,23 @@ * @author Bryan Chavez */ -@Component(immediate = true, - service = {Servlet.class}, - property = { - "sling.servlet.paths=/bin/public/valtech/aecu/execute", - "sling.servlet.extensions=json", - "sling.servlet.methods=GET" - }) +@Component(immediate = true, service = {Servlet.class}, property = {"sling.servlet.paths=/bin/public/valtech/aecu/execute", + "sling.servlet.extensions=json", "sling.servlet.methods=GET"}) public class ExecutionServlet extends BaseServlet { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(ExecutionServlet.class); - protected static final String ERROR_MESSAGE_MANDATORY = "ExecutionServlet :: Make sure your are sending the correct parameters."; + protected static final String ERROR_MESSAGE_MANDATORY = + "ExecutionServlet :: Make sure your are sending the correct parameters."; @Reference AecuService aecuService; @Override - protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { + protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) + throws ServletException, IOException { this.setNoCache(response); @@ -90,15 +84,15 @@ protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse r } - protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHttpServletResponse response, String historyEntryAction) - throws AecuException, IOException { + protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHttpServletResponse response, + String historyEntryAction) throws AecuException, IOException { HistoryEntry historyEntry; switch (historyEntryAction.toLowerCase()) { case "use": case "close": - //Used for "use" and "close" + // Used for "use" and "close" String historyEntryPath = request.getParameter("historyEntryPath"); if (!this.validateParameter(historyEntryPath)) { writeResult(response, ERROR_MESSAGE_MANDATORY); @@ -110,7 +104,7 @@ protected HistoryEntry getHistoryEntry(SlingHttpServletRequest request, SlingHtt historyEntry = historyUtil.readHistoryEntry(resolver.getResource(historyEntryPath)); break; default: - //Used for "single" and "create" + // Used for "single" and "create" historyEntry = aecuService.createHistoryEntry(); break; } @@ -123,7 +117,7 @@ protected HistoryEntry finishHistoryEntry(HistoryEntry historyEntry, String hist switch (historyEntryAction.toLowerCase()) { case "single": case "close": - //Used for "single" and "close" + // Used for "single" and "close" aecuService.finishHistoryEntry(historyEntry); break; } @@ -133,8 +127,8 @@ protected HistoryEntry finishHistoryEntry(HistoryEntry historyEntry, String hist } /** - * This method builds the JSON String for the response. - * Eg: {"success": true,"historyEntryPath":"/var/aecu/2018/6/13/152892696338961314"} + * This method builds the JSON String for the response. Eg: {"success": + * true,"historyEntryPath":"/var/aecu/2018/6/13/152892696338961314"} * * @return json String */ @@ -145,4 +139,4 @@ protected String prepareJson(boolean status, String historyEntryPath) { return json.toString(); } -} \ No newline at end of file +} diff --git a/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java index d8d8c099..a32d1e25 100644 --- a/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java +++ b/core/src/test/java/de/valtech/aecu/core/history/HistoryUtilTest.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.history; diff --git a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java index ef812963..be233116 100644 --- a/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java +++ b/core/src/test/java/de/valtech/aecu/core/service/AecuServiceImplTest.java @@ -1,23 +1,20 @@ /* - * Copyright 2018 Valtech GmbH + * Copyright 2018 Valtech GmbH * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package de.valtech.aecu.core.service; From 7d85e8468fc23daa7f563605773b177f1c8c1b3e Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 13 Jul 2018 16:19:33 +0200 Subject: [PATCH 106/122] formatter --- docs/formatter/intellij-aecu.xml | 476 +++++++++++++++++++++++++++++++ 1 file changed, 476 insertions(+) create mode 100644 docs/formatter/intellij-aecu.xml diff --git a/docs/formatter/intellij-aecu.xml b/docs/formatter/intellij-aecu.xml new file mode 100644 index 00000000..49df1d87 --- /dev/null +++ b/docs/formatter/intellij-aecu.xml @@ -0,0 +1,476 @@ +<?xml version="1.0" encoding="UTF-8"?> +<code_scheme name="Code Style"> + <option name="JAVA_INDENT_OPTIONS"> + <value> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="8" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </value> + </option> + <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> + <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" /> + <option name="IMPORT_LAYOUT_TABLE"> + <value> + <package name="com.google" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="android" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="antenna" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="antlr" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="ar" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="asposewobfuscated" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="asquare" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="atg" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="au" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="beaver" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="bibtex" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="bmsi" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="bsh" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="ccl" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="cern" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="ChartDirector" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="checkers" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="com" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="COM" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="common" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="contribs" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="corejava" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="cryptix" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="cybervillains" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="dalvik" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="danbikel" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="de" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="EDU" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="eg" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="eu" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="examples" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="fat" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="fit" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="fitlibrary" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="fmpp" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="freemarker" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="gnu" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="groovy" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="groovyjarjarantlr" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="groovyjarjarasm" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="hak" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="hep" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="ie" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="imageinfo" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="info" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="it" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jal" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="Jama" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="japa" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="japacheckers" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jas" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jasmin" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="javancss" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="javanet" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="javassist" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="javazoom" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="java_cup" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jcifs" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jetty" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="JFlex" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jj2000" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jline" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jp" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="JSci" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jsr166y" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="junit" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jxl" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="jxxload_help" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="kawa" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="kea" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="libcore" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="libsvm" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="lti" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="memetic" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="mt" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="mx4j" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="net" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="netscape" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="nl" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="nu" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="oauth" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="ognl" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="opennlp" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="oracle" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="org" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="penn2dg" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="pennconverter" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="pl" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="prefuse" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="proguard" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="repackage" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="scm" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="se" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="serp" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="simple" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="soot" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="sqlj" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="src" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="ssa" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="sun" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="sunlabs" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="tcl" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="testdata" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="testshell" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="testsuite" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="twitter4j" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="uk" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="ViolinStrings" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="weka" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="wet" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="winstone" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="woolfel" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="wowza" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="java" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="javax" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="" withSubpackages="true" static="false" /> + <emptyLine /> + <package name="" withSubpackages="true" static="true" /> + </value> + </option> + <option name="RIGHT_MARGIN" value="130" /> + <option name="JD_P_AT_EMPTY_LINES" value="false" /> + <option name="JD_KEEP_EMPTY_PARAMETER" value="false" /> + <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" /> + <option name="JD_KEEP_EMPTY_RETURN" value="false" /> + <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> + <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> + <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" /> + <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" /> + <option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" /> + <option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" /> + <option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" /> + <option name="ALIGN_MULTILINE_THROWS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" /> + <option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" /> + <option name="CALL_PARAMETERS_WRAP" value="1" /> + <option name="METHOD_PARAMETERS_WRAP" value="1" /> + <option name="EXTENDS_LIST_WRAP" value="1" /> + <option name="THROWS_LIST_WRAP" value="1" /> + <option name="EXTENDS_KEYWORD_WRAP" value="1" /> + <option name="THROWS_KEYWORD_WRAP" value="1" /> + <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> + <option name="BINARY_OPERATION_WRAP" value="1" /> + <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> + <option name="TERNARY_OPERATION_WRAP" value="1" /> + <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> + <option name="FOR_STATEMENT_WRAP" value="1" /> + <option name="ARRAY_INITIALIZER_WRAP" value="1" /> + <option name="ASSIGNMENT_WRAP" value="5" /> + <option name="WRAP_COMMENTS" value="true" /> + <option name="IF_BRACE_FORCE" value="3" /> + <option name="DOWHILE_BRACE_FORCE" value="3" /> + <option name="WHILE_BRACE_FORCE" value="3" /> + <option name="FOR_BRACE_FORCE" value="3" /> + <ADDITIONAL_INDENT_OPTIONS fileType="css"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="haml"> + <option name="INDENT_SIZE" value="2" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="java"> + <option name="INDENT_SIZE" value="2" /> + <option name="CONTINUATION_INDENT_SIZE" value="4" /> + <option name="TAB_SIZE" value="8" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="js"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="4" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="jsp"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="php"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="sass"> + <option name="INDENT_SIZE" value="2" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="xml"> + <option name="INDENT_SIZE" value="4" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <ADDITIONAL_INDENT_OPTIONS fileType="yml"> + <option name="INDENT_SIZE" value="2" /> + <option name="CONTINUATION_INDENT_SIZE" value="8" /> + <option name="TAB_SIZE" value="4" /> + <option name="USE_TAB_CHARACTER" value="false" /> + <option name="SMART_TABS" value="false" /> + <option name="LABEL_INDENT_SIZE" value="0" /> + <option name="LABEL_INDENT_ABSOLUTE" value="false" /> + <option name="USE_RELATIVE_INDENTS" value="false" /> + </ADDITIONAL_INDENT_OPTIONS> + <codeStyleSettings language="ECMA Script Level 4"> + <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> + <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> + <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" /> + <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" /> + <option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" /> + <option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" /> + <option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" /> + <option name="ALIGN_MULTILINE_THROWS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" /> + <option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" /> + <option name="CALL_PARAMETERS_WRAP" value="1" /> + <option name="METHOD_PARAMETERS_WRAP" value="1" /> + <option name="EXTENDS_LIST_WRAP" value="1" /> + <option name="THROWS_LIST_WRAP" value="1" /> + <option name="EXTENDS_KEYWORD_WRAP" value="1" /> + <option name="THROWS_KEYWORD_WRAP" value="1" /> + <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> + <option name="BINARY_OPERATION_WRAP" value="1" /> + <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> + <option name="TERNARY_OPERATION_WRAP" value="1" /> + <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> + <option name="FOR_STATEMENT_WRAP" value="1" /> + <option name="ARRAY_INITIALIZER_WRAP" value="1" /> + <option name="ASSIGNMENT_WRAP" value="5" /> + <option name="WRAP_COMMENTS" value="true" /> + <option name="IF_BRACE_FORCE" value="3" /> + <option name="DOWHILE_BRACE_FORCE" value="3" /> + <option name="WHILE_BRACE_FORCE" value="3" /> + <option name="FOR_BRACE_FORCE" value="3" /> + <option name="PARENT_SETTINGS_INSTALLED" value="true" /> + </codeStyleSettings> + <codeStyleSettings language="JavaScript"> + <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> + <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> + <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" /> + <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" /> + <option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" /> + <option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" /> + <option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" /> + <option name="ALIGN_MULTILINE_THROWS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" /> + <option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" /> + <option name="CALL_PARAMETERS_WRAP" value="1" /> + <option name="METHOD_PARAMETERS_WRAP" value="1" /> + <option name="EXTENDS_LIST_WRAP" value="1" /> + <option name="THROWS_LIST_WRAP" value="1" /> + <option name="EXTENDS_KEYWORD_WRAP" value="1" /> + <option name="THROWS_KEYWORD_WRAP" value="1" /> + <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> + <option name="BINARY_OPERATION_WRAP" value="1" /> + <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> + <option name="TERNARY_OPERATION_WRAP" value="1" /> + <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> + <option name="FOR_STATEMENT_WRAP" value="1" /> + <option name="ARRAY_INITIALIZER_WRAP" value="1" /> + <option name="ASSIGNMENT_WRAP" value="5" /> + <option name="WRAP_COMMENTS" value="true" /> + <option name="IF_BRACE_FORCE" value="3" /> + <option name="DOWHILE_BRACE_FORCE" value="3" /> + <option name="WHILE_BRACE_FORCE" value="3" /> + <option name="FOR_BRACE_FORCE" value="3" /> + <option name="PARENT_SETTINGS_INSTALLED" value="true" /> + </codeStyleSettings> + <codeStyleSettings language="PHP"> + <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" /> + <option name="KEEP_BLANK_LINES_IN_CODE" value="1" /> + <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" /> + <option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" /> + <option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" /> + <option name="ALIGN_MULTILINE_THROWS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" /> + <option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" /> + <option name="CALL_PARAMETERS_WRAP" value="1" /> + <option name="METHOD_PARAMETERS_WRAP" value="1" /> + <option name="EXTENDS_LIST_WRAP" value="1" /> + <option name="THROWS_LIST_WRAP" value="1" /> + <option name="EXTENDS_KEYWORD_WRAP" value="1" /> + <option name="THROWS_KEYWORD_WRAP" value="1" /> + <option name="METHOD_CALL_CHAIN_WRAP" value="1" /> + <option name="BINARY_OPERATION_WRAP" value="1" /> + <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" /> + <option name="TERNARY_OPERATION_WRAP" value="1" /> + <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" /> + <option name="FOR_STATEMENT_WRAP" value="1" /> + <option name="ARRAY_INITIALIZER_WRAP" value="1" /> + <option name="ASSIGNMENT_WRAP" value="5" /> + <option name="WRAP_COMMENTS" value="true" /> + <option name="IF_BRACE_FORCE" value="3" /> + <option name="DOWHILE_BRACE_FORCE" value="3" /> + <option name="WHILE_BRACE_FORCE" value="3" /> + <option name="FOR_BRACE_FORCE" value="3" /> + <option name="PARENT_SETTINGS_INSTALLED" value="true" /> + </codeStyleSettings> +</code_scheme> + From b9fb69f7278d652a33d2354cd3cd3f40d354510d Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Fri, 13 Jul 2018 16:27:54 +0200 Subject: [PATCH 107/122] developer docs --- Readme.md | 4 ++++ docs/developers.md | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 docs/developers.md diff --git a/Readme.md b/Readme.md index 7e5715b9..98ea8426 100644 --- a/Readme.md +++ b/Readme.md @@ -160,3 +160,7 @@ For the status of older runs use AECU's history page. # License The AC Tool is licensed under the [MIT LICENSE](LICENSE). + +# Developers + +See our [developer zone](docs/developers.md) \ No newline at end of file diff --git a/docs/developers.md b/docs/developers.md new file mode 100644 index 00000000..6f062005 --- /dev/null +++ b/docs/developers.md @@ -0,0 +1,19 @@ +# Build and Deploy + +To build and deploy run this in the base folder: + +```bash +mvn clean install -PautoInstallPackage +``` + +You can deploy the core project using this command in core folder: + +```bash +mvn clean install -PautoInstallBundle +``` + + +# Code Formatting + +Please use our standard code formatters for [Eclipse](formatter/eclipse-aecu.xml) +and [IntelliJ](formatter/intellij-aecu.xml). From 54a4911de08cef6f422963bbe2ac6347aa3750fe Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 10:27:56 +0200 Subject: [PATCH 108/122] devel docs --- docs/developers.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/developers.md b/docs/developers.md index 6f062005..15247c1f 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -1,12 +1,20 @@ +# AEM Server Setup + +By default AEM is expected to listen on localhost on port 5702. This setting can be overridden by adding parameters: +* -Daem.port=4502 +* -Daem.host=localhost + +You need AEM 6.3 with service pack 2. + # Build and Deploy -To build and deploy run this in the base folder: +To build and deploy run this in the base (aem-easy-content-upgrade) or ui.apps/examples folder: ```bash mvn clean install -PautoInstallPackage ``` -You can deploy the core project using this command in core folder: +In case you want to deploy core only you can use this command in core folder: ```bash mvn clean install -PautoInstallBundle From 620fd7abd14f4c0563488a4183e400a12fedfd7a Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 11:02:38 +0200 Subject: [PATCH 109/122] binding documentation --- Readme.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 98ea8426..0b736976 100644 --- a/Readme.md +++ b/Readme.md @@ -112,10 +112,74 @@ You can click on any run to see the full details. This will show the status for # Extension to Groovy Console -TODO +AECU adds its own binding to Groovy Console. You can reach it using "aecu" in your script. This provides methods to perform common tasks like property modification or node deletion. + +It follows a collect, filter, execute process. + +## Collect Options +In the collect phase you define which nodes should be checked for a migration. + +* forResources(String[] paths): use the given paths without any subnodes +* forChildResourcesOf(String path): use all direct childs of the given path (but no grandchilds) +* forDescendantResourcesOf(String path): use the whole subtree under this path + +You can call these methods multiple times and combine them. They will be merged together. + +Example: + +```java +println aecu.contentUpgradeBuilder() + .forResources((String[])["/content/we-retail/ca/en"]) + .forChildResourcesOf("/content/we-retail/us/en") + .forDescendantResourcesOf("/content/we-retail/us/en/experience") + .doSetProperty("name", "value") + .run() +``` + +## Filter options +These methods can be used to filter the nodes that were collected above. Multiple filters can be applied for one run. + +### Filter by Properties +Use this to filter by a list of property values (e.g. sling:resourceType). + +```java +filterByProperties(Map<String, String> properties) +``` + +Example: + +```java +def conditionMap = [:] +conditionMap["sling:resourceType"] = "weretail/components/structure/page" + +println aecu.contentUpgradeBuilder() + .forChildResourcesOf("/content/we-retail/ca/en") + .filterByProperties(conditionMap) + .doSetProperty("name", "value") + .run() +``` + +<a name="jmx"></a> + +### Filter by Node Name + +You can also filter nodes by their name. + +* filterByNodeName(String name): process only nodes which have this exact name +* filterByNodeNameRegex(String regex): process nodes that have a name that matches the given regular expression + +```java +println aecu.contentUpgradeBuilder() + .forChildResourcesOf("/content/we-retail/ca/en") + .filterByNodeName("jcr:content") + .filterByNodeNameRegex("jcr.*") + .doSetProperty("name", "value") + .run() +``` <a name="jmx"></a> + # JMX Interface <img src="docs/images/jmx.png"> From 2c26efe8e991ee926d27e41a9f4852198954a5f9 Mon Sep 17 00:00:00 2001 From: Christopher Piosecny <christopher.piosecny@valtech.de> Date: Mon, 16 Jul 2018 11:44:04 +0200 Subject: [PATCH 110/122] Adapt InstallHook, only process groovy scripts matching runmode that have never been executed or have been modified. --- .../de/valtech/aecu/service/AecuService.java | 16 ++ .../core/installhook/AecuInstallHook.java | 141 ++++++++++++------ .../core/installhook/AecuTrackerListener.java | 49 +++--- .../installhook/HookExecutionHistory.java | 91 +++++++++++ .../core/installhook/OsgiServiceProvider.java | 88 +++++++++++ .../aecu/core/service/AecuServiceImpl.java | 18 +-- 6 files changed, 317 insertions(+), 86 deletions(-) create mode 100644 core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java create mode 100644 core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java diff --git a/api/src/main/java/de/valtech/aecu/service/AecuService.java b/api/src/main/java/de/valtech/aecu/service/AecuService.java index b7e9c155..c39151a7 100644 --- a/api/src/main/java/de/valtech/aecu/service/AecuService.java +++ b/api/src/main/java/de/valtech/aecu/service/AecuService.java @@ -59,6 +59,22 @@ public interface AecuService { */ List<String> getFiles(String path) throws AecuException; + /** + * Checks if the folder matches the system's run modes if specified in folder name. + * + * @param name resource name + * @return matches run modes + */ + boolean matchesRunmodes(String name); + + /** + * Checks if the name is a valid script. + * + * @param name file name + * @return is valid + */ + boolean isValidScriptName(String name); + /** * Executes the script at the given position. * diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java index b30e7da2..1bc7a71d 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -23,93 +23,136 @@ import de.valtech.aecu.service.ExecutionResult; import de.valtech.aecu.service.HistoryEntry; +import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener; +import org.apache.jackrabbit.vault.fs.io.Archive; import org.apache.jackrabbit.vault.packaging.InstallContext; import org.apache.jackrabbit.vault.packaging.InstallHook; import org.apache.jackrabbit.vault.packaging.PackageException; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + /** - * InstallHook handling installation of groovy scripts. + * InstallHook handling installation of groovy scripts. The InstallHook gathers groovy scripts contained in the installed vault + * package and executes them depending on active runmodes and if the script has been added, modified or never executed. <br> + * Example usage in content-package-maven-plugin: + * <pre> + * {@code + * <plugin> + * <groupId>com.day.jcr.vault</groupId> + * <artifactId>content-package-maven-plugin</artifactId> + * <extensions>true</extensions> + * <configuration> + * <filterSource>src/main/content/META-INF/vault/filter.xml</filterSource> + * <verbose>true</verbose> + * <failOnError>true</failOnError> + * <group>Valtech</group> + * <properties> + * <installhook.aecu.class>de.valtech.aecu.core.installhook.AecuInstallHook</installhook.aecu.class> + * </properties> + * </configuration> + * </plugin> + * } + * </pre> */ public class AecuInstallHook implements InstallHook { private static final Logger LOG = LoggerFactory.getLogger(AecuInstallHook.class); - private final BundleContext bundleContext; + private final OsgiServiceProvider osgiServiceProvider; private AecuTrackerListener listener; public AecuInstallHook() { - Bundle currentBundle = FrameworkUtil.getBundle(this.getClass()); - if (currentBundle == null) { - throw new IllegalStateException("The class " + this.getClass() + " was not loaded through a bundle classloader"); - } - bundleContext = currentBundle.getBundleContext(); - if (bundleContext == null) { - throw new IllegalStateException("Could not get bundle context for bundle " + currentBundle); - } - - } - - private ServiceReference<AecuService> getAecuServiceReference() { - ServiceReference<AecuService> aecuServiceReference = bundleContext.getServiceReference(AecuService.class); - if (aecuServiceReference == null) { - throw new IllegalStateException("Could not retrieve service reference for AECUService."); - } - return aecuServiceReference; + LOG.info("Instantiating install hook"); + this.osgiServiceProvider = new OsgiServiceProvider(this.getClass()); } @Override public void execute(InstallContext installContext) throws PackageException { LOG.info("Executing in phase {}", installContext.getPhase()); - ServiceReference<AecuService> aecuServiceReference = getAecuServiceReference(); - AecuService aecuService = bundleContext.getService(aecuServiceReference); - if (aecuService == null) { - throw new IllegalStateException("Could not get the AECU service, verify that the bundle was installed correctly!"); - } + ServiceReference<AecuService> aecuServiceReference = osgiServiceProvider.getServiceReference(AecuService.class); + AecuService aecuService = osgiServiceProvider.getService(aecuServiceReference); + try { switch (installContext.getPhase()) { case PREPARE: ProgressTrackerListener originalListener = installContext.getOptions().getListener(); - listener = new AecuTrackerListener(originalListener, aecuService, "A", "M", "-"); + listener = new AecuTrackerListener(originalListener, aecuService); installContext.getOptions().setListener(listener); break; case INSTALLED: - boolean isDryRun = installContext.getOptions().isDryRun(); - if (isDryRun) { - LOG.debug("Skipping any modifications, dry run mode selected"); - } else { - HistoryEntry installationHistory = aecuService.createHistoryEntry(); - for (String groovyScriptPath : listener.getGroovyScriptPaths()) { - LOG.info("Executing script {}", groovyScriptPath); - ExecutionResult result = aecuService.execute(groovyScriptPath); - installationHistory = aecuService.storeExecutionInHistory(installationHistory, result); - LOG.info("Executed script {}: {}", groovyScriptPath, result.getOutput()); - } - aecuService.finishHistoryEntry(installationHistory); - // TODO: from my point of view the installation should not be failed in case - // a fallback script was executed successfully - if (!installationHistory.getResult().equals(HistoryEntry.RESULT.SUCCESS)) { - throw new PackageException("Failed installation, check installation history at " - + installationHistory.getRepositoryPath()); - } + HistoryEntry installationHistory = executeScripts(aecuService, installContext); + // TODO: decide if we throw an exception or not. + // For example, when a fallback script can be executed but the original script failed the history would + // be marked as failed. + if (!installationHistory.getSingleResults().isEmpty() && + !HistoryEntry.RESULT.SUCCESS.equals(installationHistory.getResult())) { + throw new PackageException( + "Failed installation, check installation history at " + installationHistory.getRepositoryPath()); } break; default: break; } - } catch (AecuException e) { + } catch (IOException | AecuException e) { throw new PackageException(e); } finally { - if (aecuServiceReference != null) { - bundleContext.ungetService(aecuServiceReference); + osgiServiceProvider.ungetService(aecuServiceReference); + } + } + + private HistoryEntry executeScripts(AecuService aecuService, InstallContext installContext) + throws AecuException, IOException { + HistoryEntry installationHistory = aecuService.createHistoryEntry(); + Archive archive = installContext.getPackage().getArchive(); + List<String> allValidScriptCandidatesInArchive = findCandidates("", archive.getJcrRoot(), aecuService); + List<String> modifiedOrAddedScriptPaths = listener.getModifiedOrAddedPaths(); + for (String groovyScriptPath : allValidScriptCandidatesInArchive) { + HookExecutionHistory hookExecutionHistory = new HookExecutionHistory(installContext.getSession(), groovyScriptPath); + if (modifiedOrAddedScriptPaths.contains(groovyScriptPath) || !hookExecutionHistory.hasBeenExecutedBefore()) { + try { + installationHistory = executeScript(aecuService, installationHistory, groovyScriptPath); + hookExecutionHistory.setExecuted(); + } catch (AecuException e) { + LOG.warn("Error executing script " + groovyScriptPath, e); + } + } + } + installationHistory = aecuService.finishHistoryEntry(installationHistory); + return installationHistory; + } + + private HistoryEntry executeScript(AecuService aecuService, HistoryEntry installationHistory, String groovyScriptPath) + throws AecuException { + LOG.info("Executing script {}", groovyScriptPath); + ExecutionResult result = aecuService.execute(groovyScriptPath); + installationHistory = aecuService.storeExecutionInHistory(installationHistory, result); + LOG.info("Executed script {}: {}", groovyScriptPath, result.getOutput()); + return installationHistory; + } + + // mildly duplicated + private List<String> findCandidates(String parent, Archive.Entry entry, AecuService aecuService) { + List<String> candidates = new ArrayList<>(); + if (entry == null) { + return candidates; + } + String entryName = entry.getName(); + String entryPath = parent + "/" + entryName; + + if (entry.isDirectory() && aecuService.matchesRunmodes(entryName)) { + for (Archive.Entry childEntry : entry.getChildren()) { + candidates.addAll(findCandidates(entryPath, childEntry, aecuService)); } + } else if (aecuService.isValidScriptName(entryName)) { + candidates.add(StringUtils.substringAfter(entryPath, "/jcr_root")); } + return candidates; } } diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java index f1be7a95..9453a2d9 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java @@ -18,10 +18,8 @@ */ package de.valtech.aecu.core.installhook; -import de.valtech.aecu.service.AecuException; import de.valtech.aecu.service.AecuService; -import org.apache.jackrabbit.util.Text; import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,52 +27,57 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Set; +import javax.annotation.Nonnull; + /** - * Collects groovy script paths to execute. + * Collects groovy script paths to potentially execute based on the given actions. */ public class AecuTrackerListener implements ProgressTrackerListener { private static final Logger LOG = LoggerFactory.getLogger(AecuTrackerListener.class); - private static final String SCRIPT_PARENT_PATH = "/etc/groovyconsole/scripts/aecu/"; + private static final Set<String> ACTIONS = new HashSet<>(Arrays.asList("A", "M")); private final ProgressTrackerListener originalListener; private final AecuService aecuService; - private final Set<String> actions; - private final Set<String> paths; + private final List<String> paths; - public AecuTrackerListener(ProgressTrackerListener originalListener, AecuService aecuService, String... actions) { + /** + * Constructor. + * @param originalListener the original ProgressTrackerListener. + * @param aecuService an AecuService instance. + */ + public AecuTrackerListener(ProgressTrackerListener originalListener, AecuService aecuService) { this.originalListener = originalListener; this.aecuService = aecuService; - this.actions = new HashSet<>(Arrays.asList(actions)); - this.paths = new HashSet<>(); + this.paths = new LinkedList<>(); } - public Set<String> getGroovyScriptPaths() { - return Collections.unmodifiableSet(paths); + /** + * Returns an unmodifiable list of the modified or added paths encountered during the installation phase. + * @return a list of modified or added paths, can be empty. + */ + @Nonnull + public List<String> getModifiedOrAddedPaths() { + return Collections.unmodifiableList(paths); } @Override public void onMessage(Mode mode, String action, String path) { originalListener.onMessage(mode, action, path); - if (!actions.contains(action)) { + if (!ACTIONS.contains(action)) { LOG.debug("Skipping {} due to non matching action {}", path, action); return; } - // TODO: not the best idea to couple the detection of project roots to the structure - if (path.startsWith(SCRIPT_PARENT_PATH)) { - String pathToUse = Text.getAbsoluteParent(path, 4); - // grouping items by first sub folder below SCRIPT_PARENT_PATH - LOG.info("Found matching path {}, using parent {}", path, pathToUse); - try { - paths.addAll(aecuService.getFiles(pathToUse)); - } catch (AecuException e) { - // TODO re-throw? - LOG.error(e.getMessage(), e); - } + + if (aecuService.isValidScriptName(path)) { + LOG.debug("Found valid script path {}", path); + paths.add(path); } } diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java b/core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java new file mode 100644 index 00000000..08d54023 --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package de.valtech.aecu.core.installhook; + +import de.valtech.aecu.service.AecuException; + +import org.apache.jackrabbit.JcrConstants; +import org.apache.jackrabbit.commons.JcrUtils; +import org.apache.jackrabbit.value.DateValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +/** + * Execution history for groovy scripts executed during {@link AecuInstallHook} invocation. + */ +public class HookExecutionHistory { + + private static final Logger LOG = LoggerFactory.getLogger(HookExecutionHistory.class); + + private static final String HISTORY_BASE_PATH = "/var/aecu-installhook"; + + private static final String PN_EXECUTED = "executed"; + + private final Node hookHistory; + + /** + * Constructor. + * @param session a session with write permissons on {@value HISTORY_BASE_PATH}. + * @param groovyScriptPath the groovy script to instantiate the execution history for. + * @throws AecuException in case the call to JcrUtils.getOrCreateByPath fails. + */ + public HookExecutionHistory(Session session, String groovyScriptPath) throws AecuException { + try { + hookHistory = JcrUtils.getOrCreateByPath(HISTORY_BASE_PATH + groovyScriptPath, false, JcrConstants.NT_UNSTRUCTURED, + JcrConstants.NT_UNSTRUCTURED, session, true); + } catch (RepositoryException e) { + throw new AecuException("Error getting or creating node at " + HISTORY_BASE_PATH + groovyScriptPath, e); + } + } + + /** + * Returns if the script has been executed before. This is determined by checking existence of the property + * {@value PN_EXECUTED} on the history node. + * @return true if it has been executed previously, false otherwise. + */ + public boolean hasBeenExecutedBefore() { + boolean hasBeenExecuted = false; + try { + hasBeenExecuted = hookHistory.hasProperty(PN_EXECUTED); + } catch (RepositoryException e) { + LOG.error(e.getMessage(), e); + } + return hasBeenExecuted; + } + + /** + * Sets {@value PN_EXECUTED} on the history node to the current date. + * @throws AecuException in case the property could not be saved. + */ + public void setExecuted() throws AecuException { + try { + hookHistory.setProperty(PN_EXECUTED, new DateValue(Calendar.getInstance())); + hookHistory.getSession().save(); + } catch (RepositoryException e) { + throw new AecuException("Could not set property " + PN_EXECUTED, e); + } + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java b/core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java new file mode 100644 index 00000000..a95dde3b --- /dev/null +++ b/core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java @@ -0,0 +1,88 @@ +/* + * Copyright 2018 Valtech GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package de.valtech.aecu.core.installhook; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; + +import javax.annotation.Nonnull; + +/** + * Service Provider for InstallHook. + */ +public class OsgiServiceProvider { + + private final BundleContext bundleContext; + + /** + * Constructor. + * @param clazz the class that was loaded over a bundle classloader. + */ + public OsgiServiceProvider(@Nonnull Class clazz) { + Bundle currentBundle = FrameworkUtil.getBundle(clazz); + if (currentBundle == null) { + throw new IllegalStateException("The class " + clazz + " was not loaded through a bundle classloader"); + } + bundleContext = currentBundle.getBundleContext(); + if (bundleContext == null) { + throw new IllegalStateException("Could not get bundle context for bundle " + currentBundle); + } + } + + /** + * Retrieves a {@link ServiceReference} for the given class. + * @see org.osgi.framework.BundleContext#getServiceReference(Class) + * @param clazz the class to retrieve a {@link ServiceReference} for. + * @param <T> the type of the service. + * @return a {@link ServiceReference} for the requested service. + */ + @Nonnull <T> ServiceReference<T> getServiceReference(@Nonnull Class<T> clazz) { + ServiceReference<T> serviceReference = bundleContext.getServiceReference(clazz); + if (serviceReference == null) { + throw new IllegalStateException("Could not retrieve service reference for class " + clazz); + } + return serviceReference; + } + + /** + * Retrieves the service object the {@link ServiceReference} is pointing to. + * @see org.osgi.framework.BundleContext#getService(ServiceReference) + * @param serviceReference the {@link ServiceReference}. + * @param <T> the service type. + * @return the service instance. + */ + @Nonnull <T> T getService(@Nonnull ServiceReference<T> serviceReference) { + T service = bundleContext.getService(serviceReference); + if (service == null) { + throw new IllegalStateException("Could not get the service for reference " + serviceReference + + ", verify that the bundle was installed correctly!"); + } + return service; + } + + /** + * @see org.osgi.framework.BundleContext#ungetService(ServiceReference) + */ + boolean ungetService(@Nonnull ServiceReference<?> serviceReference) { + return bundleContext.ungetService(serviceReference); + } + +} diff --git a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java index 886505a6..0d2af5b2 100644 --- a/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/service/AecuServiceImpl.java @@ -116,13 +116,8 @@ private boolean isFolder(Resource resource) { || JcrConstants.NT_FOLDER.equals(type); } - /** - * Checks if the folder matches the system's run modes if specified in folder name. - * - * @param name resource name - * @return matches run modes - */ - protected boolean matchesRunmodes(String name) { + @Override + public boolean matchesRunmodes(String name) { if (!name.contains(".")) { return true; } @@ -138,13 +133,8 @@ protected boolean matchesRunmodes(String name) { return false; } - /** - * Checks if the name is a valid script. - * - * @param name file name - * @return is valid - */ - protected boolean isValidScriptName(String name) { + @Override + public boolean isValidScriptName(String name) { if (!name.endsWith(".groovy")) { return false; } From fb362487555fb5c382c06cb9a8ccd89638f293ca Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 11:53:59 +0200 Subject: [PATCH 111/122] binding documentation --- Readme.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Readme.md b/Readme.md index 0b736976..43eea1fc 100644 --- a/Readme.md +++ b/Readme.md @@ -179,6 +179,51 @@ println aecu.contentUpgradeBuilder() <a name="jmx"></a> +### Combine Multiple Filters +You can combine filters with AND and OR to build more complex filters. + +```java +def conditionMap_type = [:] +conditionMap_type['sling:resourceType'] = "weretail/components/content/heroimage" +def conditionMap_file = [:] +conditionMap_file['fileReference'] = "/content/dam/we-retail/en/activities/running/fitness-woman.jpg" +def conditionMap_page = [:] +conditionMap_page['jcr:primaryType'] = "cq:PageContent" + +def complexFilter = new ORFilter( + [ new FilterByProperties(conditionMap_page), + new ANDFilter( [ + new FilterByProperties(conditionMap_type), + new FilterByProperties(conditionMap_file) + ] ) + ]) + +println aecu.contentUpgradeBuilder() + .forDescendantResourcesOf("/content/we-retail/ca/en") + .filterWith(complexFilter) + .doSetProperty("name", "value") + .run() +``` + +## Execute Options + +### Update Single Value Properies + +* doSetProperty(String name, Object value): sets the given property to the value. Any existing value is overwritten. +* doDeleteProperty(String name): removes the property with the given name if existing. +* doRenameProperty(String oldName, String newName): renames the given property if existing. If the new property name already exists it will be overwritten. + +```java +println aecu.contentUpgradeBuilder() + .forChildResourcesOf("/content/we-retail/ca/en") + .filterByNodeName("jcr:content") + .doSetProperty("name", "value") + .doDeleteProperty("nameToDelete") + .doRenameProperty("oldName", "newName") + .run() +``` + +TODO # JMX Interface From 9f5f79d9a0885ece5965d17065ffc734a30cf5b3 Mon Sep 17 00:00:00 2001 From: Christopher Piosecny <christopher.piosecny@valtech.de> Date: Mon, 16 Jul 2018 13:24:01 +0200 Subject: [PATCH 112/122] Add information to be shown in install log, ensure that 'always' scripts are selected for execution --- .../core/installhook/AecuInstallHook.java | 70 ++++++++++++------- .../core/installhook/AecuTrackerListener.java | 36 +++++++++- 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java index 1bc7a71d..689559b0 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -68,12 +68,10 @@ public class AecuInstallHook implements InstallHook { private AecuTrackerListener listener; public AecuInstallHook() { - LOG.info("Instantiating install hook"); this.osgiServiceProvider = new OsgiServiceProvider(this.getClass()); } - @Override - public void execute(InstallContext installContext) throws PackageException { + @Override public void execute(InstallContext installContext) throws PackageException { LOG.info("Executing in phase {}", installContext.getPhase()); ServiceReference<AecuService> aecuServiceReference = osgiServiceProvider.getServiceReference(AecuService.class); AecuService aecuService = osgiServiceProvider.getService(aecuServiceReference); @@ -86,14 +84,18 @@ public void execute(InstallContext installContext) throws PackageException { installContext.getOptions().setListener(listener); break; case INSTALLED: - HistoryEntry installationHistory = executeScripts(aecuService, installContext); - // TODO: decide if we throw an exception or not. - // For example, when a fallback script can be executed but the original script failed the history would - // be marked as failed. - if (!installationHistory.getSingleResults().isEmpty() && - !HistoryEntry.RESULT.SUCCESS.equals(installationHistory.getResult())) { - throw new PackageException( - "Failed installation, check installation history at " + installationHistory.getRepositoryPath()); + + Archive archive = installContext.getPackage().getArchive(); + List<String> allValidScriptCandidatesInArchive = findCandidates("", archive.getJcrRoot(), aecuService); + List<String> scriptsForInstallation = + getScriptsForExecution(allValidScriptCandidatesInArchive, installContext); + + if (!scriptsForInstallation.isEmpty()) { + HistoryEntry installationHistory = executeScripts(scriptsForInstallation, aecuService, installContext); + if (!HistoryEntry.RESULT.SUCCESS.equals(installationHistory.getResult())) { + throw new PackageException("Failed installation, check installation history at " + installationHistory + .getRepositoryPath()); + } } break; default: @@ -106,21 +108,39 @@ public void execute(InstallContext installContext) throws PackageException { } } - private HistoryEntry executeScripts(AecuService aecuService, InstallContext installContext) - throws AecuException, IOException { - HistoryEntry installationHistory = aecuService.createHistoryEntry(); - Archive archive = installContext.getPackage().getArchive(); - List<String> allValidScriptCandidatesInArchive = findCandidates("", archive.getJcrRoot(), aecuService); + private List<String> getScriptsForExecution(List<String> allValidScriptCandidatesInArchive, InstallContext installContext) { + List<String> scriptsForExecution = new ArrayList<>(); List<String> modifiedOrAddedScriptPaths = listener.getModifiedOrAddedPaths(); for (String groovyScriptPath : allValidScriptCandidatesInArchive) { - HookExecutionHistory hookExecutionHistory = new HookExecutionHistory(installContext.getSession(), groovyScriptPath); - if (modifiedOrAddedScriptPaths.contains(groovyScriptPath) || !hookExecutionHistory.hasBeenExecutedBefore()) { - try { - installationHistory = executeScript(aecuService, installationHistory, groovyScriptPath); - hookExecutionHistory.setExecuted(); - } catch (AecuException e) { - LOG.warn("Error executing script " + groovyScriptPath, e); + try { + HookExecutionHistory hookExecutionHistory = + new HookExecutionHistory(installContext.getSession(), groovyScriptPath); + if (shouldExecute(modifiedOrAddedScriptPaths, groovyScriptPath, hookExecutionHistory)) { + scriptsForExecution.add(groovyScriptPath); } + } catch (AecuException e) { + listener.logError("Could not obtain execution history for " + groovyScriptPath, e); + } + + } + return scriptsForExecution; + } + + private boolean shouldExecute(List<String> modifiedOrAddedScriptPaths, String groovyScriptPath, + HookExecutionHistory hookExecutionHistory) { + return modifiedOrAddedScriptPaths.contains(groovyScriptPath) || !hookExecutionHistory.hasBeenExecutedBefore(); + } + + private HistoryEntry executeScripts(List<String> scriptsForExecution, AecuService aecuService, InstallContext installContext) + throws AecuException, IOException { + HistoryEntry installationHistory = aecuService.createHistoryEntry(); + for (String groovyScriptPath : scriptsForExecution) { + HookExecutionHistory hookExecutionHistory = new HookExecutionHistory(installContext.getSession(), groovyScriptPath); + try { + installationHistory = executeScript(aecuService, installationHistory, groovyScriptPath); + hookExecutionHistory.setExecuted(); + } catch (AecuException e) { + listener.logError("Error executing script " + groovyScriptPath, e); } } installationHistory = aecuService.finishHistoryEntry(installationHistory); @@ -129,10 +149,10 @@ private HistoryEntry executeScripts(AecuService aecuService, InstallContext inst private HistoryEntry executeScript(AecuService aecuService, HistoryEntry installationHistory, String groovyScriptPath) throws AecuException { - LOG.info("Executing script {}", groovyScriptPath); + listener.logMessage("Executing script " + groovyScriptPath); ExecutionResult result = aecuService.execute(groovyScriptPath); installationHistory = aecuService.storeExecutionInHistory(installationHistory, result); - LOG.info("Executed script {}: {}", groovyScriptPath, result.getOutput()); + listener.logMessage("Executed script " + groovyScriptPath + ", output: " + result.getOutput()); return installationHistory; } diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java index 9453a2d9..a2fbc926 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java @@ -20,6 +20,7 @@ import de.valtech.aecu.service.AecuService; +import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.vault.fs.api.ProgressTrackerListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,7 +41,11 @@ public class AecuTrackerListener implements ProgressTrackerListener { private static final Logger LOG = LoggerFactory.getLogger(AecuTrackerListener.class); - private static final Set<String> ACTIONS = new HashSet<>(Arrays.asList("A", "M")); + private static final Set<String> ACTIONS = new HashSet<>(Arrays.asList("A", "M", "U")); + + private static final int VALID_ACTION_LENGTH = 1; + + private static final String LOG_PREFIX = "AECU InstallHook: "; private final ProgressTrackerListener originalListener; private final AecuService aecuService; @@ -55,6 +60,7 @@ public AecuTrackerListener(ProgressTrackerListener originalListener, AecuService this.originalListener = originalListener; this.aecuService = aecuService; this.paths = new LinkedList<>(); + logMessage("Starting install hook..."); } /** @@ -70,13 +76,29 @@ public List<String> getModifiedOrAddedPaths() { public void onMessage(Mode mode, String action, String path) { originalListener.onMessage(mode, action, path); + if (StringUtils.length(action) != VALID_ACTION_LENGTH) { + // skip actions like 'Collecting import information... ', 'Package imported.' etc. + return; + } + + if (StringUtils.endsWith(path, "always.groovy")) { + logMessage(String.format("Adding %s due to having 'always' in name.", path)); + paths.add(path); + return; + } + if (!ACTIONS.contains(action)) { - LOG.debug("Skipping {} due to non matching action {}", path, action); + logMessage(String.format("Skipping %s due to non matching action '%s'", path, action)); return; } + // in case a script was updated the update will actually be shown on jcr:content and not on the groovy script node + if (StringUtils.endsWith(path, "/jcr:content")) { + path = StringUtils.substringBefore(path, "/jcr:content"); + } + if (aecuService.isValidScriptName(path)) { - LOG.debug("Found valid script path {}", path); + logMessage(String.format("Found valid script path '%s'", path)); paths.add(path); } } @@ -85,4 +107,12 @@ public void onMessage(Mode mode, String action, String path) { public void onError(Mode mode, String action, Exception e) { originalListener.onError(mode, action, e); } + + public void logMessage(String message) { + onMessage(Mode.TEXT, LOG_PREFIX + message, ""); + } + + public void logError(String message, Exception e) { + onError(Mode.TEXT, LOG_PREFIX + message, e); + } } From 0e70eb1a345039ad50dde5d085233a67dcffa0a0 Mon Sep 17 00:00:00 2001 From: Christopher Piosecny <christopher.piosecny@valtech.de> Date: Mon, 16 Jul 2018 13:26:00 +0200 Subject: [PATCH 113/122] Fix formatting issue. --- .../java/de/valtech/aecu/core/installhook/AecuInstallHook.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java index 689559b0..40b172fb 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -71,7 +71,8 @@ public AecuInstallHook() { this.osgiServiceProvider = new OsgiServiceProvider(this.getClass()); } - @Override public void execute(InstallContext installContext) throws PackageException { + @Override + public void execute(InstallContext installContext) throws PackageException { LOG.info("Executing in phase {}", installContext.getPhase()); ServiceReference<AecuService> aecuServiceReference = osgiServiceProvider.getServiceReference(AecuService.class); AecuService aecuService = osgiServiceProvider.getService(aecuServiceReference); From 237805061c893caf52cd0508376b81bce4cc14f3 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 13:51:11 +0200 Subject: [PATCH 114/122] binding documentation --- Readme.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 43eea1fc..a22e85b1 100644 --- a/Readme.md +++ b/Readme.md @@ -207,7 +207,7 @@ println aecu.contentUpgradeBuilder() ## Execute Options -### Update Single Value Properies +### Update Single-value Properies * doSetProperty(String name, Object value): sets the given property to the value. Any existing value is overwritten. * doDeleteProperty(String name): removes the property with the given name if existing. @@ -223,6 +223,38 @@ println aecu.contentUpgradeBuilder() .run() ``` +### Update Multi-value Properties + +* doAddValuesToMultiValueProperty(String name, String[] values): adds the list of values to a property. The property is created if it does not yet exist. +* doRemoveValuesOfMultiValueProperty(String name, String[] values): removes the list of values from a given property. +* doReplaceValuesOfMultiValueProperty(String name, String[] oldValues, String[] newValues): removes the old values and adds the new values in a given property. + +```java +println aecu.contentUpgradeBuilder() + .forChildResourcesOf("/content/we-retail/ca/en") + .filterByNodeName("jcr:content") + .doAddValuesToMultiValueProperty("name", (String[])["value1", "value2"]) + .doRemoveValuesOfMultiValueProperty("name", (String[])["value1", "value2"]) + .doReplaceValuesOfMultiValueProperty("name", (String[])["old1", "old2"], (String[])["new1", "new2"]) + .run() +``` + +### Copy and Move Properties + +This will copy or move a property to a subnode. You can also change the property name. + +* doCopyPropertyToRelativePath(String name, String newName, String relativeResourcePath): copy the property to the given path under the new name. +* doMovePropertyToRelativePath(String name, String newName, String relativeResourcePath): move the property to the given path under the new name. + +```java +println aecu.contentUpgradeBuilder() + .forChildResourcesOf("/content/we-retail/ca/en") + .filterByNodeName("jcr:content") + .doCopyPropertyToRelativePath("name", "newName", "subnode") + .doMovePropertyToRelativePath("name", "newName", "subnode") + .run() +``` + TODO # JMX Interface From 22ada3efacbcff2d9601cb8e16920702862f3219 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 14:00:02 +0200 Subject: [PATCH 115/122] formatting --- .../aecu/core/installhook/AecuInstallHook.java | 10 ++++++---- .../core/installhook/AecuTrackerListener.java | 10 +++++++--- .../core/installhook/HookExecutionHistory.java | 9 ++++++--- .../core/installhook/OsgiServiceProvider.java | 15 ++++++++++----- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java index 40b172fb..697bb09d 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuInstallHook.java @@ -38,9 +38,11 @@ import java.util.List; /** - * InstallHook handling installation of groovy scripts. The InstallHook gathers groovy scripts contained in the installed vault - * package and executes them depending on active runmodes and if the script has been added, modified or never executed. <br> + * InstallHook handling installation of groovy scripts. The InstallHook gathers groovy scripts + * contained in the installed vault package and executes them depending on active runmodes and if + * the script has been added, modified or never executed. <br> * Example usage in content-package-maven-plugin: + * * <pre> * {@code * <plugin> @@ -94,8 +96,8 @@ public void execute(InstallContext installContext) throws PackageException { if (!scriptsForInstallation.isEmpty()) { HistoryEntry installationHistory = executeScripts(scriptsForInstallation, aecuService, installContext); if (!HistoryEntry.RESULT.SUCCESS.equals(installationHistory.getResult())) { - throw new PackageException("Failed installation, check installation history at " + installationHistory - .getRepositoryPath()); + throw new PackageException("Failed installation, check installation history at " + + installationHistory.getRepositoryPath()); } } break; diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java index a2fbc926..bc3c3d14 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/AecuTrackerListener.java @@ -53,8 +53,9 @@ public class AecuTrackerListener implements ProgressTrackerListener { /** * Constructor. + * * @param originalListener the original ProgressTrackerListener. - * @param aecuService an AecuService instance. + * @param aecuService an AecuService instance. */ public AecuTrackerListener(ProgressTrackerListener originalListener, AecuService aecuService) { this.originalListener = originalListener; @@ -64,7 +65,9 @@ public AecuTrackerListener(ProgressTrackerListener originalListener, AecuService } /** - * Returns an unmodifiable list of the modified or added paths encountered during the installation phase. + * Returns an unmodifiable list of the modified or added paths encountered during the + * installation phase. + * * @return a list of modified or added paths, can be empty. */ @Nonnull @@ -92,7 +95,8 @@ public void onMessage(Mode mode, String action, String path) { return; } - // in case a script was updated the update will actually be shown on jcr:content and not on the groovy script node + // in case a script was updated the update will actually be shown on jcr:content and not on + // the groovy script node if (StringUtils.endsWith(path, "/jcr:content")) { path = StringUtils.substringBefore(path, "/jcr:content"); } diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java b/core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java index 08d54023..39a96583 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/HookExecutionHistory.java @@ -47,7 +47,8 @@ public class HookExecutionHistory { /** * Constructor. - * @param session a session with write permissons on {@value HISTORY_BASE_PATH}. + * + * @param session a session with write permissons on {@value HISTORY_BASE_PATH}. * @param groovyScriptPath the groovy script to instantiate the execution history for. * @throws AecuException in case the call to JcrUtils.getOrCreateByPath fails. */ @@ -61,8 +62,9 @@ public HookExecutionHistory(Session session, String groovyScriptPath) throws Aec } /** - * Returns if the script has been executed before. This is determined by checking existence of the property - * {@value PN_EXECUTED} on the history node. + * Returns if the script has been executed before. This is determined by checking existence of + * the property {@value PN_EXECUTED} on the history node. + * * @return true if it has been executed previously, false otherwise. */ public boolean hasBeenExecutedBefore() { @@ -77,6 +79,7 @@ public boolean hasBeenExecutedBefore() { /** * Sets {@value PN_EXECUTED} on the history node to the current date. + * * @throws AecuException in case the property could not be saved. */ public void setExecuted() throws AecuException { diff --git a/core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java b/core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java index a95dde3b..67da6787 100644 --- a/core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java +++ b/core/src/main/java/de/valtech/aecu/core/installhook/OsgiServiceProvider.java @@ -34,6 +34,7 @@ public class OsgiServiceProvider { /** * Constructor. + * * @param clazz the class that was loaded over a bundle classloader. */ public OsgiServiceProvider(@Nonnull Class clazz) { @@ -49,12 +50,14 @@ public OsgiServiceProvider(@Nonnull Class clazz) { /** * Retrieves a {@link ServiceReference} for the given class. + * * @see org.osgi.framework.BundleContext#getServiceReference(Class) * @param clazz the class to retrieve a {@link ServiceReference} for. - * @param <T> the type of the service. + * @param <T> the type of the service. * @return a {@link ServiceReference} for the requested service. */ - @Nonnull <T> ServiceReference<T> getServiceReference(@Nonnull Class<T> clazz) { + @Nonnull + <T> ServiceReference<T> getServiceReference(@Nonnull Class<T> clazz) { ServiceReference<T> serviceReference = bundleContext.getServiceReference(clazz); if (serviceReference == null) { throw new IllegalStateException("Could not retrieve service reference for class " + clazz); @@ -64,15 +67,17 @@ public OsgiServiceProvider(@Nonnull Class clazz) { /** * Retrieves the service object the {@link ServiceReference} is pointing to. + * * @see org.osgi.framework.BundleContext#getService(ServiceReference) * @param serviceReference the {@link ServiceReference}. - * @param <T> the service type. + * @param <T> the service type. * @return the service instance. */ - @Nonnull <T> T getService(@Nonnull ServiceReference<T> serviceReference) { + @Nonnull + <T> T getService(@Nonnull ServiceReference<T> serviceReference) { T service = bundleContext.getService(serviceReference); if (service == null) { - throw new IllegalStateException("Could not get the service for reference " + serviceReference + throw new IllegalStateException("Could not get the service for reference " + serviceReference + ", verify that the bundle was installed correctly!"); } return service; From ac9abdd725621cd03c089c68342400078c2cc4a4 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 15:00:35 +0200 Subject: [PATCH 116/122] added meta data --- api/pom.xml | 6 ++++ core/pom.xml | 6 ++++ pom.xml | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/api/pom.xml b/api/pom.xml index 1193be53..374e9e4b 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -7,10 +7,12 @@ <artifactId>aecu</artifactId> <version>1.0-SNAPSHOT</version> </parent> + <artifactId>aecu.api</artifactId> <packaging>bundle</packaging> <name>AECU - API</name> <description>Api bundle for AECU</description> + <build> <plugins> <plugin> @@ -28,6 +30,10 @@ </instructions> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + </plugin> </plugins> </build> diff --git a/core/pom.xml b/core/pom.xml index c39cb8a5..3b4fd4de 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -7,10 +7,12 @@ <artifactId>aecu</artifactId> <version>1.0-SNAPSHOT</version> </parent> + <artifactId>aecu.core</artifactId> <packaging>bundle</packaging> <name>AECU - Core</name> <description>Core bundle for AECU</description> + <build> <plugins> <plugin> @@ -31,6 +33,10 @@ </instructions> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + </plugin> </plugins> </build> diff --git a/pom.xml b/pom.xml index 93dcd2e9..a471b0ca 100644 --- a/pom.xml +++ b/pom.xml @@ -8,6 +8,7 @@ <version>1.0-SNAPSHOT</version> <name>AECU</name> <description>AEM Easy COntent Upgrade</description> + <url>https://github.com/valtech/aem-easy-content-upgrade</url> <modules> <module>api</module> @@ -122,6 +123,21 @@ <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.9.1</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-project-info-reports-plugin</artifactId> + <version>2.7</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-site-plugin</artifactId> + <version>3.3</version> + </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-install-plugin</artifactId> @@ -498,5 +514,84 @@ </dependency> </dependencies> </dependencyManagement> + + <licenses> + <license> + <name>MIT License</name> + <url>http://www.opensource.org/licenses/mit-license.php</url> + </license> + </licenses> + + <developers> + <developer> + <name>Roland Gruber</name> + <email>roland.gruber@valtech.de</email> + <organization>Valtech GmbH</organization> + <organizationUrl>https://www.valtech.de/</organizationUrl> + </developer> + <developer> + <name>Roxana Mureșan</name> + <email>roxana.muresan@valtech.de</email> + <organization>Valtech GmbH</organization> + <organizationUrl>https://www.valtech.de/</organizationUrl> + </developer> + <developer> + <name>Bryan Chavez</name> + <email>bryan.chavez@valtech.de</email> + <organization>Valtech GmbH</organization> + <organizationUrl>https://www.valtech.de/</organizationUrl> + </developer> + <developer> + <name>Christopher Piosecny</name> + <email>christopher.piosecny@valtech.de</email> + <organization>Valtech GmbH</organization> + <organizationUrl>https://www.valtech.de/</organizationUrl> + </developer> + <developer> + <name>Robert Lingner</name> + <email>robert.lingner@valtech.de</email> + <organization>Valtech GmbH</organization> + <organizationUrl>https://www.valtech.de/</organizationUrl> + </developer> + </developers> + + <scm> + <connection>scm:git:https://github.com/valtech/aem-easy-content-upgrade.git</connection> + <developerConnection>scm:git:git@github.com:valtech/aem-easy-content-upgrade.git</developerConnection> + <url>https://github.com/valtech/aem-easy-content-upgrade</url> + </scm> + + <issueManagement> + <system>Github</system> + <url>https://github.com/valtech/aem-easy-content-upgrade/issues</url> + </issueManagement> + + <distributionManagement> + <snapshotRepository> + <id>ossrh</id> + <url>https://oss.sonatype.org/content/repositories/snapshots</url> + </snapshotRepository> + <repository> + <id>ossrh</id> + <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> + </repository> + </distributionManagement> + + <repositories> + <repository> + <id>adobe</id> + <name>Adobe Public Repository</name> + <url>http://repo.adobe.com/nexus/content/groups/public/</url> + <layout>default</layout> + </repository> + </repositories> + <pluginRepositories> + <pluginRepository> + <id>adobe</id> + <name>Adobe Public Repository</name> + <url>http://repo.adobe.com/nexus/content/groups/public/</url> + <layout>default</layout> + </pluginRepository> + </pluginRepositories> </project> From 409607da1bbf3b616b0ae76fc8fe8f3046d23d1c Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 15:08:58 +0200 Subject: [PATCH 117/122] release plugin --- pom.xml | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index a471b0ca..ebc19516 100644 --- a/pom.xml +++ b/pom.xml @@ -35,14 +35,15 @@ <build> <plugins> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-release-plugin</artifactId> - <version>2.5.3</version> + <groupId>external.atlassian.jgitflow</groupId> + <artifactId>jgitflow-maven-plugin</artifactId> + <version>1.0-m5.1</version> <configuration> - <scmCommentPrefix>[maven-scm] :</scmCommentPrefix> - <preparationGoals>clean install</preparationGoals> - <goals>install</goals> - <releaseProfiles>release</releaseProfiles> + <enableSshAgent>true</enableSshAgent> + <enableFeatureVersions>true</enableFeatureVersions> + <pushReleases>true</pushReleases> + <autoVersionSubmodules>true</autoVersionSubmodules> + <releaseBranchVersionSuffix>rc</releaseBranchVersionSuffix> </configuration> </plugin> <plugin> @@ -105,6 +106,17 @@ <downloadSources>true</downloadSources> </configuration> </plugin> + <plugin> + <groupId>org.sonatype.plugins</groupId> + <artifactId>nexus-staging-maven-plugin</artifactId> + <version>1.6.3</version> + <extensions>true</extensions> + <configuration> + <serverId>ossrh</serverId> + <nexusUrl>https://oss.sonatype.org/</nexusUrl> + <autoReleaseAfterClose>true</autoReleaseAfterClose> + </configuration> + </plugin> </plugins> <pluginManagement> <plugins> @@ -366,6 +378,33 @@ </pluginManagement> </build> </profile> + + <profile> + <id>release</id> + <activation> + <property> + <name>performRelease</name> + </property> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.6</version> + <executions> + <execution> + <id>sign-artifacts</id> + <phase>verify</phase> + <goals> + <goal>sign</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> </profiles> From 6a041df4fd28586dfd061d6cebcdae3c81e0df43 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 15:11:03 +0200 Subject: [PATCH 118/122] jgitflow --- pom.xml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pom.xml b/pom.xml index ebc19516..5d149269 100644 --- a/pom.xml +++ b/pom.xml @@ -34,18 +34,6 @@ <build> <plugins> - <plugin> - <groupId>external.atlassian.jgitflow</groupId> - <artifactId>jgitflow-maven-plugin</artifactId> - <version>1.0-m5.1</version> - <configuration> - <enableSshAgent>true</enableSshAgent> - <enableFeatureVersions>true</enableFeatureVersions> - <pushReleases>true</pushReleases> - <autoVersionSubmodules>true</autoVersionSubmodules> - <releaseBranchVersionSuffix>rc</releaseBranchVersionSuffix> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> @@ -170,6 +158,18 @@ <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> + <plugin> + <groupId>external.atlassian.jgitflow</groupId> + <artifactId>jgitflow-maven-plugin</artifactId> + <version>1.0-m5.1</version> + <configuration> + <enableSshAgent>true</enableSshAgent> + <enableFeatureVersions>true</enableFeatureVersions> + <pushReleases>true</pushReleases> + <autoVersionSubmodules>true</autoVersionSubmodules> + <releaseBranchVersionSuffix>rc</releaseBranchVersionSuffix> + </configuration> + </plugin> <plugin> <groupId>org.apache.sling</groupId> <artifactId>maven-sling-plugin</artifactId> From fe4a5baec2c1cec0e23bb64697564a81befb391b Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 15:12:16 +0200 Subject: [PATCH 119/122] updating poms for 0.9 branch with snapshot versions --- api/pom.xml | 5 ++--- bundle/pom.xml | 5 ++--- core/pom.xml | 5 ++--- examples/pom.xml | 5 ++--- pom.xml | 11 +++++------ ui.apps/pom.xml | 5 ++--- 6 files changed, 15 insertions(+), 21 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 374e9e4b..1f1538e6 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -1,11 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> -<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"> +<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> <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>1.0-SNAPSHOT</version> + <version>0.9-rc-SNAPSHOT</version> </parent> <artifactId>aecu.api</artifactId> diff --git a/bundle/pom.xml b/bundle/pom.xml index c9bb9653..87a1ef1c 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -1,12 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>1.0-SNAPSHOT</version> + <version>0.9-rc-SNAPSHOT</version> </parent> <artifactId>aecu.bundle</artifactId> diff --git a/core/pom.xml b/core/pom.xml index 3b4fd4de..8587ac41 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -1,11 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> -<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"> +<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> <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>1.0-SNAPSHOT</version> + <version>0.9-rc-SNAPSHOT</version> </parent> <artifactId>aecu.core</artifactId> diff --git a/examples/pom.xml b/examples/pom.xml index aa608396..0dfdb7c9 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,12 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>1.0-SNAPSHOT</version> + <version>0.9-rc-SNAPSHOT</version> </parent> <artifactId>aecu.examples</artifactId> diff --git a/pom.xml b/pom.xml index 5d149269..846f6ca9 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> <packaging>pom</packaging> - <version>1.0-SNAPSHOT</version> + <version>0.9-rc-SNAPSHOT</version> <name>AECU</name> <description>AEM Easy COntent Upgrade</description> <url>https://github.com/valtech/aem-easy-content-upgrade</url> @@ -244,7 +243,7 @@ </goals> </pluginExecutionFilter> <action> - <ignore/> + <ignore /> </action> </pluginExecution> <pluginExecution> @@ -264,7 +263,7 @@ </goals> </pluginExecutionFilter> <action> - <ignore/> + <ignore /> </action> </pluginExecution> <pluginExecution> @@ -285,7 +284,7 @@ </goals> </pluginExecutionFilter> <action> - <ignore/> + <ignore /> </action> </pluginExecution> </pluginExecutions> diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index 1d6801ab..deaf7f42 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -1,12 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> -<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/maven-v4_0_0.xsd"> +<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>1.0-SNAPSHOT</version> + <version>0.9-rc-SNAPSHOT</version> </parent> <artifactId>aecu.ui.apps</artifactId> From 7a1509a0f4fe1f794466c9f688409b6cdb054be9 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 15:12:46 +0200 Subject: [PATCH 120/122] updating poms for branch'release/0.9' with non-snapshot versions --- api/pom.xml | 2 +- bundle/pom.xml | 2 +- core/pom.xml | 2 +- examples/pom.xml | 2 +- pom.xml | 2 +- ui.apps/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 1f1538e6..d1053df9 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>0.9-rc-SNAPSHOT</version> + <version>0.9</version> </parent> <artifactId>aecu.api</artifactId> diff --git a/bundle/pom.xml b/bundle/pom.xml index 87a1ef1c..aa33e8b8 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>0.9-rc-SNAPSHOT</version> + <version>0.9</version> </parent> <artifactId>aecu.bundle</artifactId> diff --git a/core/pom.xml b/core/pom.xml index 8587ac41..c7370c81 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>0.9-rc-SNAPSHOT</version> + <version>0.9</version> </parent> <artifactId>aecu.core</artifactId> diff --git a/examples/pom.xml b/examples/pom.xml index 0dfdb7c9..b8bd3e7d 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>0.9-rc-SNAPSHOT</version> + <version>0.9</version> </parent> <artifactId>aecu.examples</artifactId> diff --git a/pom.xml b/pom.xml index 846f6ca9..dbc64fe8 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> <packaging>pom</packaging> - <version>0.9-rc-SNAPSHOT</version> + <version>0.9</version> <name>AECU</name> <description>AEM Easy COntent Upgrade</description> <url>https://github.com/valtech/aem-easy-content-upgrade</url> diff --git a/ui.apps/pom.xml b/ui.apps/pom.xml index deaf7f42..62c4ed8c 100644 --- a/ui.apps/pom.xml +++ b/ui.apps/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>de.valtech.aecu</groupId> <artifactId>aecu</artifactId> - <version>0.9-rc-SNAPSHOT</version> + <version>0.9</version> </parent> <artifactId>aecu.ui.apps</artifactId> From c422d72ea602221f9254670455f7ceebfcc6efc0 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 15:37:39 +0200 Subject: [PATCH 121/122] no javadoc --- core/pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index c7370c81..f8bcd30d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -32,10 +32,6 @@ </instructions> </configuration> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - </plugin> </plugins> </build> From 58c86620e56ec82516806a3b878f7d00c2123543 Mon Sep 17 00:00:00 2001 From: Roland Gruber <roland.gruber@valtech.de> Date: Mon, 16 Jul 2018 15:47:01 +0200 Subject: [PATCH 122/122] JavaDoc update --- .../console/bindings/ContentUpgrade.java | 50 +++++++++++-------- .../aecu/core/history/HistoryUtil.java | 1 - .../aecu/core/jmx/AecuServiceMBean.java | 1 + .../aecu/core/jmx/AecuServiceMBeanImpl.java | 2 + .../aecu/core/servlets/ExecutionServlet.java | 2 + 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java index ec107801..daf5db84 100644 --- a/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java +++ b/core/src/main/java/de/valtech/aecu/core/groovy/console/bindings/ContentUpgrade.java @@ -1,5 +1,18 @@ package de.valtech.aecu.core.groovy.console.bindings; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; + +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.ResourceResolver; +import org.scribe.utils.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import de.valtech.aecu.core.groovy.console.bindings.actions.Action; import de.valtech.aecu.core.groovy.console.bindings.actions.PrintPath; import de.valtech.aecu.core.groovy.console.bindings.actions.multivalue.AddMultiValues; @@ -22,19 +35,6 @@ import de.valtech.aecu.core.groovy.console.bindings.traversers.ForResources; import de.valtech.aecu.core.groovy.console.bindings.traversers.TraversData; -import org.apache.sling.api.resource.PersistenceException; -import org.apache.sling.api.resource.ResourceResolver; -import org.scribe.utils.MapUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nonnull; - public class ContentUpgrade { private static Logger LOG = LoggerFactory.getLogger(ContentUpgrade.class); @@ -51,7 +51,10 @@ public ContentUpgrade(@Nonnull ResourceResolver resourceResolver) { } /** - * content path filter methods + * Loops for given list of resources. + * + * @param paths list of paths + * @return upgrade object **/ public ContentUpgrade forResources(@Nonnull String[] paths) { LOG.debug("forResources: {}", paths.toString()); @@ -72,7 +75,10 @@ public ContentUpgrade forDescendantResourcesOf(@Nonnull String path) { } /** - * filters + * Filters by properties. + * + * @param conditionProperties properties to filter + * @return upgrade object **/ public ContentUpgrade filterByProperties(@Nonnull Map<String, String> conditionProperties) { LOG.debug("filterByProperties: {}", MapUtils.toString(conditionProperties)); @@ -99,7 +105,11 @@ public ContentUpgrade filterWith(@Nonnull FilterBy filter) { } /** - * properties edit methods + * Sets a property value. + * + * @param name property name + * @param value property value + * @return upgrade object **/ public ContentUpgrade doSetProperty(@Nonnull String name, Object value) { LOG.debug("doSetProperty: {} = {}", name, value); @@ -153,9 +163,6 @@ public ContentUpgrade doReplaceValuesOfMultiValueProperty(@Nonnull String name, return this; } - /** - * resource edit methods - **/ public ContentUpgrade doCopyResourceToRelativePath(@Nonnull String relativePath) { LOG.debug("doCopyResource to {}", relativePath); actions.add(new CopyResourceToRelativePath(relativePath, resourceResolver)); @@ -176,6 +183,8 @@ public ContentUpgrade doDeleteResource() { /** * Print path + * + * @return upgrade object */ public ContentUpgrade printPath() { LOG.debug("printPath"); @@ -183,9 +192,6 @@ public ContentUpgrade printPath() { return this; } - /** - * runner methods - **/ public StringBuffer run() throws PersistenceException { LOG.debug("apply content upgrade"); return run(false); diff --git a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java index 185ac9d6..3f76d869 100644 --- a/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java +++ b/core/src/main/java/de/valtech/aecu/core/history/HistoryUtil.java @@ -117,7 +117,6 @@ public void storeExecutionInHistory(HistoryEntry history, ExecutionResult result * * @param history open history entry * @param resolver resource resolver - * @return history entry */ public void finishHistoryEntry(HistoryEntry history, ResourceResolver resolver) { Resource resource = resolver.getResource(history.getRepositoryPath()); diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java index c6802db8..7cc6eed6 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBean.java @@ -67,6 +67,7 @@ public interface AecuServiceMBean { * @param start start index (0 is last run) * @param count number of entries to return * @return history entries + * @throws AecuException error reading history */ @Description("Returns the last history entries") String getHistory(@Name("Start index") int start, @Name("Count") int count) throws AecuException; diff --git a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java index 41f8b22f..a34241fc 100644 --- a/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java +++ b/core/src/main/java/de/valtech/aecu/core/jmx/AecuServiceMBeanImpl.java @@ -41,6 +41,8 @@ public class AecuServiceMBeanImpl extends AnnotatedStandardMBean implements Aecu /** * Constructor + * + * @throws NotCompliantMBeanException error setting up mbean */ public AecuServiceMBeanImpl() throws NotCompliantMBeanException { super(AecuServiceMBean.class); diff --git a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java index 3cee1359..9983cae5 100644 --- a/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java +++ b/core/src/main/java/de/valtech/aecu/core/servlets/ExecutionServlet.java @@ -130,6 +130,8 @@ protected HistoryEntry finishHistoryEntry(HistoryEntry historyEntry, String hist * This method builds the JSON String for the response. Eg: {"success": * true,"historyEntryPath":"/var/aecu/2018/6/13/152892696338961314"} * + * @param status success or fail + * @param historyEntryPath path to history node * @return json String */ protected String prepareJson(boolean status, String historyEntryPath) {