NIFI-5859: Added XML-based documentation writer that can be used to document a component.

- Found several instances of nifi-framework-api's ProviderException being thrown from processors. Changed those to IllegalStateException, as ProviderException is not an appropriate Exception in those cases, and extensions should not depend on nifi-framework-api.
- Performed some cleanup, moving Property Descriptors from Controller Service API's/specs into the implementations. Adding to the Service API results in bringing in nifi-utils to the nifi-standard-services-api-nar, which is a bad practice. The 'main' service api nar should not have a dependency on a util class.

NIFI-5859: Added javadocs. Fixed pom.xml that was left pointing to snapshot version of nar maven plugin

NIFI-5859: Addressing review feedback: adding component type, multiple additional details into separate file(s)

This closes #3192.

Signed-off-by: Bryan Bende <bbende@apache.org>
This commit is contained in:
Mark Payne 2018-11-15 12:07:08 -05:00 committed by Bryan Bende
parent 4e7a856f77
commit 1ac5b93144
No known key found for this signature in database
GPG Key ID: A0DDA9ED50711C39
32 changed files with 1510 additions and 141 deletions

View File

@ -0,0 +1,285 @@
/*
* 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.documentation;
import org.apache.nifi.annotation.behavior.DynamicProperties;
import org.apache.nifi.annotation.behavior.DynamicProperty;
import org.apache.nifi.annotation.behavior.DynamicRelationship;
import org.apache.nifi.annotation.behavior.InputRequirement;
import org.apache.nifi.annotation.behavior.ReadsAttribute;
import org.apache.nifi.annotation.behavior.ReadsAttributes;
import org.apache.nifi.annotation.behavior.Restricted;
import org.apache.nifi.annotation.behavior.Stateful;
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
import org.apache.nifi.annotation.behavior.WritesAttribute;
import org.apache.nifi.annotation.behavior.WritesAttributes;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.DeprecationNotice;
import org.apache.nifi.annotation.documentation.SeeAlso;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.documentation.init.DocumentationControllerServiceInitializationContext;
import org.apache.nifi.documentation.init.DocumentationProcessorInitializationContext;
import org.apache.nifi.documentation.init.DocumentationReportingInitializationContext;
import org.apache.nifi.processor.Processor;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.reporting.ReportingTask;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* Base class for DocumentationWriter that simplifies iterating over all information for a component, creating a separate method
* for each, to ensure that implementations properly override all methods and therefore properly account for all information about
* a component.
*
* Please note that while this class lives within the nifi-api, it is provided primarily as a means for documentation components within
* the NiFi NAR Maven Plugin. Its home is the nifi-api, however, because the API is needed in order to extract the relevant information and
* the NAR Maven Plugin cannot have a direct dependency on nifi-api (doing so would cause a circular dependency). By having this homed within
* the nifi-api, the Maven plugin is able to discover the class dynamically and invoke the one or two methods necessary to create the documentation.
*
* This is a new capability in 1.9.0 in preparation for the Extension Registry and therefore, you should
* <b>NOTE WELL:</b> At this time, while this class is part of nifi-api, it is still evolving and may change in a non-backward-compatible manner or even be
* removed from one incremental release to the next. Use at your own risk!
*/
public abstract class AbstractDocumentationWriter implements ExtensionDocumentationWriter {
@Override
public final void write(final ConfigurableComponent component) throws IOException {
write(component, null);
}
@Override
public final void write(final ConfigurableComponent component, final Collection<ProvidedServiceAPI> providedServices) throws IOException {
initialize(component);
writeHeader(component);
writeBody(component);
if (providedServices != null && component instanceof ControllerService) {
writeProvidedServices(providedServices);
}
writeFooter(component);
}
private void initialize(final ConfigurableComponent component) {
try {
if (component instanceof Processor) {
initialize((Processor) component);
} else if (component instanceof ControllerService) {
initialize((ControllerService) component);
} else if (component instanceof ReportingTask) {
initialize((ReportingTask) component);
}
} catch (final InitializationException ie) {
throw new RuntimeException("Failed to initialize " + component, ie);
}
}
protected void initialize(final Processor processor) {
processor.initialize(new DocumentationProcessorInitializationContext());
}
protected void initialize(final ControllerService service) throws InitializationException {
service.initialize(new DocumentationControllerServiceInitializationContext());
}
protected void initialize(final ReportingTask reportingTask) throws InitializationException {
reportingTask.initialize(new DocumentationReportingInitializationContext());
}
protected void writeBody(final ConfigurableComponent component) throws IOException {
writeExtensionName(component.getClass().getName());
writeExtensionType(getExtensionType(component));
writeDeprecationNotice(component.getClass().getAnnotation(DeprecationNotice.class));
writeDescription(getDescription(component));
writeTags(getTags(component));
writeProperties(component.getPropertyDescriptors());
writeDynamicProperties(getDynamicProperties(component));
if (component instanceof Processor) {
final Processor processor = (Processor) component;
writeRelationships(processor.getRelationships());
writeDynamicRelationship(getDynamicRelationship(processor));
writeReadsAttributes(getReadsAttributes(processor));
writeWritesAttributes(getWritesAttributes(processor));
}
writeStatefulInfo(component.getClass().getAnnotation(Stateful.class));
writeRestrictedInfo(component.getClass().getAnnotation(Restricted.class));
writeInputRequirementInfo(getInputRequirement(component));
writeSystemResourceConsiderationInfo(getSystemResourceConsiderations(component));
writeSeeAlso(component.getClass().getAnnotation(SeeAlso.class));
}
protected String getDescription(final ConfigurableComponent component) {
final CapabilityDescription capabilityDescription = component.getClass().getAnnotation(CapabilityDescription.class);
if (capabilityDescription == null) {
return null;
}
return capabilityDescription.value();
}
protected List<String> getTags(final ConfigurableComponent component) {
final Tags tags = component.getClass().getAnnotation(Tags.class);
if (tags == null) {
return Collections.emptyList();
}
final String[] tagValues = tags.value();
return tagValues == null ? Collections.emptyList() : Arrays.asList(tagValues);
}
protected List<DynamicProperty> getDynamicProperties(ConfigurableComponent configurableComponent) {
final List<DynamicProperty> dynamicProperties = new ArrayList<>();
final DynamicProperties dynProps = configurableComponent.getClass().getAnnotation(DynamicProperties.class);
if (dynProps != null) {
Collections.addAll(dynamicProperties, dynProps.value());
}
final DynamicProperty dynProp = configurableComponent.getClass().getAnnotation(DynamicProperty.class);
if (dynProp != null) {
dynamicProperties.add(dynProp);
}
return dynamicProperties;
}
private DynamicRelationship getDynamicRelationship(Processor processor) {
return processor.getClass().getAnnotation(DynamicRelationship.class);
}
private List<ReadsAttribute> getReadsAttributes(final Processor processor) {
final List<ReadsAttribute> attributes = new ArrayList<>();
final ReadsAttributes readsAttributes = processor.getClass().getAnnotation(ReadsAttributes.class);
if (readsAttributes != null) {
Collections.addAll(attributes, readsAttributes.value());
}
final ReadsAttribute readsAttribute = processor.getClass().getAnnotation(ReadsAttribute.class);
if (readsAttribute != null) {
attributes.add(readsAttribute);
}
return attributes;
}
private List<WritesAttribute> getWritesAttributes(Processor processor) {
List<WritesAttribute> attributes = new ArrayList<>();
WritesAttributes writesAttributes = processor.getClass().getAnnotation(WritesAttributes.class);
if (writesAttributes != null) {
Collections.addAll(attributes, writesAttributes.value());
}
WritesAttribute writeAttribute = processor.getClass().getAnnotation(WritesAttribute.class);
if (writeAttribute != null) {
attributes.add(writeAttribute);
}
return attributes;
}
private InputRequirement.Requirement getInputRequirement(final ConfigurableComponent component) {
final InputRequirement annotation = component.getClass().getAnnotation(InputRequirement.class);
return annotation == null ? null : annotation.value();
}
private List<SystemResourceConsideration> getSystemResourceConsiderations(final ConfigurableComponent component) {
SystemResourceConsideration[] systemResourceConsiderations = component.getClass().getAnnotationsByType(SystemResourceConsideration.class);
if (systemResourceConsiderations == null) {
return Collections.emptyList();
}
return Arrays.asList(systemResourceConsiderations);
}
protected ExtensionType getExtensionType(final ConfigurableComponent component) {
if (component instanceof Processor) {
return ExtensionType.PROCESSOR;
}
if (component instanceof ControllerService) {
return ExtensionType.CONTROLLER_SERVICE;
}
if (component instanceof ReportingTask) {
return ExtensionType.REPORTING_TASK;
}
throw new AssertionError("Encountered unknown Configurable Component Type for " + component);
}
protected abstract void writeHeader(ConfigurableComponent component) throws IOException;
protected abstract void writeExtensionName(String extensionName) throws IOException;
protected abstract void writeExtensionType(ExtensionType extensionType) throws IOException;
protected abstract void writeDeprecationNotice(final DeprecationNotice deprecationNotice) throws IOException;
protected abstract void writeDescription(String description) throws IOException;
protected abstract void writeTags(List<String> tags) throws IOException;
protected abstract void writeProperties(List<PropertyDescriptor> properties) throws IOException;
protected abstract void writeDynamicProperties(List<DynamicProperty> dynamicProperties) throws IOException;
protected abstract void writeStatefulInfo(Stateful stateful) throws IOException;
protected abstract void writeRestrictedInfo(Restricted restricted) throws IOException;
protected abstract void writeInputRequirementInfo(InputRequirement.Requirement requirement) throws IOException;
protected abstract void writeSystemResourceConsiderationInfo(List<SystemResourceConsideration> considerations) throws IOException;
protected abstract void writeSeeAlso(SeeAlso seeAlso) throws IOException;
// Processor-specific methods
protected abstract void writeRelationships(Set<Relationship> relationships) throws IOException;
protected abstract void writeDynamicRelationship(DynamicRelationship dynamicRelationship) throws IOException;
protected abstract void writeReadsAttributes(List<ReadsAttribute> attributes) throws IOException;
protected abstract void writeWritesAttributes(List<WritesAttribute> attributes) throws IOException;
// ControllerService-specific methods
protected abstract void writeProvidedServices(Collection<ProvidedServiceAPI> providedServices) throws IOException;
protected abstract void writeFooter(ConfigurableComponent component) throws IOException;
}

View File

@ -0,0 +1,42 @@
/*
* 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.documentation;
import org.apache.nifi.components.ConfigurableComponent;
import java.io.IOException;
import java.util.Collection;
/**
* Generates documentation for an instance of a ConfigurableComponent.
*
* Please note that while this class lives within the nifi-api, it is provided primarily as a means for documentation components within
* the NiFi NAR Maven Plugin. Its home is the nifi-api, however, because the API is needed in order to extract the relevant information and
* the NAR Maven Plugin cannot have a direct dependency on nifi-api (doing so would cause a circular dependency). By having this homed within
* the nifi-api, the Maven plugin is able to discover the class dynamically and invoke the one or two methods necessary to create the documentation.
*
* This is a new capability in 1.9.0 in preparation for the Extension Registry and therefore, you should
* <b>NOTE WELL:</b> At this time, while this class is part of nifi-api, it is still evolving and may change in a non-backward-compatible manner or even be
* removed from one incremental release to the next. Use at your own risk!
*/
public interface ExtensionDocumentationWriter {
void write(ConfigurableComponent component) throws IOException;
void write(ConfigurableComponent component, Collection<ProvidedServiceAPI> provideServices) throws IOException;
}

View File

@ -0,0 +1,25 @@
/*
* 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.documentation;
public enum ExtensionType {
PROCESSOR,
CONTROLLER_SERVICE,
REPORTING_TASK;
}

View File

@ -0,0 +1,51 @@
/*
* 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.documentation;
/**
* Describes a Controller Service API that is provided by some implementation.
*
* Please note that while this class lives within the nifi-api, it is provided primarily as a means for documentation components within
* the NiFi NAR Maven Plugin. Its home is the nifi-api, however, because the API is needed in order to extract the relevant information and
* the NAR Maven Plugin cannot have a direct dependency on nifi-api (doing so would cause a circular dependency). By having this homed within
* the nifi-api, the Maven plugin is able to discover the class dynamically and invoke the one or two methods necessary to create the documentation.
*
* This is a new capability in 1.9.0 in preparation for the Extension Registry and therefore, you should
* <b>NOTE WELL:</b> At this time, while this class is part of nifi-api, it is still evolving and may change in a non-backward-compatible manner or even be
* removed from one incremental release to the next. Use at your own risk!
*/
public interface ProvidedServiceAPI {
/**
* @return the fully qualified class name of the interface implemented by the Controller Service
*/
String getClassName();
/**
* @return the Group ID of the bundle that provides the interface
*/
String getGroupId();
/**
* @return the Artifact ID of the bundle that provides the interface
*/
String getArtifactId();
/**
* @return the Version of the bundle that provides the interface
*/
String getVersion();
}

View File

@ -0,0 +1,51 @@
/*
* 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.documentation;
public class StandardProvidedServiceAPI implements ProvidedServiceAPI {
private final String className;
private final String groupId;
private final String artifactId;
private final String version;
public StandardProvidedServiceAPI(final String className, final String groupId, final String artifactId, final String version) {
this.className = className;
this.groupId = groupId;
this.artifactId = artifactId;
this.version = version;
}
@Override
public String getClassName() {
return className;
}
@Override
public String getGroupId() {
return groupId;
}
@Override
public String getArtifactId() {
return artifactId;
}
@Override
public String getVersion() {
return version;
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.documentation.init;
import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.controller.ControllerServiceInitializationContext;
import org.apache.nifi.controller.ControllerServiceLookup;
import org.apache.nifi.logging.ComponentLog;
import java.io.File;
import java.util.UUID;
public class DocumentationControllerServiceInitializationContext implements ControllerServiceInitializationContext {
private final String id = UUID.randomUUID().toString();
private final ControllerServiceLookup serviceLookup = new EmptyControllerServiceLookup();
private final ComponentLog componentLog = new NopComponentLog();
@Override
public String getIdentifier() {
return id;
}
@Override
public ControllerServiceLookup getControllerServiceLookup() {
return serviceLookup;
}
@Override
public ComponentLog getLogger() {
return componentLog;
}
@Override
public StateManager getStateManager() {
return new NopStateManager();
}
@Override
public String getKerberosServicePrincipal() {
return null;
}
@Override
public File getKerberosServiceKeytab() {
return null;
}
@Override
public File getKerberosConfigurationFile() {
return null;
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.documentation.init;
import org.apache.nifi.controller.ControllerServiceLookup;
import org.apache.nifi.controller.NodeTypeProvider;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processor.ProcessorInitializationContext;
import java.io.File;
import java.util.UUID;
public class DocumentationProcessorInitializationContext implements ProcessorInitializationContext {
private final String uuid = UUID.randomUUID().toString();
private final NodeTypeProvider nodeTypeProvider = new StandaloneNodeTypeProvider();
@Override
public String getIdentifier() {
return uuid;
}
@Override
public ComponentLog getLogger() {
return new NopComponentLog();
}
@Override
public ControllerServiceLookup getControllerServiceLookup() {
return new EmptyControllerServiceLookup();
}
@Override
public NodeTypeProvider getNodeTypeProvider() {
return nodeTypeProvider;
}
@Override
public String getKerberosServicePrincipal() {
return null;
}
@Override
public File getKerberosServiceKeytab() {
return null;
}
@Override
public File getKerberosConfigurationFile() {
return null;
}
}

View File

@ -0,0 +1,89 @@
/*
* 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.documentation.init;
import org.apache.nifi.controller.ControllerServiceLookup;
import org.apache.nifi.controller.NodeTypeProvider;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.reporting.ReportingInitializationContext;
import org.apache.nifi.scheduling.SchedulingStrategy;
import java.io.File;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class DocumentationReportingInitializationContext implements ReportingInitializationContext {
private final String id = UUID.randomUUID().toString();
private final ComponentLog componentLog = new NopComponentLog();
private final NodeTypeProvider nodeTypeProvider = new StandaloneNodeTypeProvider();
private final String name = "name";
@Override
public String getIdentifier() {
return id;
}
@Override
public String getName() {
return name;
}
@Override
public long getSchedulingPeriod(final TimeUnit timeUnit) {
return 0;
}
@Override
public ControllerServiceLookup getControllerServiceLookup() {
return new EmptyControllerServiceLookup();
}
@Override
public String getSchedulingPeriod() {
return "0 sec";
}
@Override
public SchedulingStrategy getSchedulingStrategy() {
return SchedulingStrategy.TIMER_DRIVEN;
}
@Override
public ComponentLog getLogger() {
return componentLog;
}
@Override
public NodeTypeProvider getNodeTypeProvider() {
return nodeTypeProvider;
}
@Override
public String getKerberosServicePrincipal() {
return null;
}
@Override
public File getKerberosServiceKeytab() {
return null;
}
@Override
public File getKerberosConfigurationFile() {
return null;
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.documentation.init;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.controller.ControllerServiceLookup;
import java.util.Set;
public class EmptyControllerServiceLookup implements ControllerServiceLookup {
@Override
public ControllerService getControllerService(final String serviceIdentifier) {
return null;
}
@Override
public boolean isControllerServiceEnabled(final String serviceIdentifier) {
return false;
}
@Override
public boolean isControllerServiceEnabling(final String serviceIdentifier) {
return false;
}
@Override
public boolean isControllerServiceEnabled(final ControllerService service) {
return false;
}
@Override
public Set<String> getControllerServiceIdentifiers(final Class<? extends ControllerService> serviceType) throws IllegalArgumentException {
return null;
}
@Override
public String getControllerServiceName(final String serviceIdentifier) {
return null;
}
}

View File

@ -0,0 +1,172 @@
/*
* 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.documentation.init;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.logging.LogLevel;
public class NopComponentLog implements ComponentLog {
@Override
public void warn(final String msg, final Throwable t) {
}
@Override
public void warn(final String msg, final Object[] os) {
}
@Override
public void warn(final String msg, final Object[] os, final Throwable t) {
}
@Override
public void warn(final String msg) {
}
@Override
public void trace(final String msg, final Throwable t) {
}
@Override
public void trace(final String msg, final Object[] os) {
}
@Override
public void trace(final String msg) {
}
@Override
public void trace(final String msg, final Object[] os, final Throwable t) {
}
@Override
public boolean isWarnEnabled() {
return false;
}
@Override
public boolean isTraceEnabled() {
return false;
}
@Override
public boolean isInfoEnabled() {
return false;
}
@Override
public boolean isErrorEnabled() {
return false;
}
@Override
public boolean isDebugEnabled() {
return false;
}
@Override
public void info(final String msg, final Throwable t) {
}
@Override
public void info(final String msg, final Object[] os) {
}
@Override
public void info(final String msg) {
}
@Override
public void info(final String msg, final Object[] os, final Throwable t) {
}
@Override
public String getName() {
return null;
}
@Override
public void error(final String msg, final Throwable t) {
}
@Override
public void error(final String msg, final Object[] os) {
}
@Override
public void error(final String msg) {
}
@Override
public void error(final String msg, final Object[] os, final Throwable t) {
}
@Override
public void debug(final String msg, final Throwable t) {
}
@Override
public void debug(final String msg, final Object[] os) {
}
@Override
public void debug(final String msg, final Object[] os, final Throwable t) {
}
@Override
public void debug(final String msg) {
}
@Override
public void log(final LogLevel level, final String msg, final Throwable t) {
}
@Override
public void log(final LogLevel level, final String msg, final Object[] os) {
}
@Override
public void log(final LogLevel level, final String msg) {
}
@Override
public void log(final LogLevel level, final String msg, final Object[] os, final Throwable t) {
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.documentation.init;
import org.apache.nifi.components.state.Scope;
import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.components.state.StateMap;
import java.util.Map;
public class NopStateManager implements StateManager {
@Override
public void setState(final Map<String, String> state, final Scope scope) {
}
@Override
public StateMap getState(final Scope scope) {
return null;
}
@Override
public boolean replace(final StateMap oldValue, final Map<String, String> newValue, final Scope scope) {
return false;
}
@Override
public void clear(final Scope scope) {
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.documentation.init;
import org.apache.nifi.controller.NodeTypeProvider;
public class StandaloneNodeTypeProvider implements NodeTypeProvider {
@Override
public boolean isClustered() {
return false;
}
@Override
public boolean isPrimary() {
return false;
}
}

View File

@ -0,0 +1,407 @@
/*
* 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.documentation.xml;
import org.apache.nifi.annotation.behavior.DynamicProperty;
import org.apache.nifi.annotation.behavior.DynamicRelationship;
import org.apache.nifi.annotation.behavior.InputRequirement;
import org.apache.nifi.annotation.behavior.ReadsAttribute;
import org.apache.nifi.annotation.behavior.Restricted;
import org.apache.nifi.annotation.behavior.Restriction;
import org.apache.nifi.annotation.behavior.Stateful;
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
import org.apache.nifi.annotation.behavior.WritesAttribute;
import org.apache.nifi.annotation.documentation.DeprecationNotice;
import org.apache.nifi.annotation.documentation.SeeAlso;
import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.RequiredPermission;
import org.apache.nifi.documentation.AbstractDocumentationWriter;
import org.apache.nifi.documentation.ExtensionType;
import org.apache.nifi.documentation.ProvidedServiceAPI;
import org.apache.nifi.processor.Relationship;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
/**
* XML-based implementation of DocumentationWriter
*
* Please note that while this class lives within the nifi-api, it is provided primarily as a means for documentation components within
* the NiFi NAR Maven Plugin. Its home is the nifi-api, however, because the API is needed in order to extract the relevant information and
* the NAR Maven Plugin cannot have a direct dependency on nifi-api (doing so would cause a circular dependency). By having this homed within
* the nifi-api, the Maven plugin is able to discover the class dynamically and invoke the one or two methods necessary to create the documentation.
*
* This is a new capability in 1.9.0 in preparation for the Extension Registry and therefore, you should
* <b>NOTE WELL:</b> At this time, while this class is part of nifi-api, it is still evolving and may change in a non-backward-compatible manner or even be
* removed from one incremental release to the next. Use at your own risk!
*/
public class XmlDocumentationWriter extends AbstractDocumentationWriter {
private final XMLStreamWriter writer;
public XmlDocumentationWriter(final OutputStream out) throws XMLStreamException {
this.writer = XMLOutputFactory.newInstance().createXMLStreamWriter(out, "UTF-8");
}
public XmlDocumentationWriter(final XMLStreamWriter writer) {
this.writer = writer;
}
@Override
protected void writeHeader(final ConfigurableComponent component) throws IOException {
writeStartElement("extension");
}
@Override
protected void writeExtensionName(final String extensionName) throws IOException {
writeTextElement("name", extensionName);
}
@Override
protected void writeExtensionType(final ExtensionType extensionType) throws IOException {
writeTextElement("type", extensionType.name());
}
@Override
protected void writeDeprecationNotice(final DeprecationNotice deprecationNotice) throws IOException {
if (deprecationNotice == null) {
writeEmptyElement("deprecationNotice");
return;
}
final Class[] classes = deprecationNotice.alternatives();
final String[] classNames = deprecationNotice.classNames();
final Set<String> alternatives = new LinkedHashSet<>();
if (classes != null) {
for (final Class alternativeClass : classes) {
alternatives.add(alternativeClass.getName());
}
}
if (classNames != null) {
Collections.addAll(alternatives, classNames);
}
writeDeprecationNotice(deprecationNotice.reason(), alternatives);
}
private void writeDeprecationNotice(final String reason, final Set<String> alternatives) throws IOException {
writeStartElement("deprecationNotice");
writeTextElement("reason", reason);
writeTextArray("alternatives", "alternative", alternatives);
writeEndElement();
}
@Override
protected void writeDescription(final String description) throws IOException {
writeTextElement("description", description);
}
@Override
protected void writeTags(final List<String> tags) throws IOException {
writeTextArray("tags", "tag", tags);
}
@Override
protected void writeProperties(final List<PropertyDescriptor> properties) throws IOException {
writeArray("properties", properties, this::writeProperty);
}
private void writeProperty(final PropertyDescriptor property) throws IOException {
writeStartElement("property");
writeTextElement("name", property.getName());
writeTextElement("displayName", property.getDisplayName());
writeTextElement("description", property.getDescription());
writeTextElement("defaultValue", property.getDefaultValue());
writeTextElement("controllerServiceDefinition", property.getControllerServiceDefinition() == null ? null : property.getControllerServiceDefinition().getName());
writeTextArray("allowableValues", "allowableValue", property.getAllowableValues(), AllowableValue::getDisplayName);
writeBooleanElement("required", property.isRequired());
writeBooleanElement("sensitive", property.isSensitive());
writeBooleanElement("expressionLanguageSupported", property.isExpressionLanguageSupported());
writeTextElement("expressionLanguageScope", property.getExpressionLanguageScope() == null ? null : property.getExpressionLanguageScope().name());
writeBooleanElement("dynamicallyModifiesClasspath", property.isDynamicClasspathModifier());
writeBooleanElement("dynamic", property.isDynamic());
writeEndElement();
}
@Override
protected void writeDynamicProperties(final List<DynamicProperty> dynamicProperties) throws IOException {
writeArray("dynamicProperty", dynamicProperties, this::writeDynamicProperty);
}
private void writeDynamicProperty(final DynamicProperty property) throws IOException {
writeStartElement("dynamicProperty");
writeTextElement("name", property.name());
writeTextElement("value", property.value());
writeTextElement("description", property.description());
writeBooleanElement("expressionLanguageSupported", property.supportsExpressionLanguage());
writeTextElement("expressionLanguageScope", property.expressionLanguageScope() == null ? null : property.expressionLanguageScope().name());
writeEndElement();
}
@Override
protected void writeStatefulInfo(final Stateful stateful) throws IOException {
writeStartElement("stateful");
if (stateful != null) {
writeTextElement("description", stateful.description());
writeArray("scopes", Arrays.asList(stateful.scopes()), scope -> writeTextElement("scope", scope.name()));
}
writeEndElement();
}
@Override
protected void writeRestrictedInfo(final Restricted restricted) throws IOException {
writeStartElement("restricted");
if (restricted != null) {
writeTextElement("generalRestrictionExplanation", restricted.value());
final Restriction[] restrictions = restricted.restrictions();
if (restrictions != null) {
writeArray("restrictions", Arrays.asList(restrictions), this::writeRestriction);
}
}
writeEndElement();
}
private void writeRestriction(final Restriction restriction) throws IOException {
writeStartElement("restriction");
final RequiredPermission permission = restriction.requiredPermission();
final String label = permission == null ? null : permission.getPermissionLabel();
writeTextElement("requiredPermission", label);
writeTextElement("explanation", restriction.explanation());
writeEndElement();
}
@Override
protected void writeInputRequirementInfo(final InputRequirement.Requirement requirement) throws IOException {
writeTextElement("inputRequirement", requirement == null ? null : requirement.name());
}
@Override
protected void writeSystemResourceConsiderationInfo(final List<SystemResourceConsideration> considerations) throws IOException {
writeArray("systemResourceConsiderations", considerations, this::writeSystemResourceConsideration);
}
private void writeSystemResourceConsideration(final SystemResourceConsideration consideration) throws IOException {
writeStartElement("consideration");
writeTextElement("resource", consideration.resource() == null ? null : consideration.resource().name());
writeTextElement("description", consideration.description());
writeEndElement();
}
@Override
protected void writeSeeAlso(final SeeAlso seeAlso) throws IOException {
if (seeAlso == null) {
writeEmptyElement("seeAlso");
return;
}
final Class[] classes = seeAlso.value();
final String[] classNames = seeAlso.classNames();
final Set<String> toSee = new LinkedHashSet<>();
if (classes != null) {
for (final Class classToSee : classes) {
toSee.add(classToSee.getName());
}
}
if (classNames != null) {
Collections.addAll(toSee, classNames);
}
writeTextArray("seeAlso", "see", toSee);
}
@Override
protected void writeRelationships(final Set<Relationship> relationships) throws IOException {
writeArray("relationships", relationships,rel -> {
writeStartElement("relationship");
writeTextElement("name", rel.getName());
writeTextElement("description", rel.getDescription());
writeBooleanElement("autoTerminated", rel.isAutoTerminated());
writeEndElement();
} );
}
@Override
protected void writeDynamicRelationship(final DynamicRelationship dynamicRelationship) throws IOException {
writeStartElement("dynamicRelationship");
if (dynamicRelationship != null) {
writeTextElement("name", dynamicRelationship.name());
writeTextElement("description", dynamicRelationship.description());
}
writeEndElement();
}
@Override
protected void writeReadsAttributes(final List<ReadsAttribute> attributes) throws IOException {
writeArray("readsAttributes", attributes, this::writeReadsAttribute);
}
private void writeReadsAttribute(final ReadsAttribute attribute) throws IOException {
writeStartElement("attribute");
writeTextElement("name", attribute.attribute());
writeTextElement("description", attribute.description());
writeEndElement();
}
@Override
protected void writeWritesAttributes(final List<WritesAttribute> attributes) throws IOException {
writeArray("writesAttributes", attributes, this::writeWritesAttribute);
}
private void writeWritesAttribute(final WritesAttribute attribute) throws IOException {
writeStartElement("attribute");
writeTextElement("name", attribute.attribute());
writeTextElement("description", attribute.description());
writeEndElement();
}
@Override
protected void writeFooter(final ConfigurableComponent component) throws IOException {
writeEndElement();
}
@Override
protected void writeProvidedServices(final Collection<ProvidedServiceAPI> providedServices) throws IOException {
writeStartElement("providedServiceAPIs");
writeArray("service", providedServices, this::writeProvidedService);
writeEndElement();
}
private void writeProvidedService(final ProvidedServiceAPI service) throws IOException {
writeTextElement("className",service.getClassName());
writeTextElement("groupId",service.getGroupId());
writeTextElement("artifactId",service.getArtifactId());
writeTextElement("version",service.getVersion());
}
private <T> void writeArray(final String tagName, final Collection<T> values, final ElementWriter<T> writer) throws IOException {
writeStartElement(tagName);
if (values != null) {
for (final T value : values) {
writer.write(value);
}
}
writeEndElement();
}
private void writeTextArray(final String outerTagName, final String elementTagName, final Collection<String> values) throws IOException {
writeTextArray(outerTagName, elementTagName, values, String::toString);
}
private <T> void writeTextArray(final String outerTagName, final String elementTagName, final Collection<T> values, final Function<T, String> transform) throws IOException {
writeStartElement(outerTagName);
if (values != null) {
for (final T value : values) {
writeStartElement(elementTagName);
if (value != null) {
writeText(transform.apply(value));
}
writeEndElement();
}
}
writeEndElement();
}
private void writeText(final String text) throws IOException {
if (text == null) {
return;
}
try {
writer.writeCharacters(text);
} catch (XMLStreamException e) {
throw new IOException(e);
}
}
private void writeEmptyElement(final String elementName) throws IOException {
try {
writer.writeEmptyElement(elementName);
} catch (final XMLStreamException e) {
throw new IOException(e);
}
}
private void writeStartElement(final String elementName) throws IOException {
try {
writer.writeStartElement(elementName);
} catch (final XMLStreamException e) {
throw new IOException(e);
}
}
private void writeEndElement() throws IOException {
try {
writer.writeEndElement();;
} catch (final XMLStreamException e) {
throw new IOException(e);
}
}
private void writeTextElement(final String name, final String text) throws IOException {
writeStartElement(name);
writeText(text);
writeEndElement();
}
private void writeBooleanElement(final String name, final boolean value) throws IOException {
writeTextElement(name, String.valueOf(value));
}
private interface ElementWriter<T> {
void write(T value) throws IOException;
}
}

View File

@ -16,17 +16,11 @@
*/
package org.apache.nifi.amqp.processors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import javax.net.ssl.SSLContext;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultSaslConfig;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.annotation.lifecycle.OnStopped;
import org.apache.nifi.authentication.exception.ProviderCreationException;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.processor.AbstractProcessor;
@ -37,9 +31,12 @@ import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.security.util.SslContextFactory;
import org.apache.nifi.ssl.SSLContextService;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultSaslConfig;
import javax.net.ssl.SSLContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
@ -224,7 +221,7 @@ abstract class AbstractAMQPProcessor<T extends AMQPWorker> extends AbstractProce
final SSLContextService sslService = context.getProperty(SSL_CONTEXT_SERVICE).asControllerService(SSLContextService.class);
// if the property to use cert authentication is set but the SSL service hasn't been configured, throw an exception.
if (useCertAuthentication && sslService == null) {
throw new ProviderCreationException("This processor is configured to use cert authentication, " +
throw new IllegalStateException("This processor is configured to use cert authentication, " +
"but the SSL Context Service hasn't been configured. You need to configure the SSL Context Service.");
}
final String rawClientAuth = context.getProperty(CLIENT_AUTH).getValue();
@ -237,7 +234,7 @@ abstract class AbstractAMQPProcessor<T extends AMQPWorker> extends AbstractProce
try {
clientAuth = SSLContextService.ClientAuth.valueOf(rawClientAuth);
} catch (final IllegalArgumentException iae) {
throw new ProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
throw new IllegalStateException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
rawClientAuth, StringUtils.join(SslContextFactory.ClientAuth.values(), ", ")));
}
}

View File

@ -16,10 +16,7 @@
*/
package org.apache.nifi.amqp.processors;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.apache.nifi.authentication.exception.ProviderCreationException;
import com.rabbitmq.client.Connection;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.exception.ProcessException;
@ -29,7 +26,8 @@ import org.apache.nifi.util.TestRunners;
import org.junit.Before;
import org.junit.Test;
import com.rabbitmq.client.Connection;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
@ -46,7 +44,7 @@ public class AbstractAMQPProcessorTest {
testRunner = TestRunners.newTestRunner(processor);
}
@Test(expected = ProviderCreationException.class)
@Test(expected = IllegalStateException.class)
public void testConnectToCassandraWithSSLBadClientAuth() throws Exception {
SSLContextService sslService = mock(SSLContextService.class);
when(sslService.getIdentifier()).thenReturn("ssl-context");
@ -63,7 +61,7 @@ public class AbstractAMQPProcessorTest {
processor.onTrigger(testRunner.getProcessContext(), testRunner.getProcessSessionFactory());
}
@Test(expected = ProviderCreationException.class)
@Test(expected = IllegalStateException.class)
public void testInvalidSSLConfiguration() throws Exception {
// it's invalid to have use_cert_auth enabled and not have the SSL Context Service configured
testRunner.setProperty(AbstractAMQPProcessor.USE_CERT_AUTHENTICATION, "true");

View File

@ -28,7 +28,6 @@
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Forcing to 3.2.2 to avoid a CVE in 3.2.1 .. coming in transitively from tranquility core-->
<dependency>

View File

@ -36,7 +36,6 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<version>1.9.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>

View File

@ -41,7 +41,6 @@
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<scope>provided</scope>
<version>1.9.0-SNAPSHOT</version>
</dependency>
<dependency>

View File

@ -142,7 +142,7 @@ public class DocGenerator {
* that specific type of class
*/
private static DocumentationWriter getDocumentWriter(final ExtensionManager extensionManager,
final Class<? extends ConfigurableComponent> componentClass) {
final Class<? extends ConfigurableComponent> componentClass) {
if (Processor.class.isAssignableFrom(componentClass)) {
return new HtmlProcessorDocumentationWriter(extensionManager);
} else if (ControllerService.class.isAssignableFrom(componentClass)) {

View File

@ -16,8 +16,8 @@
*/
package org.apache.nifi.documentation.html;
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
import org.apache.nifi.annotation.behavior.SystemResource;
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.documentation.DocumentationWriter;
import org.apache.nifi.documentation.example.ControllerServiceWithLogger;

View File

@ -16,12 +16,6 @@
*/
package org.apache.nifi.documentation.html;
import static org.apache.nifi.documentation.html.XmlValidator.assertContains;
import static org.apache.nifi.documentation.html.XmlValidator.assertNotContains;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.apache.nifi.annotation.behavior.SystemResource;
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
@ -37,6 +31,12 @@ import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import static org.apache.nifi.documentation.html.XmlValidator.assertContains;
import static org.apache.nifi.documentation.html.XmlValidator.assertNotContains;
public class ProcessorDocumentationWriterTest {
@Test

View File

@ -1138,8 +1138,11 @@ public class JettyServer implements NiFiServer, ExtensionUiLoader {
} catch (Exception ex) {
logger.warn("Failed to stop web server", ex);
}
try {
narAutoLoader.stop();
if (narAutoLoader != null) {
narAutoLoader.stop();
}
} catch (Exception e) {
logger.warn("Failed to stop NAR auto-loader", e);
}

View File

@ -35,7 +35,6 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-processor-utils</artifactId>
<version>1.9.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>

View File

@ -29,7 +29,6 @@ import com.mongodb.client.MongoDatabase;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.annotation.lifecycle.OnScheduled;
import org.apache.nifi.annotation.lifecycle.OnStopped;
import org.apache.nifi.authentication.exception.ProviderCreationException;
import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
@ -254,7 +253,7 @@ public abstract class AbstractMongoProcessor extends AbstractProcessor {
try {
clientAuth = SSLContextService.ClientAuth.valueOf(rawClientAuth);
} catch (final IllegalArgumentException iae) {
throw new ProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
throw new IllegalStateException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
rawClientAuth, StringUtils.join(SslContextFactory.ClientAuth.values(), ", ")));
}
}

View File

@ -16,14 +16,8 @@
*/
package org.apache.nifi.processors.mongodb;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.any;
import javax.net.ssl.SSLContext;
import org.apache.nifi.authentication.exception.ProviderCreationException;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientOptions.Builder;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.exception.ProcessException;
@ -34,8 +28,12 @@ import org.apache.nifi.util.TestRunners;
import org.junit.Before;
import org.junit.Test;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientOptions.Builder;
import javax.net.ssl.SSLContext;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class AbstractMongoProcessorTest {
@ -67,7 +65,7 @@ public class AbstractMongoProcessorTest {
assertNotNull(processor.mongoClient);
}
@Test(expected = ProviderCreationException.class)
@Test(expected = IllegalStateException.class)
public void testcreateClientWithSSLBadClientAuth() throws Exception {
SSLContextService sslService = mock(SSLContextService.class);
SSLContext sslContext = mock(SSLContext.class);

View File

@ -28,7 +28,6 @@ import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.annotation.lifecycle.OnDisabled;
import org.apache.nifi.annotation.lifecycle.OnEnabled;
import org.apache.nifi.annotation.lifecycle.OnStopped;
import org.apache.nifi.authentication.exception.ProviderCreationException;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.controller.AbstractControllerService;
import org.apache.nifi.controller.ConfigurationContext;
@ -83,7 +82,7 @@ public class MongoDBControllerService extends AbstractControllerService implemen
try {
clientAuth = SSLContextService.ClientAuth.valueOf(rawClientAuth);
} catch (final IllegalArgumentException iae) {
throw new ProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
throw new IllegalStateException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
rawClientAuth, StringUtils.join(SslContextFactory.ClientAuth.values(), ", ")));
}
}

View File

@ -31,10 +31,5 @@
<artifactId>nifi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
<version>1.9.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -18,15 +18,11 @@ package org.apache.nifi.hbase;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.hbase.put.PutColumn;
import org.apache.nifi.hbase.put.PutFlowFile;
import org.apache.nifi.hbase.scan.Column;
import org.apache.nifi.hbase.scan.ResultHandler;
import org.apache.nifi.hbase.validate.ConfigFilesValidator;
import org.apache.nifi.processor.util.StandardValidators;
import java.io.IOException;
import java.util.Collection;
@ -36,52 +32,6 @@ import java.util.List;
@CapabilityDescription("A controller service for accessing an HBase client.")
public interface HBaseClientService extends ControllerService {
PropertyDescriptor HADOOP_CONF_FILES = new PropertyDescriptor.Builder()
.name("Hadoop Configuration Files")
.description("Comma-separated list of Hadoop Configuration files," +
" such as hbase-site.xml and core-site.xml for kerberos, " +
"including full paths to the files.")
.addValidator(new ConfigFilesValidator())
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
.name("ZooKeeper Quorum")
.description("Comma-separated list of ZooKeeper hosts for HBase. Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
PropertyDescriptor ZOOKEEPER_CLIENT_PORT = new PropertyDescriptor.Builder()
.name("ZooKeeper Client Port")
.description("The port on which ZooKeeper is accepting client connections. Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.PORT_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
PropertyDescriptor ZOOKEEPER_ZNODE_PARENT = new PropertyDescriptor.Builder()
.name("ZooKeeper ZNode Parent")
.description("The ZooKeeper ZNode Parent value for HBase (example: /hbase). Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
PropertyDescriptor HBASE_CLIENT_RETRIES = new PropertyDescriptor.Builder()
.name("HBase Client Retries")
.description("The number of times the HBase client will retry connecting. Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
.defaultValue("1")
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
PropertyDescriptor PHOENIX_CLIENT_JAR_LOCATION = new PropertyDescriptor.Builder()
.name("Phoenix Client JAR Location")
.description("The full path to the Phoenix client JAR. Required if Phoenix is installed on top of HBase.")
.addValidator(StandardValidators.FILE_EXISTS_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.dynamicallyModifiesClasspath(true)
.build();
/**
* Puts a batch of mutations to the given table.
*

View File

@ -52,6 +52,7 @@ import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.controller.AbstractControllerService;
import org.apache.nifi.controller.ConfigurationContext;
import org.apache.nifi.controller.ControllerServiceInitializationContext;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.hadoop.KerberosProperties;
import org.apache.nifi.hadoop.SecurityUtil;
import org.apache.nifi.hbase.put.PutColumn;
@ -59,6 +60,7 @@ import org.apache.nifi.hbase.put.PutFlowFile;
import org.apache.nifi.hbase.scan.Column;
import org.apache.nifi.hbase.scan.ResultCell;
import org.apache.nifi.hbase.scan.ResultHandler;
import org.apache.nifi.hbase.validate.ConfigFilesValidator;
import org.apache.nifi.kerberos.KerberosCredentialsService;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.reporting.InitializationException;
@ -100,6 +102,51 @@ public class HBase_1_1_2_ClientService extends AbstractControllerService impleme
.required(false)
.build();
static final PropertyDescriptor HADOOP_CONF_FILES = new PropertyDescriptor.Builder()
.name("Hadoop Configuration Files")
.description("Comma-separated list of Hadoop Configuration files," +
" such as hbase-site.xml and core-site.xml for kerberos, " +
"including full paths to the files.")
.addValidator(new ConfigFilesValidator())
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
.name("ZooKeeper Quorum")
.description("Comma-separated list of ZooKeeper hosts for HBase. Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
static final PropertyDescriptor ZOOKEEPER_CLIENT_PORT = new PropertyDescriptor.Builder()
.name("ZooKeeper Client Port")
.description("The port on which ZooKeeper is accepting client connections. Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.PORT_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
static final PropertyDescriptor ZOOKEEPER_ZNODE_PARENT = new PropertyDescriptor.Builder()
.name("ZooKeeper ZNode Parent")
.description("The ZooKeeper ZNode Parent value for HBase (example: /hbase). Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
static final PropertyDescriptor HBASE_CLIENT_RETRIES = new PropertyDescriptor.Builder()
.name("HBase Client Retries")
.description("The number of times the HBase client will retry connecting. Required if Hadoop Configuration Files are not provided.")
.addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
.defaultValue("1")
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
static final PropertyDescriptor PHOENIX_CLIENT_JAR_LOCATION = new PropertyDescriptor.Builder()
.name("Phoenix Client JAR Location")
.description("The full path to the Phoenix client JAR. Required if Phoenix is installed on top of HBase.")
.addValidator(StandardValidators.FILE_EXISTS_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.dynamicallyModifiesClasspath(true)
.build();
static final String HBASE_CONF_ZK_QUORUM = "hbase.zookeeper.quorum";
static final String HBASE_CONF_ZK_PORT = "hbase.zookeeper.property.clientPort";

View File

@ -26,6 +26,12 @@
<source.skip>true</source.skip>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-jetty-bundle</artifactId>
<version>1.9.0-SNAPSHOT</version>
<type>nar</type>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-ssl-context-service-api</artifactId>

74
pom.xml
View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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
<!-- 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. -->
<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>
@ -99,7 +99,7 @@
<repositories>
<repository>
<id>central</id>
<!-- This should be at top, it makes maven try the central repo
<!-- This should be at top, it makes maven try the central repo
first and then others and hence faster dep resolution -->
<name>Maven Repository</name>
<url>https://repo1.maven.org/maven2</url>
@ -135,7 +135,7 @@
<dependencyManagement>
<dependencies>
<!-- The following dependency management entries exist because these are jars
<!-- The following dependency management entries exist because these are jars
that live in the top-level lib directory and will be present in the parent-first
classloading of all child nars. Therefore we dont want child nars using different
versions anyway.-->
@ -549,7 +549,7 @@
</module>
<module name="OuterTypeFilename" />
<module name="LineLength">
<!-- needs extra, because Eclipse formatter
<!-- needs extra, because Eclipse formatter
ignores the ending left brace -->
<property name="max" value="200" />
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://" />
@ -626,9 +626,9 @@
</build>
<profiles>
<profile>
<!-- Performs execution of Integration Tests using the Maven
FailSafe Plugin. The view of integration tests in this context are those
tests interfacing with external sources and services requiring additional
<!-- Performs execution of Integration Tests using the Maven
FailSafe Plugin. The view of integration tests in this context are those
tests interfacing with external sources and services requiring additional
resources or credentials that cannot be explicitly provided. Also appropriate
for tests which depend on inter-thread and/or network or having timing
considerations which could make the tests brittle on various environments.-->
@ -651,11 +651,11 @@
</build>
</profile>
<profile>
<!-- Checks style and licensing requirements. This is a good
idea to run for contributions and for the release process. While it would
be nice to run always these plugins can considerably slow the build and have
proven to create unstable builds in our multi-module project and when building
using multiple threads. The stability issues seen with Checkstyle in multi-module
<!-- Checks style and licensing requirements. This is a good
idea to run for contributions and for the release process. While it would
be nice to run always these plugins can considerably slow the build and have
proven to create unstable builds in our multi-module project and when building
using multiple threads. The stability issues seen with Checkstyle in multi-module
builds include false-positives and false negatives. -->
<id>contrib-check</id>
<build>
@ -692,11 +692,11 @@
</build>
</profile>
<profile>
<!-- This profile will disable DocLint which performs strict
JavaDoc processing which was introduced in JDK 8. These are technically errors
in the JavaDoc which we need to eventually address. However, if a release
is performed using JDK 8, the JavaDoc generation would fail. By activating
this profile when running on JDK 8 we can ensure the JavaDocs continue to
<!-- This profile will disable DocLint which performs strict
JavaDoc processing which was introduced in JDK 8. These are technically errors
in the JavaDoc which we need to eventually address. However, if a release
is performed using JDK 8, the JavaDoc generation would fail. By activating
this profile when running on JDK 8 we can ensure the JavaDocs continue to
generate successfully -->
<id>disable-doclint</id>
<activation>
@ -716,15 +716,15 @@
</pluginManagement>
</build>
</profile>
<!-- The following profiles are here as a convenience for folks that
want to build against vendor-specific distributions of the various Hadoop
ecosystem libraries. These will alter which dependencies are sourced in a
manner that can adjust the correct LICENSE and NOTICE requirements for any
affected jar and the resulting assembly overall. These L&N impacts are not
automatically handled by the build process and are the responsibility of
<!-- The following profiles are here as a convenience for folks that
want to build against vendor-specific distributions of the various Hadoop
ecosystem libraries. These will alter which dependencies are sourced in a
manner that can adjust the correct LICENSE and NOTICE requirements for any
affected jar and the resulting assembly overall. These L&N impacts are not
automatically handled by the build process and are the responsibility of
those creating and using the resulting binary artifacts. -->
<profile>
<!-- This profile adds the Hortonworks repository for resolving
<!-- This profile adds the Hortonworks repository for resolving
Hortonworks Data Platform (HDP) artifacts for the Hadoop bundles -->
<id>hortonworks</id>
<repositories>
@ -760,12 +760,12 @@
</repository>
</repositories>
<properties>
<!-- Vendor-specific version number included here as default,
<!-- Vendor-specific version number included here as default,
should be overridden on the command-line <hadoop.version>2.7.1.2.4.0.0-169</hadoop.version> -->
</properties>
</profile>
<profile>
<!-- This profile will add the MapR repository for resolving
<!-- This profile will add the MapR repository for resolving
MapR Hadoop artifacts for the Hadoop bundles -->
<id>mapr</id>
<repositories>
@ -782,12 +782,12 @@
</repository>
</repositories>
<properties>
<!-- Vendor-specific version number included here as default,
<!-- Vendor-specific version number included here as default,
should be overridden on the command-line <hadoop.version>2.7.0-mapr-1602</hadoop.version> -->
</properties>
</profile>
<profile>
<!-- This profile will add the Cloudera repository for resolving
<!-- This profile will add the Cloudera repository for resolving
Cloudera Distribution of Hadoop (CDH) artifacts for the Hadoop bundles -->
<id>cloudera</id>
<repositories>
@ -804,7 +804,7 @@
</repository>
</repositories>
<properties>
<!-- Vendor-specific version number included here as default,
<!-- Vendor-specific version number included here as default,
should be overridden on the command-line <hadoop.version>2.6.0-cdh5.8.1</hadoop.version> -->
</properties>
</profile>