mirror of https://github.com/apache/nifi.git
NIFI-10915 Add additionalDetails content to runtime manifest
- Update manifests assembly to include the additionaDetails.html files - Update C2 ExtensionDefinition to add a new field for additional details content - Update manifest generation to read the additional details and pass through to C2 runtime manifest - Switch to boolean to indicate presence of additional details, instead of including content Add additionalDetails files to nifi-runtime-manifest artifact, organized by group/artifact/version/type Signed-off-by: Matthew Burgess <mattyb149@apache.org> This closes #6767
This commit is contained in:
parent
b744fac479
commit
334c9db9c3
|
@ -47,6 +47,8 @@ public class ExtensionComponent extends DefinedType {
|
||||||
|
|
||||||
private Stateful stateful;
|
private Stateful stateful;
|
||||||
|
|
||||||
|
private boolean additionalDetails;
|
||||||
|
|
||||||
@ApiModelProperty("The build metadata for this component")
|
@ApiModelProperty("The build metadata for this component")
|
||||||
public BuildInfo getBuildInfo() {
|
public BuildInfo getBuildInfo() {
|
||||||
return buildInfo;
|
return buildInfo;
|
||||||
|
@ -120,6 +122,7 @@ public class ExtensionComponent extends DefinedType {
|
||||||
this.explicitRestrictions = explicitRestrictions;
|
this.explicitRestrictions = explicitRestrictions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiModelProperty("Indicates if the component stores state")
|
||||||
public Stateful getStateful() {
|
public Stateful getStateful() {
|
||||||
return stateful;
|
return stateful;
|
||||||
}
|
}
|
||||||
|
@ -128,6 +131,15 @@ public class ExtensionComponent extends DefinedType {
|
||||||
this.stateful = stateful;
|
this.stateful = stateful;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiModelProperty("Indicates if the component has additional details documentation")
|
||||||
|
public boolean isAdditionalDetails() {
|
||||||
|
return additionalDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdditionalDetails(boolean additionalDetails) {
|
||||||
|
this.additionalDetails = additionalDetails;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
|
|
|
@ -32,16 +32,13 @@ language governing permissions and limitations under the License. -->
|
||||||
<phase>generate-resources</phase>
|
<phase>generate-resources</phase>
|
||||||
<configuration>
|
<configuration>
|
||||||
<includeTypes>nar</includeTypes>
|
<includeTypes>nar</includeTypes>
|
||||||
<includes>**/extension-manifest.xml</includes>
|
<includes>**/docs/**</includes>
|
||||||
<excludeTransitive>false</excludeTransitive>
|
<excludeTransitive>false</excludeTransitive>
|
||||||
<outputDirectory>${project.build.directory}/extension-manifests</outputDirectory>
|
<outputDirectory>${project.build.directory}/extension-manifests</outputDirectory>
|
||||||
<useSubDirectoryPerArtifact>true</useSubDirectoryPerArtifact>
|
<useSubDirectoryPerArtifact>true</useSubDirectoryPerArtifact>
|
||||||
<stripClassifier>true</stripClassifier>
|
<stripClassifier>true</stripClassifier>
|
||||||
<stripVersion>true</stripVersion>
|
<stripVersion>true</stripVersion>
|
||||||
<silent>true</silent>
|
<silent>true</silent>
|
||||||
<fileMappers>
|
|
||||||
<org.codehaus.plexus.components.io.filemappers.FlattenFileMapper />
|
|
||||||
</fileMappers>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* 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.nifi.runtime.manifest;
|
||||||
|
|
||||||
|
import org.apache.nifi.extension.manifest.ExtensionManifest;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class ExtensionManifestContainer {
|
||||||
|
|
||||||
|
private final ExtensionManifest manifest;
|
||||||
|
private final Map<String, String> additionalDetails;
|
||||||
|
|
||||||
|
public ExtensionManifestContainer(final ExtensionManifest manifest) {
|
||||||
|
this(manifest, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtensionManifestContainer(final ExtensionManifest manifest, final Map<String, String> additionalDetails) {
|
||||||
|
this.manifest = Objects.requireNonNull(manifest);
|
||||||
|
this.additionalDetails = Collections.unmodifiableMap(additionalDetails == null
|
||||||
|
? Collections.emptyMap() : new LinkedHashMap<>(additionalDetails));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtensionManifest getManifest() {
|
||||||
|
return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getAdditionalDetails() {
|
||||||
|
return additionalDetails;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,8 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.runtime.manifest;
|
package org.apache.nifi.runtime.manifest;
|
||||||
|
|
||||||
import org.apache.nifi.extension.manifest.ExtensionManifest;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +23,6 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public interface ExtensionManifestProvider {
|
public interface ExtensionManifestProvider {
|
||||||
|
|
||||||
List<ExtensionManifest> getExtensionManifests();
|
List<ExtensionManifestContainer> getExtensionManifests();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import org.apache.nifi.c2.protocol.component.api.BuildInfo;
|
||||||
import org.apache.nifi.c2.protocol.component.api.Bundle;
|
import org.apache.nifi.c2.protocol.component.api.Bundle;
|
||||||
import org.apache.nifi.c2.protocol.component.api.RuntimeManifest;
|
import org.apache.nifi.c2.protocol.component.api.RuntimeManifest;
|
||||||
import org.apache.nifi.c2.protocol.component.api.SchedulingDefaults;
|
import org.apache.nifi.c2.protocol.component.api.SchedulingDefaults;
|
||||||
import org.apache.nifi.extension.manifest.ExtensionManifest;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for creating a RuntimeManifest.
|
* Builder for creating a RuntimeManifest.
|
||||||
|
@ -57,7 +56,7 @@ public interface RuntimeManifestBuilder {
|
||||||
* @param extensionManifest the extension manifest to add
|
* @param extensionManifest the extension manifest to add
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
RuntimeManifestBuilder addBundle(ExtensionManifest extensionManifest);
|
RuntimeManifestBuilder addBundle(ExtensionManifestContainer extensionManifest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a Bundle for each of the given ExtensionManifests.
|
* Adds a Bundle for each of the given ExtensionManifests.
|
||||||
|
@ -65,7 +64,7 @@ public interface RuntimeManifestBuilder {
|
||||||
* @param extensionManifests the extension manifests to add
|
* @param extensionManifests the extension manifests to add
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
RuntimeManifestBuilder addBundles(Iterable<ExtensionManifest> extensionManifests);
|
RuntimeManifestBuilder addBundles(Iterable<ExtensionManifestContainer> extensionManifests);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given Bundle.
|
* Adds the given Bundle.
|
||||||
|
|
|
@ -16,8 +16,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.runtime.manifest.impl;
|
package org.apache.nifi.runtime.manifest.impl;
|
||||||
|
|
||||||
import org.apache.nifi.extension.manifest.parser.ExtensionManifestParser;
|
|
||||||
import org.apache.nifi.extension.manifest.ExtensionManifest;
|
import org.apache.nifi.extension.manifest.ExtensionManifest;
|
||||||
|
import org.apache.nifi.extension.manifest.parser.ExtensionManifestParser;
|
||||||
|
import org.apache.nifi.runtime.manifest.ExtensionManifestContainer;
|
||||||
import org.apache.nifi.runtime.manifest.ExtensionManifestProvider;
|
import org.apache.nifi.runtime.manifest.ExtensionManifestProvider;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -26,8 +27,12 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExtensionManifestProvider that loads extension manifests from a directory where the nifi-assembly-manifests
|
* ExtensionManifestProvider that loads extension manifests from a directory where the nifi-assembly-manifests
|
||||||
|
@ -46,7 +51,7 @@ public class DirectoryExtensionManifestProvider implements ExtensionManifestProv
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ExtensionManifest> getExtensionManifests() {
|
public List<ExtensionManifestContainer> getExtensionManifests() {
|
||||||
if (!baseDir.exists()) {
|
if (!baseDir.exists()) {
|
||||||
throw new IllegalArgumentException("The specified manifest directory does not exist");
|
throw new IllegalArgumentException("The specified manifest directory does not exist");
|
||||||
}
|
}
|
||||||
|
@ -56,18 +61,22 @@ public class DirectoryExtensionManifestProvider implements ExtensionManifestProv
|
||||||
|
|
||||||
LOGGER.info("Loading extension manifests from: {}", baseDir.getAbsolutePath());
|
LOGGER.info("Loading extension manifests from: {}", baseDir.getAbsolutePath());
|
||||||
|
|
||||||
final List<ExtensionManifest> extensionManifests = new ArrayList<>();
|
final List<ExtensionManifestContainer> extensionManifests = new ArrayList<>();
|
||||||
for (final File manifestDir : baseDir.listFiles()) {
|
for (final File manifestDir : baseDir.listFiles()) {
|
||||||
if (!manifestDir.isDirectory()) {
|
if (!manifestDir.isDirectory()) {
|
||||||
LOGGER.debug("Skipping [{}], not a directory...", manifestDir.getAbsolutePath());
|
LOGGER.debug("Skipping [{}], not a directory...", manifestDir.getAbsolutePath());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final File manifestFile = new File(manifestDir, "extension-manifest.xml");
|
final File manifestFile = new File(manifestDir, "META-INF/docs/extension-manifest.xml");
|
||||||
LOGGER.debug("Loading extension manifest file [{}]", manifestFile.getAbsolutePath());
|
LOGGER.debug("Loading extension manifest file [{}]", manifestFile.getAbsolutePath());
|
||||||
|
|
||||||
final ExtensionManifest extensionManifest = loadExtensionManifest(manifestFile);
|
final ExtensionManifest extensionManifest = loadExtensionManifest(manifestFile);
|
||||||
extensionManifests.add(extensionManifest);
|
final Map<String, String> additionalDetails = loadAdditionalDetails(manifestDir);
|
||||||
|
|
||||||
|
final ExtensionManifestContainer container = new ExtensionManifestContainer(extensionManifest, additionalDetails);
|
||||||
|
extensionManifests.add(container);
|
||||||
|
|
||||||
LOGGER.debug("Successfully loaded extension manifest for [{}-{}-{}]",
|
LOGGER.debug("Successfully loaded extension manifest for [{}-{}-{}]",
|
||||||
extensionManifest.getGroupId(), extensionManifest.getArtifactId(), extensionManifest.getVersion());
|
extensionManifest.getGroupId(), extensionManifest.getArtifactId(), extensionManifest.getVersion());
|
||||||
}
|
}
|
||||||
|
@ -83,4 +92,40 @@ public class DirectoryExtensionManifestProvider implements ExtensionManifestProv
|
||||||
throw new RuntimeException("Unable to load extension manifest: " + manifestFile.getAbsolutePath(), ioException);
|
throw new RuntimeException("Unable to load extension manifest: " + manifestFile.getAbsolutePath(), ioException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, String> loadAdditionalDetails(final File manifestDir) {
|
||||||
|
final Map<String, String> additionalDetailsMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
final File additionalDetailsDir = new File(manifestDir, "META-INF/docs/additional-details");
|
||||||
|
if (!additionalDetailsDir.exists()) {
|
||||||
|
LOGGER.debug("No additional-details directory found under [{}]", manifestDir.getAbsolutePath());
|
||||||
|
return additionalDetailsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final File additionalDetailsTypeDir : additionalDetailsDir.listFiles()) {
|
||||||
|
if (!additionalDetailsTypeDir.isDirectory()) {
|
||||||
|
LOGGER.debug("Skipping [{}], not a directory...", additionalDetailsTypeDir.getAbsolutePath());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final File additionalDetailsFile = new File(additionalDetailsTypeDir, "additionalDetails.html");
|
||||||
|
if (!additionalDetailsFile.exists()) {
|
||||||
|
LOGGER.debug("No additionalDetails.html found under [{}]", additionalDetailsTypeDir.getAbsolutePath());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String typeName = additionalDetailsTypeDir.getName();
|
||||||
|
final byte[] additionalDetailsBytes = Files.readAllBytes(additionalDetailsFile.toPath());
|
||||||
|
LOGGER.debug("Added additionalDetails for {} from {}", typeName, additionalDetailsFile.getAbsolutePath());
|
||||||
|
additionalDetailsMap.put(typeName, new String(additionalDetailsBytes, StandardCharsets.UTF_8));
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new RuntimeException("Unable to load additional details content for "
|
||||||
|
+ additionalDetailsFile.getAbsolutePath() + " due to: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return additionalDetailsMap;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
import org.apache.nifi.c2.protocol.component.api.BuildInfo;
|
import org.apache.nifi.c2.protocol.component.api.BuildInfo;
|
||||||
import org.apache.nifi.c2.protocol.component.api.RuntimeManifest;
|
import org.apache.nifi.c2.protocol.component.api.RuntimeManifest;
|
||||||
|
import org.apache.nifi.extension.manifest.Extension;
|
||||||
|
import org.apache.nifi.extension.manifest.ExtensionManifest;
|
||||||
import org.apache.nifi.extension.manifest.parser.ExtensionManifestParser;
|
import org.apache.nifi.extension.manifest.parser.ExtensionManifestParser;
|
||||||
import org.apache.nifi.extension.manifest.parser.jaxb.JAXBExtensionManifestParser;
|
import org.apache.nifi.extension.manifest.parser.jaxb.JAXBExtensionManifestParser;
|
||||||
|
import org.apache.nifi.runtime.manifest.ExtensionManifestContainer;
|
||||||
import org.apache.nifi.runtime.manifest.ExtensionManifestProvider;
|
import org.apache.nifi.runtime.manifest.ExtensionManifestProvider;
|
||||||
import org.apache.nifi.runtime.manifest.RuntimeManifestSerializer;
|
import org.apache.nifi.runtime.manifest.RuntimeManifestSerializer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -34,8 +37,12 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,12 +100,14 @@ public class RuntimeManifestGenerator {
|
||||||
buildInfo.setTimestamp(buildTimestampMillis);
|
buildInfo.setTimestamp(buildTimestampMillis);
|
||||||
buildInfo.setCompiler(buildJdkVendor + " " + buildJdk);
|
buildInfo.setCompiler(buildJdkVendor + " " + buildJdk);
|
||||||
|
|
||||||
|
final List<ExtensionManifestContainer> extensionsManifests = extensionManifestProvider.getExtensionManifests();
|
||||||
|
|
||||||
final RuntimeManifest runtimeManifest = new StandardRuntimeManifestBuilder()
|
final RuntimeManifest runtimeManifest = new StandardRuntimeManifestBuilder()
|
||||||
.identifier(runtimeManifestId)
|
.identifier(runtimeManifestId)
|
||||||
.version(runtimeVersion)
|
.version(runtimeVersion)
|
||||||
.runtimeType("nifi")
|
.runtimeType("nifi")
|
||||||
.buildInfo(buildInfo)
|
.buildInfo(buildInfo)
|
||||||
.addBundles(extensionManifestProvider.getExtensionManifests())
|
.addBundles(extensionsManifests)
|
||||||
.schedulingDefaults(SchedulingDefaultsFactory.getNifiSchedulingDefaults())
|
.schedulingDefaults(SchedulingDefaultsFactory.getNifiSchedulingDefaults())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -106,6 +115,30 @@ public class RuntimeManifestGenerator {
|
||||||
try (final OutputStream outputStream = new FileOutputStream(runtimeManifestFile)) {
|
try (final OutputStream outputStream = new FileOutputStream(runtimeManifestFile)) {
|
||||||
runtimeManifestSerializer.write(runtimeManifest, outputStream);
|
runtimeManifestSerializer.write(runtimeManifest, outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final File docsDir = new File(runtimeManifestFile.getParent(), "docs");
|
||||||
|
docsDir.mkdirs();
|
||||||
|
|
||||||
|
for (final ExtensionManifestContainer manifestContainer : extensionsManifests) {
|
||||||
|
final ExtensionManifest extensionManifest = manifestContainer.getManifest();
|
||||||
|
final Map<String, String> additionalDetailsMap = manifestContainer.getAdditionalDetails();
|
||||||
|
|
||||||
|
final File bundleDir = new File(docsDir, extensionManifest.getGroupId()
|
||||||
|
+ "/" + extensionManifest.getArtifactId()
|
||||||
|
+ "/" + extensionManifest.getVersion());
|
||||||
|
|
||||||
|
for (final Extension extension : extensionManifest.getExtensions()) {
|
||||||
|
final String extensionType = extension.getName();
|
||||||
|
final File extensionDir = new File(bundleDir, extensionType);
|
||||||
|
|
||||||
|
final String additionalDetails = additionalDetailsMap.get(extensionType);
|
||||||
|
if (additionalDetails != null) {
|
||||||
|
extensionDir.mkdirs();
|
||||||
|
final File additionalDetailsFile = new File(extensionDir, "additionalDetails.html");
|
||||||
|
Files.write(additionalDetailsFile.toPath(), additionalDetails.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExtensionManifestProvider createExtensionManifestProvider() {
|
private ExtensionManifestProvider createExtensionManifestProvider() {
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.apache.nifi.extension.manifest.Restricted;
|
||||||
import org.apache.nifi.extension.manifest.Stateful;
|
import org.apache.nifi.extension.manifest.Stateful;
|
||||||
import org.apache.nifi.logging.LogLevel;
|
import org.apache.nifi.logging.LogLevel;
|
||||||
import org.apache.nifi.runtime.manifest.ComponentManifestBuilder;
|
import org.apache.nifi.runtime.manifest.ComponentManifestBuilder;
|
||||||
|
import org.apache.nifi.runtime.manifest.ExtensionManifestContainer;
|
||||||
import org.apache.nifi.runtime.manifest.RuntimeManifestBuilder;
|
import org.apache.nifi.runtime.manifest.RuntimeManifestBuilder;
|
||||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||||
|
|
||||||
|
@ -105,7 +106,12 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RuntimeManifestBuilder addBundle(final ExtensionManifest extensionManifest) {
|
public RuntimeManifestBuilder addBundle(final ExtensionManifestContainer extensionManifestContainer) {
|
||||||
|
if (extensionManifestContainer == null) {
|
||||||
|
throw new IllegalArgumentException("Extension manifest container is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
final ExtensionManifest extensionManifest = extensionManifestContainer.getManifest();
|
||||||
if (extensionManifest == null) {
|
if (extensionManifest == null) {
|
||||||
throw new IllegalArgumentException("Extension manifest is required");
|
throw new IllegalArgumentException("Extension manifest is required");
|
||||||
}
|
}
|
||||||
|
@ -125,8 +131,12 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
|
||||||
bundle.setVersion(extensionManifest.getVersion());
|
bundle.setVersion(extensionManifest.getVersion());
|
||||||
|
|
||||||
if (extensionManifest.getExtensions() != null) {
|
if (extensionManifest.getExtensions() != null) {
|
||||||
|
final Map<String, String> additionalDetailsMap = extensionManifestContainer.getAdditionalDetails();
|
||||||
final ComponentManifestBuilder componentManifestBuilder = new StandardComponentManifestBuilder();
|
final ComponentManifestBuilder componentManifestBuilder = new StandardComponentManifestBuilder();
|
||||||
extensionManifest.getExtensions().forEach(extension -> addExtension(extensionManifest, extension, componentManifestBuilder));
|
extensionManifest.getExtensions().forEach(extension -> {
|
||||||
|
final String additionalDetails = additionalDetailsMap.get(extension.getName());
|
||||||
|
addExtension(extensionManifest, extension, additionalDetails, componentManifestBuilder);
|
||||||
|
});
|
||||||
bundle.setComponentManifest(componentManifestBuilder.build());
|
bundle.setComponentManifest(componentManifestBuilder.build());
|
||||||
}
|
}
|
||||||
bundles.add(bundle);
|
bundles.add(bundle);
|
||||||
|
@ -135,7 +145,7 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RuntimeManifestBuilder addBundles(final Iterable<ExtensionManifest> extensionManifests) {
|
public RuntimeManifestBuilder addBundles(final Iterable<ExtensionManifestContainer> extensionManifests) {
|
||||||
extensionManifests.forEach(em -> addBundle(em));
|
extensionManifests.forEach(em -> addBundle(em));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -167,30 +177,32 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
|
||||||
return runtimeManifest;
|
return runtimeManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addExtension(final ExtensionManifest extensionManifest, final Extension extension, final ComponentManifestBuilder componentManifestBuilder) {
|
private void addExtension(final ExtensionManifest extensionManifest, final Extension extension, final String additionalDetails,
|
||||||
|
final ComponentManifestBuilder componentManifestBuilder) {
|
||||||
if (extension == null) {
|
if (extension == null) {
|
||||||
throw new IllegalArgumentException("Extension cannot be null");
|
throw new IllegalArgumentException("Extension cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(extension.getType()) {
|
switch(extension.getType()) {
|
||||||
case PROCESSOR:
|
case PROCESSOR:
|
||||||
addProcessorDefinition(extensionManifest, extension, componentManifestBuilder);
|
addProcessorDefinition(extensionManifest, extension, additionalDetails, componentManifestBuilder);
|
||||||
break;
|
break;
|
||||||
case CONTROLLER_SERVICE:
|
case CONTROLLER_SERVICE:
|
||||||
addControllerServiceDefinition(extensionManifest, extension, componentManifestBuilder);
|
addControllerServiceDefinition(extensionManifest, extension, additionalDetails, componentManifestBuilder);
|
||||||
break;
|
break;
|
||||||
case REPORTING_TASK:
|
case REPORTING_TASK:
|
||||||
addReportingTaskDefinition(extensionManifest, extension, componentManifestBuilder);
|
addReportingTaskDefinition(extensionManifest, extension, additionalDetails, componentManifestBuilder);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown extension type: " + extension.getType());
|
throw new IllegalArgumentException("Unknown extension type: " + extension.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addProcessorDefinition(final ExtensionManifest extensionManifest, final Extension extension, final ComponentManifestBuilder componentManifestBuilder) {
|
private void addProcessorDefinition(final ExtensionManifest extensionManifest, final Extension extension, final String additionalDetails,
|
||||||
|
final ComponentManifestBuilder componentManifestBuilder) {
|
||||||
final ProcessorDefinition processorDefinition = new ProcessorDefinition();
|
final ProcessorDefinition processorDefinition = new ProcessorDefinition();
|
||||||
populateDefinedType(extensionManifest, extension, processorDefinition);
|
populateDefinedType(extensionManifest, extension, processorDefinition);
|
||||||
populateExtensionComponent(extensionManifest, extension, processorDefinition);
|
populateExtensionComponent(extensionManifest, extension, additionalDetails, processorDefinition);
|
||||||
populateConfigurableComponent(extension, processorDefinition);
|
populateConfigurableComponent(extension, processorDefinition);
|
||||||
|
|
||||||
// processor specific fields
|
// processor specific fields
|
||||||
|
@ -279,18 +291,20 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
|
||||||
return componentRelationships;
|
return componentRelationships;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addControllerServiceDefinition(final ExtensionManifest extensionManifest, final Extension extension, final ComponentManifestBuilder componentManifestBuilder) {
|
private void addControllerServiceDefinition(final ExtensionManifest extensionManifest, final Extension extension, final String additionalDetails,
|
||||||
|
final ComponentManifestBuilder componentManifestBuilder) {
|
||||||
final ControllerServiceDefinition controllerServiceDefinition = new ControllerServiceDefinition();
|
final ControllerServiceDefinition controllerServiceDefinition = new ControllerServiceDefinition();
|
||||||
populateDefinedType(extensionManifest, extension, controllerServiceDefinition);
|
populateDefinedType(extensionManifest, extension, controllerServiceDefinition);
|
||||||
populateExtensionComponent(extensionManifest, extension, controllerServiceDefinition);
|
populateExtensionComponent(extensionManifest, extension, additionalDetails, controllerServiceDefinition);
|
||||||
populateConfigurableComponent(extension, controllerServiceDefinition);
|
populateConfigurableComponent(extension, controllerServiceDefinition);
|
||||||
componentManifestBuilder.addControllerService(controllerServiceDefinition);
|
componentManifestBuilder.addControllerService(controllerServiceDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addReportingTaskDefinition(final ExtensionManifest extensionManifest, final Extension extension, final ComponentManifestBuilder componentManifestBuilder) {
|
private void addReportingTaskDefinition(final ExtensionManifest extensionManifest, final Extension extension, final String additionalDetails,
|
||||||
|
final ComponentManifestBuilder componentManifestBuilder) {
|
||||||
final ReportingTaskDefinition reportingTaskDefinition = new ReportingTaskDefinition();
|
final ReportingTaskDefinition reportingTaskDefinition = new ReportingTaskDefinition();
|
||||||
populateDefinedType(extensionManifest, extension, reportingTaskDefinition);
|
populateDefinedType(extensionManifest, extension, reportingTaskDefinition);
|
||||||
populateDefinedType(extensionManifest, extension, reportingTaskDefinition);
|
populateExtensionComponent(extensionManifest, extension, additionalDetails, reportingTaskDefinition);
|
||||||
populateConfigurableComponent(extension, reportingTaskDefinition);
|
populateConfigurableComponent(extension, reportingTaskDefinition);
|
||||||
|
|
||||||
final List<String> schedulingStrategies = new ArrayList<>();
|
final List<String> schedulingStrategies = new ArrayList<>();
|
||||||
|
@ -326,7 +340,8 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
|
||||||
definedType.setVersion(extensionManifest.getVersion());
|
definedType.setVersion(extensionManifest.getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateExtensionComponent(final ExtensionManifest extensionManifest, final Extension extension, final ExtensionComponent extensionComponent) {
|
private void populateExtensionComponent(final ExtensionManifest extensionManifest, final Extension extension, final String additionalDetails,
|
||||||
|
final ExtensionComponent extensionComponent) {
|
||||||
final org.apache.nifi.extension.manifest.BuildInfo buildInfo = extensionManifest.getBuildInfo();
|
final org.apache.nifi.extension.manifest.BuildInfo buildInfo = extensionManifest.getBuildInfo();
|
||||||
if (buildInfo != null) {
|
if (buildInfo != null) {
|
||||||
final BuildInfo componentBuildInfo = new BuildInfo();
|
final BuildInfo componentBuildInfo = new BuildInfo();
|
||||||
|
@ -377,7 +392,10 @@ public class StandardRuntimeManifestBuilder implements RuntimeManifestBuilder {
|
||||||
);
|
);
|
||||||
extensionComponent.setStateful(componentStateful);
|
extensionComponent.setStateful(componentStateful);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (additionalDetails != null) {
|
||||||
|
extensionComponent.setAdditionalDetails(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ class TestRuntimeManifest {
|
||||||
assertFalse(listHdfsDefinition.getSupportsDynamicProperties());
|
assertFalse(listHdfsDefinition.getSupportsDynamicProperties());
|
||||||
assertFalse(listHdfsDefinition.getSupportsDynamicRelationships());
|
assertFalse(listHdfsDefinition.getSupportsDynamicRelationships());
|
||||||
assertEquals(InputRequirement.Requirement.INPUT_FORBIDDEN, listHdfsDefinition.getInputRequirement());
|
assertEquals(InputRequirement.Requirement.INPUT_FORBIDDEN, listHdfsDefinition.getInputRequirement());
|
||||||
|
assertTrue(listHdfsDefinition.isAdditionalDetails());
|
||||||
|
|
||||||
assertEquals("30 sec", listHdfsDefinition.getDefaultPenaltyDuration());
|
assertEquals("30 sec", listHdfsDefinition.getDefaultPenaltyDuration());
|
||||||
assertEquals("1 sec", listHdfsDefinition.getDefaultYieldDuration());
|
assertEquals("1 sec", listHdfsDefinition.getDefaultYieldDuration());
|
||||||
|
@ -159,6 +160,7 @@ class TestRuntimeManifest {
|
||||||
"org.apache.nifi.processors.hadoop.FetchHDFS");
|
"org.apache.nifi.processors.hadoop.FetchHDFS");
|
||||||
assertNotNull(fetchHdfsDefinition.isRestricted());
|
assertNotNull(fetchHdfsDefinition.isRestricted());
|
||||||
assertTrue(fetchHdfsDefinition.isRestricted());
|
assertTrue(fetchHdfsDefinition.isRestricted());
|
||||||
|
assertFalse(fetchHdfsDefinition.isAdditionalDetails());
|
||||||
|
|
||||||
final Set<Restriction> restrictions = fetchHdfsDefinition.getExplicitRestrictions();
|
final Set<Restriction> restrictions = fetchHdfsDefinition.getExplicitRestrictions();
|
||||||
assertNotNull(restrictions);
|
assertNotNull(restrictions);
|
||||||
|
@ -171,6 +173,7 @@ class TestRuntimeManifest {
|
||||||
// Verify ConsumeKafka_2_6 definition which has properties with dependencies
|
// Verify ConsumeKafka_2_6 definition which has properties with dependencies
|
||||||
final ProcessorDefinition consumeKafkaDefinition = getProcessorDefinition(bundles, "nifi-kafka-2-6-nar",
|
final ProcessorDefinition consumeKafkaDefinition = getProcessorDefinition(bundles, "nifi-kafka-2-6-nar",
|
||||||
"org.apache.nifi.processors.kafka.pubsub.ConsumeKafka_2_6");
|
"org.apache.nifi.processors.kafka.pubsub.ConsumeKafka_2_6");
|
||||||
|
assertTrue(consumeKafkaDefinition.isAdditionalDetails());
|
||||||
|
|
||||||
final PropertyDescriptor maxUncommitProp = getPropertyDescriptor(consumeKafkaDefinition, "max-uncommit-offset-wait");
|
final PropertyDescriptor maxUncommitProp = getPropertyDescriptor(consumeKafkaDefinition, "max-uncommit-offset-wait");
|
||||||
final List<PropertyDependency> propertyDependencies = maxUncommitProp.getDependencies();
|
final List<PropertyDependency> propertyDependencies = maxUncommitProp.getDependencies();
|
||||||
|
|
|
@ -92,7 +92,6 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<includeArtifactIds>nifi-assembly</includeArtifactIds>
|
<includeArtifactIds>nifi-assembly</includeArtifactIds>
|
||||||
<includeClassifiers>manifests</includeClassifiers>
|
<includeClassifiers>manifests</includeClassifiers>
|
||||||
<includes>**/extension-manifest.xml</includes>
|
|
||||||
<excludeTransitive>true</excludeTransitive>
|
<excludeTransitive>true</excludeTransitive>
|
||||||
<outputDirectory>${extension.manifest.unpack.dir}</outputDirectory>
|
<outputDirectory>${extension.manifest.unpack.dir}</outputDirectory>
|
||||||
<silent>true</silent>
|
<silent>true</silent>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.nifi.extension.manifest.ExtensionManifest;
|
||||||
import org.apache.nifi.extension.manifest.parser.ExtensionManifestParser;
|
import org.apache.nifi.extension.manifest.parser.ExtensionManifestParser;
|
||||||
import org.apache.nifi.nar.ExtensionManager;
|
import org.apache.nifi.nar.ExtensionManager;
|
||||||
import org.apache.nifi.nar.NarClassLoadersHolder;
|
import org.apache.nifi.nar.NarClassLoadersHolder;
|
||||||
|
import org.apache.nifi.runtime.manifest.ExtensionManifestContainer;
|
||||||
import org.apache.nifi.runtime.manifest.RuntimeManifestBuilder;
|
import org.apache.nifi.runtime.manifest.RuntimeManifestBuilder;
|
||||||
import org.apache.nifi.runtime.manifest.impl.SchedulingDefaultsFactory;
|
import org.apache.nifi.runtime.manifest.impl.SchedulingDefaultsFactory;
|
||||||
import org.apache.nifi.runtime.manifest.impl.StandardRuntimeManifestBuilder;
|
import org.apache.nifi.runtime.manifest.impl.StandardRuntimeManifestBuilder;
|
||||||
|
@ -32,11 +33,16 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class StandardRuntimeManifestService implements RuntimeManifestService {
|
public class StandardRuntimeManifestService implements RuntimeManifestService {
|
||||||
|
|
||||||
|
@ -90,12 +96,25 @@ public class StandardRuntimeManifestService implements RuntimeManifestService {
|
||||||
return manifestBuilder.build();
|
return manifestBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<ExtensionManifest> getExtensionManifest(final Bundle bundle) {
|
private Optional<ExtensionManifestContainer> getExtensionManifest(final Bundle bundle) {
|
||||||
final BundleDetails bundleDetails = bundle.getBundleDetails();
|
final BundleDetails bundleDetails = bundle.getBundleDetails();
|
||||||
|
try {
|
||||||
|
final ExtensionManifest extensionManifest = loadExtensionManifest(bundleDetails);
|
||||||
|
final Map<String, String> additionalDetails = loadAdditionalDetails(bundleDetails);
|
||||||
|
|
||||||
|
final ExtensionManifestContainer container = new ExtensionManifestContainer(extensionManifest, additionalDetails);
|
||||||
|
return Optional.of(container);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
LOGGER.error("Unable to load extension manifest for bundle [{}]", bundleDetails.getCoordinate(), e);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExtensionManifest loadExtensionManifest(final BundleDetails bundleDetails) throws IOException {
|
||||||
final File manifestFile = new File(bundleDetails.getWorkingDirectory(), "META-INF/docs/extension-manifest.xml");
|
final File manifestFile = new File(bundleDetails.getWorkingDirectory(), "META-INF/docs/extension-manifest.xml");
|
||||||
if (!manifestFile.exists()) {
|
if (!manifestFile.exists()) {
|
||||||
LOGGER.warn("Unable to find extension manifest for [{}] at [{}]...", bundleDetails.getCoordinate(), manifestFile.getAbsolutePath());
|
throw new FileNotFoundException("Extension manifest files does not exist for "
|
||||||
return Optional.empty();
|
+ bundleDetails.getCoordinate() + " at " + manifestFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
try (final InputStream inputStream = new FileInputStream(manifestFile)) {
|
try (final InputStream inputStream = new FileInputStream(manifestFile)) {
|
||||||
|
@ -105,13 +124,45 @@ public class StandardRuntimeManifestService implements RuntimeManifestService {
|
||||||
extensionManifest.setGroupId(bundleDetails.getCoordinate().getGroup());
|
extensionManifest.setGroupId(bundleDetails.getCoordinate().getGroup());
|
||||||
extensionManifest.setArtifactId(bundleDetails.getCoordinate().getId());
|
extensionManifest.setArtifactId(bundleDetails.getCoordinate().getId());
|
||||||
extensionManifest.setVersion(bundleDetails.getCoordinate().getVersion());
|
extensionManifest.setVersion(bundleDetails.getCoordinate().getVersion());
|
||||||
return Optional.of(extensionManifest);
|
return extensionManifest;
|
||||||
} catch (final IOException e) {
|
|
||||||
LOGGER.error("Unable to load extension manifest for bundle [{}]", bundleDetails.getCoordinate(), e);
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, String> loadAdditionalDetails(final BundleDetails bundleDetails) {
|
||||||
|
final Map<String, String> additionalDetailsMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
final File additionalDetailsDir = new File(bundleDetails.getWorkingDirectory(), "META-INF/docs/additional-details");
|
||||||
|
if (!additionalDetailsDir.exists()) {
|
||||||
|
LOGGER.debug("No additional-details directory found under [{}]", bundleDetails.getWorkingDirectory().getAbsolutePath());
|
||||||
|
return additionalDetailsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final File additionalDetailsTypeDir : additionalDetailsDir.listFiles()) {
|
||||||
|
if (!additionalDetailsTypeDir.isDirectory()) {
|
||||||
|
LOGGER.debug("Skipping [{}], not a directory...", additionalDetailsTypeDir.getAbsolutePath());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final File additionalDetailsFile = new File(additionalDetailsTypeDir, "additionalDetails.html");
|
||||||
|
if (!additionalDetailsFile.exists()) {
|
||||||
|
LOGGER.debug("No additionalDetails.html found under [{}]", additionalDetailsTypeDir.getAbsolutePath());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String typeName = additionalDetailsTypeDir.getName();
|
||||||
|
final String additionalDetailsContent = Files.lines(additionalDetailsFile.toPath()).collect(Collectors.joining());
|
||||||
|
LOGGER.debug("Added additionalDetails for {} from {}", typeName, additionalDetailsFile.getAbsolutePath());
|
||||||
|
additionalDetailsMap.put(typeName, additionalDetailsContent);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new RuntimeException("Unable to load additional details content for "
|
||||||
|
+ additionalDetailsFile.getAbsolutePath() + " due to: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return additionalDetailsMap;
|
||||||
|
}
|
||||||
|
|
||||||
// Visible for overriding from tests
|
// Visible for overriding from tests
|
||||||
Bundle getFrameworkBundle() {
|
Bundle getFrameworkBundle() {
|
||||||
return NarClassLoadersHolder.getInstance().getFrameworkBundle();
|
return NarClassLoadersHolder.getInstance().getFrameworkBundle();
|
||||||
|
|
Loading…
Reference in New Issue