blob: f8d0b94dff4b44d944b26b0094b461baed7ba08e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.sling.maven.repoinit;
import java.io.File;
import java.io.FileReader;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
import javax.jcr.Session;
import org.apache.jackrabbit.commons.cnd.CndImporter;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
import org.apache.sling.jcr.repoinit.impl.JcrRepoInitOpsProcessorImpl;
import org.apache.sling.maven.repoinit.ContentFolder.Type;
import org.apache.sling.repoinit.parser.operations.Operation;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.context.SlingContextImpl;
import org.jetbrains.annotations.NotNull;
/**
* Goal which validates the specified RepoInit files by installing them into a
* mock Sling repository. Any errors encountered will be reported and fail the
* build.
*/
@Mojo(name = "validate", defaultPhase = LifecyclePhase.TEST, requiresProject = false)
public class ValidateMojo extends ParseMojo {
/**
* CND (compact node definitions) to load before running the validation.
* Supports glob style patterns. All globs are evaluated relative to the
* <code>${project.basedir}</code>
*
* <a href="https://docs.oracle.com/javase/tutorial/essential/io/find.html">More
* on Globs in Java</a>
*/
@Parameter(property = "repoinit.nodeDefinitions", required = false)
List<String> nodeDefinitions;
/**
* Initial content folders to load before running the RepoInit scripts.
*/
@Parameter(property = "repoinit.contentFolders", required = false)
List<ContentFolder> contentFolders;
/**
* The Maven Project
*/
@Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project = null;
@Override
public void execute()
throws MojoExecutionException {
getLog().info("Loading scripts from: " + scriptBaseDir);
List<File> scripts = findScripts();
if (scripts.isEmpty()) {
return;
}
LinkedHashMap<String, List<Operation>> parsedScripts = new LinkedHashMap<>();
for (File script : scripts) {
getLog().debug("Parsing script: " + script.getAbsolutePath());
parsedScripts.put(script.getAbsolutePath(), parseScript(script));
}
getLog().info("All scripts parsed successfully!");
getLog().info("Setting up Sling context...");
try (ValidatorContext context = new ValidatorContext()) {
Session session = Optional.ofNullable(context.resourceResolver().adaptTo(Session.class))
.orElseThrow(() -> new MojoExecutionException("Failed to get Session from Sling Context"));
if (nodeDefinitions != null && !nodeDefinitions.isEmpty()) {
getLog().info("Loading nodetypes");
loadNodeDefinitions(nodeDefinitions, session);
}
if (contentFolders != null && !contentFolders.isEmpty()) {
getLog().info("Loading initial content");
loadInitialContent(contentFolders, context);
}
JcrRepoInitOpsProcessor processor = new JcrRepoInitOpsProcessorImpl();
for (Entry<String, List<Operation>> parsed : parsedScripts.entrySet()) {
getLog().info("Executing script: " + parsed.getKey());
try {
processor.apply(session, parsed.getValue());
} catch (Exception e) {
throw new MojoExecutionException("Failed to execute script: " + parsed.getKey()
+ ", Exception: " + e.toString(), e);
}
}
}
getLog().info("All scripts executed successfully!");
}
void loadNodeDefinitions(@NotNull List<String> globs, @NotNull Session session) throws MojoExecutionException {
File root = new File(".");
List<File> cndFiles = findByGlob(root, globs);
for (File cndFile : cndFiles) {
getLog().info("Loading node types from: " + cndFile.getAbsolutePath());
try {
CndImporter.registerNodeTypes(new FileReader(cndFile), session);
} catch (Exception e) {
throw new MojoExecutionException(
"Failed to load CND file: " + cndFile.getAbsolutePath() + ", Exception: " + e.toString(), e);
}
}
}
void loadInitialContent(@NotNull List<ContentFolder> contentFolders, @NotNull ValidatorContext context)
throws MojoExecutionException {
for (ContentFolder contentFolder : contentFolders) {
if (contentFolder.getFolder() == null || !contentFolder.getFolder().isDirectory()
|| contentFolder.getPath() == null || contentFolder.getType() == null) {
throw new MojoExecutionException("Invalid initial content folder: " + contentFolder);
}
if (contentFolder.getType() == Type.VLT_XML) {
context.load(true).folderFileVaultXml(contentFolder.getFolder(), contentFolder.getPath());
} else {
context.load(true).folderJson(contentFolder.getFolder(), contentFolder.getPath());
}
}
}
class ValidatorContext extends SlingContextImpl implements AutoCloseable {
ValidatorContext() {
setResourceResolverType(ResourceResolverType.JCR_OAK);
super.setUp();
}
@Override
public void close() {
super.tearDown();
}
}
}