Skip to content

Commit

Permalink
Merge branch 'release/11.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
markdaugherty committed Dec 7, 2017
2 parents f6ed43e + 8bd0c40 commit 3e38f25
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 17 deletions.
33 changes: 29 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ The AEM Groovy Console provides an interface for running [Groovy](http://www.gro

## Requirements

* AEM author instance running on localhost:4502
* AEM author instance running on [localhost:4502](http://localhost:4502/)
* [Maven](http://maven.apache.org/) 3.x

## Compatibility

Groovy Console Version(s) | AEM Version
------------ | -------------
11.x.x | 6.3
10.x.x, 9.x.x | 6.2
10.x.x, 9.x.x | 6.2
8.x.x | 6.1
7.x.x | 6.0
6.x.x, 5.x.x | 5.6 (CQ)
Expand All @@ -30,9 +30,9 @@ Groovy Console Version(s) | AEM Version

2. [Verify](http://localhost:4502/etc/groovyconsole.html) the installation.

Additional build profiles may be added in the project's pom.xml to support deployment to non-localhost AEM servers.
Additional build profiles may be added in the project's `pom.xml` to support deployment to non-localhost AEM servers.

AEM 6.0 no longer allows vanity paths for pages in /etc by default. To enable access to the Groovy Console from /groovyconsole as in previous versions, the Apache Sling Resource Resolver Factory OSGi configuration must be updated to allow vanity paths from /etc. The Groovy Console Configuration Service can then be updated to enable the vanity path if so desired.
AEM 6.0 no longer allows vanity paths for pages in `/etc` by default. To enable access to the Groovy Console from `/groovyconsole` as in previous versions, the **Apache Sling Resource Resolver Factory** OSGi configuration must be updated to allow vanity paths from `/etc`. The **Groovy Console Configuration Service** can then be updated to enable the vanity path if so desired.

## Excluding the Groovy OSGi Bundle

Expand All @@ -46,6 +46,31 @@ If you are running AEM with a context path, set the Maven property `aem.context.

mvn install -P local -Daem.context.path=/context

## OSGi Configuration

Navigate to the [OSGi console configuration page](http://localhost:4502/system/console/configMgr) and select the **Groovy Console Configuration Service**.

Property | Description | Default Value
------------ | ------------- | ----------
Email Enabled? | Check to enable email notification on completion of script execution. | False
Email Recipients | Email addresses to receive notification. | []
Allowed Groups | List of group names that are authorized to use the console. If empty, no authorization check is performed. | []
Vanity Path Enabled? | Enables `/groovyconsole` vanity path. **Apache Sling Resource Resolver Factory** OSGi configuration must also be updated to allow vanity paths from `/etc`. | False
Audit Disabled? | Disables auditing of script execution history. | False
Display All Audit Records? | If enabled, all audit records (including records for other users) will be displayed in the console history. | False

## Batch Script Execution

Saved scripts can be remotely executed by sending a POST request to the console servlet with either the `scriptPath` or `scriptPaths` query parameter.

### Single Script

curl -d "scriptPath=/etc/groovyconsole/scripts/samples/JcrSearch.groovy" -X POST -u admin:admin http://localhost:4502/bin/groovyconsole/post.json

### Multiple Scripts

curl -d "scriptPaths=/etc/groovyconsole/scripts/samples/JcrSearch.groovy&scriptPaths=/etc/groovyconsole/scripts/samples/FulltextQuery.groovy" -X POST -u admin:admin http://localhost:4502/bin/groovyconsole/post.json

## Extensions

Beginning in version 7.0.0, the Groovy Console provides extension hooks to further customize script execution. The console exposes an API containing three extension provider interfaces that can be implemented as OSGi services in any bundle deployed to an AEM instance. See the default extension providers in the `com.icfolson.aem.groovy.console.extension.impl` package for examples of how a bundle can implement these services to supply additional script bindings, metaclasses, and star imports.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<groupId>com.icfolson.aem.groovy.console</groupId>
<artifactId>aem-groovy-console</artifactId>
<packaging>jar</packaging>
<version>11.1.0</version>
<version>11.2.0</version>
<name>AEM Groovy Console</name>
<description>
The AEM Groovy Console provides an interface for running Groovy scripts in the AEM container. Scripts can be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ interface GroovyConsoleService {

RunScriptResponse runScript(SlingHttpServletRequest request)

RunScriptResponse runScript(SlingHttpServletRequest request, String scriptPath)

List<RunScriptResponse> runScripts(SlingHttpServletRequest request, List<String> scriptPaths)

SaveScriptResponse saveScript(SlingHttpServletRequest request)
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ class DefaultAuditService implements AuditService {
def auditRecordNode = addAuditRecordNode(session)

auditRecordNode.setProperty(AuditRecord.PROPERTY_SCRIPT, response.script)
auditRecordNode.setProperty(AuditRecord.PROPERTY_DATA, response.data)

if (response.data) {
auditRecordNode.setProperty(AuditRecord.PROPERTY_DATA, response.data)
}

if (response.exceptionStackTrace) {
auditRecordNode.setProperty(AuditRecord.PROPERTY_EXCEPTION_STACK_TRACE, response.exceptionStackTrace)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ class GroovyConsoleConstants {

public static final String EXTENSION_GROOVY = ".groovy"

public static final String PARAMETER_SCRIPT_PATH = "scriptPath"

public static final String PARAMETER_SCRIPT_PATHS = "scriptPaths"

public static final String PARAMETER_SCRIPT = "script"

public static final String PARAMETER_USER_ID = "userId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import javax.jcr.Node
import javax.jcr.Session
import java.util.concurrent.CopyOnWriteArrayList

import static com.google.common.base.Preconditions.checkNotNull
import static com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants.EXTENSION_GROOVY
import static com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants.PARAMETER_DATA
import static com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants.PATH_CONSOLE_ROOT
Expand Down Expand Up @@ -75,12 +76,25 @@ class DefaultGroovyConsoleService implements GroovyConsoleService {

@Override
RunScriptResponse runScript(SlingHttpServletRequest request) {
def scriptContent = request.getRequestParameter(PARAMETER_SCRIPT)?.getString(CharEncoding.UTF_8)
def data = request.getRequestParameter(PARAMETER_DATA)?.getString(CharEncoding.UTF_8)
runScript(request, null)
}

def stream = new ByteArrayOutputStream()
@Override
RunScriptResponse runScript(SlingHttpServletRequest request, String scriptPath) {
def session = request.resourceResolver.adaptTo(Session)

def scriptContent

if (scriptPath) {
scriptContent = loadScriptContent(session, scriptPath)
} else {
scriptContent = request.getRequestParameter(PARAMETER_SCRIPT)?.getString(CharEncoding.UTF_8)
}

checkNotNull(scriptContent, "Script content cannot be empty.")

def data = request.getRequestParameter(PARAMETER_DATA)?.getString(CharEncoding.UTF_8)
def stream = new ByteArrayOutputStream()
def response = null

def binding = getBinding(extensionService.getBinding(request), data, stream)
Expand Down Expand Up @@ -121,6 +135,13 @@ class DefaultGroovyConsoleService implements GroovyConsoleService {
response
}

@Override
List<RunScriptResponse> runScripts(SlingHttpServletRequest request, List<String> scriptPaths) {
scriptPaths.collect { scriptPath ->
runScript(request, scriptPath)
}
}

@Override
@Synchronized
SaveScriptResponse saveScript(SlingHttpServletRequest request) {
Expand Down Expand Up @@ -192,6 +213,19 @@ class DefaultGroovyConsoleService implements GroovyConsoleService {
}
}

private String loadScriptContent(Session session, String scriptPath) {
def binary = session.getNode(scriptPath)
.getNode(JcrConstants.JCR_CONTENT)
.getProperty(JcrConstants.JCR_DATA)
.binary

def scriptContent = binary.stream.text

binary.dispose()

scriptContent
}

private void saveFile(Session session, Node folderNode, String script, String fileName, Date date,
String mimeType) {
def fileNode = folderNode.addNode(Text.escapeIllegalJcrChars(fileName), JcrConstants.NT_FILE)
Expand All @@ -200,13 +234,11 @@ class DefaultGroovyConsoleService implements GroovyConsoleService {
def stream = new ByteArrayInputStream(script.getBytes(CharEncoding.UTF_8))
def binary = session.valueFactory.createBinary(stream)

resourceNode.with {
setProperty(JcrConstants.JCR_MIMETYPE, mimeType)
setProperty(JcrConstants.JCR_ENCODING, CharEncoding.UTF_8)
setProperty(JcrConstants.JCR_DATA, binary)
setProperty(JcrConstants.JCR_LASTMODIFIED, date.time)
setProperty(JcrConstants.JCR_LAST_MODIFIED_BY, session.userID)
}
resourceNode.setProperty(JcrConstants.JCR_MIMETYPE, mimeType)
resourceNode.setProperty(JcrConstants.JCR_ENCODING, CharEncoding.UTF_8)
resourceNode.setProperty(JcrConstants.JCR_DATA, binary)
resourceNode.setProperty(JcrConstants.JCR_LASTMODIFIED, date.time)
resourceNode.setProperty(JcrConstants.JCR_LAST_MODIFIED_BY, session.userID)

session.save()
binary.dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.icfolson.aem.groovy.console.servlets

import com.icfolson.aem.groovy.console.GroovyConsoleService
import com.icfolson.aem.groovy.console.configuration.ConfigurationService
import com.icfolson.aem.groovy.console.constants.GroovyConsoleConstants
import groovy.util.logging.Slf4j
import org.apache.felix.scr.annotations.Reference
import org.apache.felix.scr.annotations.sling.SlingServlet
Expand All @@ -26,7 +27,23 @@ class ScriptPostServlet extends AbstractJsonResponseServlet {
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws
ServletException, IOException {
if (configurationService.hasPermission(request)) {
writeJsonResponse(response, consoleService.runScript(request))
def scriptPaths = request.getParameterValues(GroovyConsoleConstants.PARAMETER_SCRIPT_PATHS)

if (scriptPaths) {
LOG.debug("running scripts for paths = {}", scriptPaths)

writeJsonResponse(response, consoleService.runScripts(request, scriptPaths as List))
} else {
def scriptPath = request.getParameter(GroovyConsoleConstants.PARAMETER_SCRIPT_PATH)

if (scriptPath) {
LOG.debug("running script for path = {}", scriptPath)

writeJsonResponse(response, consoleService.runScript(request, scriptPath))
} else {
writeJsonResponse(response, consoleService.runScript(request))
}
}
} else {
response.status = SC_FORBIDDEN
}
Expand Down

0 comments on commit 3e38f25

Please sign in to comment.