Link DCAE MOD design tool to Acumos Adapter
[dcaegen2/platform.git] / mod / designtool / designtool-web / src / main / java / org / apache / nifi / util / NiFiProperties.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Modifications to the original nifi code for the ONAP project are made
18  * available under the Apache License, Version 2.0
19  */
20 package org.apache.nifi.util;
21
22 import java.io.BufferedInputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.InputStream;
26 import java.net.InetSocketAddress;
27 import java.net.URI;
28 import java.net.URISyntaxException;
29 import java.nio.file.InvalidPathException;
30 import java.nio.file.Path;
31 import java.nio.file.Paths;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Properties;
39 import java.util.Set;
40 import java.util.stream.Collectors;
41 import java.util.stream.Stream;
42
43 /**
44  * The NiFiProperties class holds all properties which are needed for various
45  * values to be available at runtime. It is strongly tied to the startup
46  * properties needed and is often refer to as the 'nifi.properties' file. The
47  * properties contains keys and values. Great care should be taken in leveraging
48  * this class or passing it along. Its use should be refactored and minimized
49  * over time.
50  */
51 public abstract class NiFiProperties {
52
53     // core properties
54     public static final String PROPERTIES_FILE_PATH = "nifi.properties.file.path";
55     public static final String FLOW_CONFIGURATION_FILE = "nifi.flow.configuration.file";
56     public static final String FLOW_CONFIGURATION_ARCHIVE_ENABLED = "nifi.flow.configuration.archive.enabled";
57     public static final String FLOW_CONFIGURATION_ARCHIVE_DIR = "nifi.flow.configuration.archive.dir";
58     public static final String FLOW_CONFIGURATION_ARCHIVE_MAX_TIME = "nifi.flow.configuration.archive.max.time";
59     public static final String FLOW_CONFIGURATION_ARCHIVE_MAX_STORAGE = "nifi.flow.configuration.archive.max.storage";
60     public static final String FLOW_CONFIGURATION_ARCHIVE_MAX_COUNT = "nifi.flow.configuration.archive.max.count";
61     public static final String AUTHORIZER_CONFIGURATION_FILE = "nifi.authorizer.configuration.file";
62     public static final String LOGIN_IDENTITY_PROVIDER_CONFIGURATION_FILE = "nifi.login.identity.provider.configuration.file";
63     public static final String REPOSITORY_DATABASE_DIRECTORY = "nifi.database.directory";
64     public static final String RESTORE_DIRECTORY = "nifi.restore.directory";
65     public static final String WRITE_DELAY_INTERVAL = "nifi.flowservice.writedelay.interval";
66     public static final String AUTO_RESUME_STATE = "nifi.flowcontroller.autoResumeState";
67     public static final String FLOW_CONTROLLER_GRACEFUL_SHUTDOWN_PERIOD = "nifi.flowcontroller.graceful.shutdown.period";
68     public static final String NAR_LIBRARY_DIRECTORY = "nifi.nar.library.directory";
69     public static final String NAR_LIBRARY_DIRECTORY_PREFIX = "nifi.nar.library.directory.";
70     public static final String NAR_LIBRARY_AUTOLOAD_DIRECTORY = "nifi.nar.library.autoload.directory";
71     public static final String NAR_WORKING_DIRECTORY = "nifi.nar.working.directory";
72     public static final String COMPONENT_DOCS_DIRECTORY = "nifi.documentation.working.directory";
73     public static final String SENSITIVE_PROPS_KEY = "nifi.sensitive.props.key";
74     public static final String SENSITIVE_PROPS_ALGORITHM = "nifi.sensitive.props.algorithm";
75     public static final String SENSITIVE_PROPS_PROVIDER = "nifi.sensitive.props.provider";
76     public static final String H2_URL_APPEND = "nifi.h2.url.append";
77     public static final String REMOTE_INPUT_HOST = "nifi.remote.input.host";
78     public static final String REMOTE_INPUT_PORT = "nifi.remote.input.socket.port";
79     public static final String SITE_TO_SITE_SECURE = "nifi.remote.input.secure";
80     public static final String SITE_TO_SITE_HTTP_ENABLED = "nifi.remote.input.http.enabled";
81     public static final String SITE_TO_SITE_HTTP_TRANSACTION_TTL = "nifi.remote.input.http.transaction.ttl";
82     public static final String REMOTE_CONTENTS_CACHE_EXPIRATION = "nifi.remote.contents.cache.expiration";
83     public static final String TEMPLATE_DIRECTORY = "nifi.templates.directory";
84     public static final String ADMINISTRATIVE_YIELD_DURATION = "nifi.administrative.yield.duration";
85     public static final String PERSISTENT_STATE_DIRECTORY = "nifi.persistent.state.directory";
86     public static final String BORED_YIELD_DURATION = "nifi.bored.yield.duration";
87     public static final String PROCESSOR_SCHEDULING_TIMEOUT = "nifi.processor.scheduling.timeout";
88     public static final String BACKPRESSURE_COUNT = "nifi.queue.backpressure.count";
89     public static final String BACKPRESSURE_SIZE = "nifi.queue.backpressure.size";
90
91     // DCAE related config
92     public static final String DCAE_JARS_INDEX_URL = "nifi.dcae.jars.index.url";
93
94     // content repository properties
95     public static final String REPOSITORY_CONTENT_PREFIX = "nifi.content.repository.directory.";
96     public static final String CONTENT_REPOSITORY_IMPLEMENTATION = "nifi.content.repository.implementation";
97     public static final String MAX_APPENDABLE_CLAIM_SIZE = "nifi.content.claim.max.appendable.size";
98     public static final String MAX_FLOWFILES_PER_CLAIM = "nifi.content.claim.max.flow.files";
99     public static final String CONTENT_ARCHIVE_MAX_RETENTION_PERIOD = "nifi.content.repository.archive.max.retention.period";
100     public static final String CONTENT_ARCHIVE_MAX_USAGE_PERCENTAGE = "nifi.content.repository.archive.max.usage.percentage";
101     public static final String CONTENT_ARCHIVE_BACK_PRESSURE_PERCENTAGE = "nifi.content.repository.archive.backpressure.percentage";
102     public static final String CONTENT_ARCHIVE_ENABLED = "nifi.content.repository.archive.enabled";
103     public static final String CONTENT_ARCHIVE_CLEANUP_FREQUENCY = "nifi.content.repository.archive.cleanup.frequency";
104     public static final String CONTENT_VIEWER_URL = "nifi.content.viewer.url";
105
106     // flowfile repository properties
107     public static final String FLOWFILE_REPOSITORY_IMPLEMENTATION = "nifi.flowfile.repository.implementation";
108     public static final String FLOWFILE_REPOSITORY_ALWAYS_SYNC = "nifi.flowfile.repository.always.sync";
109     public static final String FLOWFILE_REPOSITORY_DIRECTORY = "nifi.flowfile.repository.directory";
110     public static final String FLOWFILE_REPOSITORY_PARTITIONS = "nifi.flowfile.repository.partitions";
111     public static final String FLOWFILE_REPOSITORY_CHECKPOINT_INTERVAL = "nifi.flowfile.repository.checkpoint.interval";
112     public static final String FLOWFILE_SWAP_MANAGER_IMPLEMENTATION = "nifi.swap.manager.implementation";
113     public static final String QUEUE_SWAP_THRESHOLD = "nifi.queue.swap.threshold";
114     public static final String SWAP_IN_THREADS = "nifi.swap.in.threads";
115     public static final String SWAP_IN_PERIOD = "nifi.swap.in.period";
116     public static final String SWAP_OUT_THREADS = "nifi.swap.out.threads";
117     public static final String SWAP_OUT_PERIOD = "nifi.swap.out.period";
118
119     // provenance properties
120     public static final String PROVENANCE_REPO_IMPLEMENTATION_CLASS = "nifi.provenance.repository.implementation";
121     public static final String PROVENANCE_REPO_DIRECTORY_PREFIX = "nifi.provenance.repository.directory.";
122     public static final String PROVENANCE_MAX_STORAGE_TIME = "nifi.provenance.repository.max.storage.time";
123     public static final String PROVENANCE_MAX_STORAGE_SIZE = "nifi.provenance.repository.max.storage.size";
124     public static final String PROVENANCE_ROLLOVER_TIME = "nifi.provenance.repository.rollover.time";
125     public static final String PROVENANCE_ROLLOVER_SIZE = "nifi.provenance.repository.rollover.size";
126     public static final String PROVENANCE_QUERY_THREAD_POOL_SIZE = "nifi.provenance.repository.query.threads";
127     public static final String PROVENANCE_INDEX_THREAD_POOL_SIZE = "nifi.provenance.repository.index.threads";
128     public static final String PROVENANCE_COMPRESS_ON_ROLLOVER = "nifi.provenance.repository.compress.on.rollover";
129     public static final String PROVENANCE_INDEXED_FIELDS = "nifi.provenance.repository.indexed.fields";
130     public static final String PROVENANCE_INDEXED_ATTRIBUTES = "nifi.provenance.repository.indexed.attributes";
131     public static final String PROVENANCE_INDEX_SHARD_SIZE = "nifi.provenance.repository.index.shard.size";
132     public static final String PROVENANCE_JOURNAL_COUNT = "nifi.provenance.repository.journal.count";
133     public static final String PROVENANCE_REPO_ENCRYPTION_KEY = "nifi.provenance.repository.encryption.key";
134     public static final String PROVENANCE_REPO_ENCRYPTION_KEY_ID = "nifi.provenance.repository.encryption.key.id";
135     public static final String PROVENANCE_REPO_ENCRYPTION_KEY_PROVIDER_IMPLEMENTATION_CLASS = "nifi.provenance.repository.encryption.key.provider.implementation";
136     public static final String PROVENANCE_REPO_ENCRYPTION_KEY_PROVIDER_LOCATION = "nifi.provenance.repository.encryption.key.provider.location";
137     public static final String PROVENANCE_REPO_DEBUG_FREQUENCY = "nifi.provenance.repository.debug.frequency";
138
139     // component status repository properties
140     public static final String COMPONENT_STATUS_REPOSITORY_IMPLEMENTATION = "nifi.components.status.repository.implementation";
141     public static final String COMPONENT_STATUS_SNAPSHOT_FREQUENCY = "nifi.components.status.snapshot.frequency";
142
143     // security properties
144     public static final String SECURITY_KEYSTORE = "nifi.security.keystore";
145     public static final String SECURITY_KEYSTORE_TYPE = "nifi.security.keystoreType";
146     public static final String SECURITY_KEYSTORE_PASSWD = "nifi.security.keystorePasswd";
147     public static final String SECURITY_KEY_PASSWD = "nifi.security.keyPasswd";
148     public static final String SECURITY_TRUSTSTORE = "nifi.security.truststore";
149     public static final String SECURITY_TRUSTSTORE_TYPE = "nifi.security.truststoreType";
150     public static final String SECURITY_TRUSTSTORE_PASSWD = "nifi.security.truststorePasswd";
151     public static final String SECURITY_USER_AUTHORIZER = "nifi.security.user.authorizer";
152     public static final String SECURITY_USER_LOGIN_IDENTITY_PROVIDER = "nifi.security.user.login.identity.provider";
153     public static final String SECURITY_OCSP_RESPONDER_URL = "nifi.security.ocsp.responder.url";
154     public static final String SECURITY_OCSP_RESPONDER_CERTIFICATE = "nifi.security.ocsp.responder.certificate";
155     public static final String SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX = "nifi.security.identity.mapping.pattern.";
156     public static final String SECURITY_IDENTITY_MAPPING_VALUE_PREFIX = "nifi.security.identity.mapping.value.";
157     public static final String SECURITY_IDENTITY_MAPPING_TRANSFORM_PREFIX = "nifi.security.identity.mapping.transform.";
158     public static final String SECURITY_GROUP_MAPPING_PATTERN_PREFIX = "nifi.security.group.mapping.pattern.";
159     public static final String SECURITY_GROUP_MAPPING_VALUE_PREFIX = "nifi.security.group.mapping.value.";
160     public static final String SECURITY_GROUP_MAPPING_TRANSFORM_PREFIX = "nifi.security.group.mapping.transform.";
161
162     // oidc
163     public static final String SECURITY_USER_OIDC_DISCOVERY_URL = "nifi.security.user.oidc.discovery.url";
164     public static final String SECURITY_USER_OIDC_CONNECT_TIMEOUT = "nifi.security.user.oidc.connect.timeout";
165     public static final String SECURITY_USER_OIDC_READ_TIMEOUT = "nifi.security.user.oidc.read.timeout";
166     public static final String SECURITY_USER_OIDC_CLIENT_ID = "nifi.security.user.oidc.client.id";
167     public static final String SECURITY_USER_OIDC_CLIENT_SECRET = "nifi.security.user.oidc.client.secret";
168     public static final String SECURITY_USER_OIDC_PREFERRED_JWSALGORITHM = "nifi.security.user.oidc.preferred.jwsalgorithm";
169
170     // apache knox
171     public static final String SECURITY_USER_KNOX_URL = "nifi.security.user.knox.url";
172     public static final String SECURITY_USER_KNOX_PUBLIC_KEY = "nifi.security.user.knox.publicKey";
173     public static final String SECURITY_USER_KNOX_COOKIE_NAME = "nifi.security.user.knox.cookieName";
174     public static final String SECURITY_USER_KNOX_AUDIENCES = "nifi.security.user.knox.audiences";
175
176     // web properties
177     public static final String WEB_WAR_DIR = "nifi.web.war.directory";
178     public static final String WEB_HTTP_PORT = "nifi.web.http.port";
179     public static final String WEB_HTTP_PORT_FORWARDING = "nifi.web.http.port.forwarding";
180     public static final String WEB_HTTP_HOST = "nifi.web.http.host";
181     public static final String WEB_HTTP_NETWORK_INTERFACE_PREFIX = "nifi.web.http.network.interface.";
182     public static final String WEB_HTTPS_PORT = "nifi.web.https.port";
183     public static final String WEB_HTTPS_PORT_FORWARDING = "nifi.web.https.port.forwarding";
184     public static final String WEB_HTTPS_HOST = "nifi.web.https.host";
185     public static final String WEB_HTTPS_NETWORK_INTERFACE_PREFIX = "nifi.web.https.network.interface.";
186     public static final String WEB_WORKING_DIR = "nifi.web.jetty.working.directory";
187     public static final String WEB_THREADS = "nifi.web.jetty.threads";
188     public static final String WEB_MAX_HEADER_SIZE = "nifi.web.max.header.size";
189     public static final String WEB_PROXY_CONTEXT_PATH = "nifi.web.proxy.context.path";
190     public static final String WEB_PROXY_HOST = "nifi.web.proxy.host";
191
192     // ui properties
193     public static final String UI_BANNER_TEXT = "nifi.ui.banner.text";
194     public static final String UI_AUTO_REFRESH_INTERVAL = "nifi.ui.autorefresh.interval";
195
196     // cluster common properties
197     public static final String CLUSTER_PROTOCOL_HEARTBEAT_INTERVAL = "nifi.cluster.protocol.heartbeat.interval";
198     public static final String CLUSTER_PROTOCOL_IS_SECURE = "nifi.cluster.protocol.is.secure";
199
200     // cluster node properties
201     public static final String CLUSTER_IS_NODE = "nifi.cluster.is.node";
202     public static final String CLUSTER_NODE_ADDRESS = "nifi.cluster.node.address";
203     public static final String CLUSTER_NODE_PROTOCOL_PORT = "nifi.cluster.node.protocol.port";
204     public static final String CLUSTER_NODE_PROTOCOL_THREADS = "nifi.cluster.node.protocol.threads";
205     public static final String CLUSTER_NODE_PROTOCOL_MAX_THREADS = "nifi.cluster.node.protocol.max.threads";
206     public static final String CLUSTER_NODE_CONNECTION_TIMEOUT = "nifi.cluster.node.connection.timeout";
207     public static final String CLUSTER_NODE_READ_TIMEOUT = "nifi.cluster.node.read.timeout";
208     public static final String CLUSTER_NODE_MAX_CONCURRENT_REQUESTS = "nifi.cluster.node.max.concurrent.requests";
209     public static final String CLUSTER_FIREWALL_FILE = "nifi.cluster.firewall.file";
210     public static final String FLOW_ELECTION_MAX_WAIT_TIME = "nifi.cluster.flow.election.max.wait.time";
211     public static final String FLOW_ELECTION_MAX_CANDIDATES = "nifi.cluster.flow.election.max.candidates";
212
213     // cluster load balance properties
214     public static final String LOAD_BALANCE_ADDRESS = "nifi.cluster.load.balance.address";
215     public static final String LOAD_BALANCE_PORT = "nifi.cluster.load.balance.port";
216     public static final String LOAD_BALANCE_CONNECTIONS_PER_NODE = "nifi.cluster.load.balance.connections.per.node";
217     public static final String LOAD_BALANCE_MAX_THREAD_COUNT = "nifi.cluster.load.balance.max.thread.count";
218     public static final String LOAD_BALANCE_COMMS_TIMEOUT = "nifi.cluster.load.balance.comms.timeout";
219
220     // zookeeper properties
221     public static final String ZOOKEEPER_CONNECT_STRING = "nifi.zookeeper.connect.string";
222     public static final String ZOOKEEPER_CONNECT_TIMEOUT = "nifi.zookeeper.connect.timeout";
223     public static final String ZOOKEEPER_SESSION_TIMEOUT = "nifi.zookeeper.session.timeout";
224     public static final String ZOOKEEPER_ROOT_NODE = "nifi.zookeeper.root.node";
225     public static final String ZOOKEEPER_AUTH_TYPE = "nifi.zookeeper.auth.type";
226     public static final String ZOOKEEPER_KERBEROS_REMOVE_HOST_FROM_PRINCIPAL = "nifi.zookeeper.kerberos.removeHostFromPrincipal";
227     public static final String ZOOKEEPER_KERBEROS_REMOVE_REALM_FROM_PRINCIPAL = "nifi.zookeeper.kerberos.removeRealmFromPrincipal";
228
229     // kerberos properties
230     public static final String KERBEROS_KRB5_FILE = "nifi.kerberos.krb5.file";
231     public static final String KERBEROS_SERVICE_PRINCIPAL = "nifi.kerberos.service.principal";
232     public static final String KERBEROS_SERVICE_KEYTAB_LOCATION = "nifi.kerberos.service.keytab.location";
233     public static final String KERBEROS_SPNEGO_PRINCIPAL = "nifi.kerberos.spnego.principal";
234     public static final String KERBEROS_SPNEGO_KEYTAB_LOCATION = "nifi.kerberos.spnego.keytab.location";
235     public static final String KERBEROS_AUTHENTICATION_EXPIRATION = "nifi.kerberos.spnego.authentication.expiration";
236
237     // state management
238     public static final String STATE_MANAGEMENT_CONFIG_FILE = "nifi.state.management.configuration.file";
239     public static final String STATE_MANAGEMENT_LOCAL_PROVIDER_ID = "nifi.state.management.provider.local";
240     public static final String STATE_MANAGEMENT_CLUSTER_PROVIDER_ID = "nifi.state.management.provider.cluster";
241     public static final String STATE_MANAGEMENT_START_EMBEDDED_ZOOKEEPER = "nifi.state.management.embedded.zookeeper.start";
242     public static final String STATE_MANAGEMENT_ZOOKEEPER_PROPERTIES = "nifi.state.management.embedded.zookeeper.properties";
243
244     // expression language properties
245     public static final String VARIABLE_REGISTRY_PROPERTIES = "nifi.variable.registry.properties";
246
247     // defaults
248     public static final Boolean DEFAULT_AUTO_RESUME_STATE = true;
249     public static final String DEFAULT_AUTHORIZER_CONFIGURATION_FILE = "conf/authorizers.xml";
250     public static final String DEFAULT_LOGIN_IDENTITY_PROVIDER_CONFIGURATION_FILE = "conf/login-identity-providers.xml";
251     public static final Integer DEFAULT_REMOTE_INPUT_PORT = null;
252     public static final Path DEFAULT_TEMPLATE_DIRECTORY = Paths.get("conf", "templates");
253     public static final int DEFAULT_WEB_THREADS = 200;
254     public static final String DEFAULT_WEB_MAX_HEADER_SIZE = "16 KB";
255     public static final String DEFAULT_WEB_WORKING_DIR = "./work/jetty";
256     public static final String DEFAULT_NAR_WORKING_DIR = "./work/nar";
257     public static final String DEFAULT_COMPONENT_DOCS_DIRECTORY = "./work/docs/components";
258     public static final String DEFAULT_NAR_LIBRARY_DIR = "./lib";
259     public static final String DEFAULT_NAR_LIBRARY_AUTOLOAD_DIR = "./extensions";
260     public static final String DEFAULT_FLOWFILE_REPO_PARTITIONS = "256";
261     public static final String DEFAULT_FLOWFILE_CHECKPOINT_INTERVAL = "2 min";
262     public static final int DEFAULT_MAX_FLOWFILES_PER_CLAIM = 100;
263     public static final String DEFAULT_MAX_APPENDABLE_CLAIM_SIZE = "1 MB";
264     public static final int DEFAULT_QUEUE_SWAP_THRESHOLD = 20000;
265     public static final String DEFAULT_SWAP_STORAGE_LOCATION = "./flowfile_repository/swap";
266     public static final String DEFAULT_SWAP_IN_PERIOD = "1 sec";
267     public static final String DEFAULT_SWAP_OUT_PERIOD = "5 sec";
268     public static final int DEFAULT_SWAP_IN_THREADS = 4;
269     public static final int DEFAULT_SWAP_OUT_THREADS = 4;
270     public static final long DEFAULT_BACKPRESSURE_COUNT = 10_000L;
271     public static final String DEFAULT_BACKPRESSURE_SIZE = "1 GB";
272     public static final String DEFAULT_ADMINISTRATIVE_YIELD_DURATION = "30 sec";
273     public static final String DEFAULT_PERSISTENT_STATE_DIRECTORY = "./conf/state";
274     public static final String DEFAULT_COMPONENT_STATUS_SNAPSHOT_FREQUENCY = "5 mins";
275     public static final String DEFAULT_BORED_YIELD_DURATION = "10 millis";
276     public static final String DEFAULT_ZOOKEEPER_CONNECT_TIMEOUT = "3 secs";
277     public static final String DEFAULT_ZOOKEEPER_SESSION_TIMEOUT = "3 secs";
278     public static final String DEFAULT_ZOOKEEPER_ROOT_NODE = "/nifi";
279     public static final String DEFAULT_ZOOKEEPER_AUTH_TYPE = "default";
280     public static final String DEFAULT_ZOOKEEPER_KERBEROS_REMOVE_HOST_FROM_PRINCIPAL = "true";
281     public static final String DEFAULT_ZOOKEEPER_KERBEROS_REMOVE_REALM_FROM_PRINCIPAL = "true";
282     public static final String DEFAULT_SITE_TO_SITE_HTTP_TRANSACTION_TTL = "30 secs";
283     public static final String DEFAULT_FLOW_CONFIGURATION_ARCHIVE_ENABLED = "true";
284     public static final String DEFAULT_FLOW_CONFIGURATION_ARCHIVE_MAX_TIME = "30 days";
285     public static final String DEFAULT_FLOW_CONFIGURATION_ARCHIVE_MAX_STORAGE = "500 MB";
286     public static final String DEFAULT_SECURITY_USER_OIDC_CONNECT_TIMEOUT = "5 secs";
287     public static final String DEFAULT_SECURITY_USER_OIDC_READ_TIMEOUT = "5 secs";
288
289     // DCAE related config
290     // REVIEW: Default is to turn off the dcae jar loading until the platform becomes more accessible/stable
291     public static final String DEFAULT_DCAE_JARS_INDEX_URL = "";
292
293     // cluster common defaults
294     public static final String DEFAULT_CLUSTER_PROTOCOL_HEARTBEAT_INTERVAL = "5 sec";
295     public static final String DEFAULT_CLUSTER_PROTOCOL_MULTICAST_SERVICE_BROADCAST_DELAY = "500 ms";
296     public static final int DEFAULT_CLUSTER_PROTOCOL_MULTICAST_SERVICE_LOCATOR_ATTEMPTS = 3;
297     public static final String DEFAULT_CLUSTER_PROTOCOL_MULTICAST_SERVICE_LOCATOR_ATTEMPTS_DELAY = "1 sec";
298     public static final String DEFAULT_CLUSTER_NODE_READ_TIMEOUT = "5 sec";
299     public static final String DEFAULT_CLUSTER_NODE_CONNECTION_TIMEOUT = "5 sec";
300     public static final int DEFAULT_CLUSTER_NODE_MAX_CONCURRENT_REQUESTS = 100;
301
302     // cluster node defaults
303     public static final int DEFAULT_CLUSTER_NODE_PROTOCOL_THREADS = 10;
304     public static final int DEFAULT_CLUSTER_NODE_PROTOCOL_MAX_THREADS = 50;
305     public static final String DEFAULT_REQUEST_REPLICATION_CLAIM_TIMEOUT = "15 secs";
306     public static final String DEFAULT_FLOW_ELECTION_MAX_WAIT_TIME = "5 mins";
307
308     // cluster load balance defaults
309     public static final int DEFAULT_LOAD_BALANCE_PORT = 6342;
310     public static final int DEFAULT_LOAD_BALANCE_CONNECTIONS_PER_NODE = 4;
311     public static final int DEFAULT_LOAD_BALANCE_MAX_THREAD_COUNT = 8;
312     public static final String DEFAULT_LOAD_BALANCE_COMMS_TIMEOUT = "30 sec";
313
314
315     // state management defaults
316     public static final String DEFAULT_STATE_MANAGEMENT_CONFIG_FILE = "conf/state-management.xml";
317
318     // Kerberos defaults
319     public static final String DEFAULT_KERBEROS_AUTHENTICATION_EXPIRATION = "12 hours";
320
321
322     /**
323      * Retrieves the property value for the given property key.
324      *
325      * @param key the key of property value to lookup
326      * @return value of property at given key or null if not found
327      */
328     public abstract String getProperty(String key);
329
330     /**
331      * Retrieves all known property keys.
332      *
333      * @return all known property keys
334      */
335     public abstract Set<String> getPropertyKeys();
336
337     // getters for core properties //
338     public File getFlowConfigurationFile() {
339         try {
340             return new File(getProperty(FLOW_CONFIGURATION_FILE));
341         } catch (Exception ex) {
342             return null;
343         }
344     }
345
346     public File getFlowConfigurationFileDir() {
347         try {
348             return getFlowConfigurationFile().getParentFile();
349         } catch (Exception ex) {
350             return null;
351         }
352     }
353
354     private Integer getPropertyAsPort(final String propertyName, final Integer defaultValue) {
355         final String port = getProperty(propertyName);
356         if (StringUtils.isEmpty(port)) {
357             return defaultValue;
358         }
359         try {
360             final int val = Integer.parseInt(port);
361             if (val <= 0 || val > 65535) {
362                 throw new RuntimeException("Valid port range is 0 - 65535 but got " + val);
363             }
364             return val;
365         } catch (final NumberFormatException e) {
366             return defaultValue;
367         }
368     }
369
370     public int getQueueSwapThreshold() {
371         final String thresholdValue = getProperty(QUEUE_SWAP_THRESHOLD);
372         if (thresholdValue == null) {
373             return DEFAULT_QUEUE_SWAP_THRESHOLD;
374         }
375
376         try {
377             return Integer.parseInt(thresholdValue);
378         } catch (final NumberFormatException e) {
379             return DEFAULT_QUEUE_SWAP_THRESHOLD;
380         }
381     }
382
383     public Integer getIntegerProperty(final String propertyName, final Integer defaultValue) {
384         final String value = getProperty(propertyName);
385         if (value == null || value.trim().isEmpty()) {
386             return defaultValue;
387         }
388
389         try {
390             return Integer.parseInt(value.trim());
391         } catch (final Exception e) {
392             return defaultValue;
393         }
394     }
395
396     public int getSwapInThreads() {
397         return getIntegerProperty(SWAP_IN_THREADS, DEFAULT_SWAP_IN_THREADS);
398     }
399
400     public int getSwapOutThreads() {
401         final String value = getProperty(SWAP_OUT_THREADS);
402         if (value == null) {
403             return DEFAULT_SWAP_OUT_THREADS;
404         }
405
406         try {
407             return Integer.parseInt(getProperty(SWAP_OUT_THREADS));
408         } catch (final Exception e) {
409             return DEFAULT_SWAP_OUT_THREADS;
410         }
411     }
412
413     public String getSwapInPeriod() {
414         return getProperty(SWAP_IN_PERIOD, DEFAULT_SWAP_IN_PERIOD);
415     }
416
417     public String getSwapOutPeriod() {
418         return getProperty(SWAP_OUT_PERIOD, DEFAULT_SWAP_OUT_PERIOD);
419     }
420
421     public String getAdministrativeYieldDuration() {
422         return getProperty(ADMINISTRATIVE_YIELD_DURATION, DEFAULT_ADMINISTRATIVE_YIELD_DURATION);
423     }
424
425     /**
426      * The host name that will be given out to clients to connect to the Remote
427      * Input Port.
428      *
429      * @return the remote input host name or null if not configured
430      */
431     public String getRemoteInputHost() {
432         final String value = getProperty(REMOTE_INPUT_HOST);
433         return StringUtils.isBlank(value) ? null : value;
434     }
435
436     /**
437      * The socket port to listen on for a Remote Input Port.
438      *
439      * @return the remote input port for RAW socket communication
440      */
441     public Integer getRemoteInputPort() {
442         return getPropertyAsPort(REMOTE_INPUT_PORT, DEFAULT_REMOTE_INPUT_PORT);
443     }
444
445     /**
446      * @return False if property value is 'false'; True otherwise.
447      */
448     public Boolean isSiteToSiteSecure() {
449         final String secureVal = getProperty(SITE_TO_SITE_SECURE, "true");
450
451         return !"false".equalsIgnoreCase(secureVal);
452
453     }
454
455     /**
456      * @return True if property value is 'true'; False otherwise.
457      */
458     public Boolean isSiteToSiteHttpEnabled() {
459         final String remoteInputHttpEnabled = getProperty(SITE_TO_SITE_HTTP_ENABLED, "false");
460
461         return "true".equalsIgnoreCase(remoteInputHttpEnabled);
462
463     }
464
465     /**
466      * The HTTP or HTTPS Web API port for a Remote Input Port.
467      *
468      * @return the remote input port for HTTP(S) communication, or null if
469      * HTTP(S) Site-to-Site is not enabled
470      */
471     public Integer getRemoteInputHttpPort() {
472         if (!isSiteToSiteHttpEnabled()) {
473             return null;
474         }
475
476         final String propertyKey;
477         if (isSiteToSiteSecure()) {
478             if (StringUtils.isBlank(getProperty(NiFiProperties.WEB_HTTPS_PORT_FORWARDING))) {
479                 propertyKey = WEB_HTTPS_PORT;
480             } else {
481                 propertyKey = WEB_HTTPS_PORT_FORWARDING;
482             }
483         } else {
484             if (StringUtils.isBlank(getProperty(NiFiProperties.WEB_HTTP_PORT_FORWARDING))) {
485                 propertyKey = WEB_HTTP_PORT;
486             } else {
487                 propertyKey = WEB_HTTP_PORT_FORWARDING;
488             }
489         }
490
491         final Integer port = getIntegerProperty(propertyKey, null);
492         if (port == null) {
493             throw new RuntimeException("Remote input HTTP" + (isSiteToSiteSecure() ? "S" : "")
494                     + " is enabled but " + propertyKey + " is not specified.");
495         }
496         return port;
497     }
498
499     /**
500      * Returns the directory to which Templates are to be persisted
501      *
502      * @return the template directory
503      */
504     public Path getTemplateDirectory() {
505         final String strVal = getProperty(TEMPLATE_DIRECTORY);
506         return (strVal == null) ? DEFAULT_TEMPLATE_DIRECTORY : Paths.get(strVal);
507     }
508
509     /**
510      * Get the flow service write delay.
511      *
512      * @return The write delay
513      */
514     public String getFlowServiceWriteDelay() {
515         return getProperty(WRITE_DELAY_INTERVAL);
516     }
517
518     /**
519      * Returns whether the processors should be started automatically when the
520      * application loads.
521      *
522      * @return Whether to auto start the processors or not
523      */
524     public boolean getAutoResumeState() {
525         final String rawAutoResumeState = getProperty(AUTO_RESUME_STATE,
526                 DEFAULT_AUTO_RESUME_STATE.toString());
527         return Boolean.parseBoolean(rawAutoResumeState);
528     }
529
530     /**
531      * Returns the number of partitions that should be used for the FlowFile
532      * Repository
533      *
534      * @return the number of partitions
535      */
536     public int getFlowFileRepositoryPartitions() {
537         final String rawProperty = getProperty(FLOWFILE_REPOSITORY_PARTITIONS,
538                 DEFAULT_FLOWFILE_REPO_PARTITIONS);
539         return Integer.parseInt(rawProperty);
540     }
541
542     /**
543      * Returns the number of milliseconds between FlowFileRepository
544      * checkpointing
545      *
546      * @return the number of milliseconds between checkpoint events
547      */
548     public String getFlowFileRepositoryCheckpointInterval() {
549         return getProperty(FLOWFILE_REPOSITORY_CHECKPOINT_INTERVAL,
550                 DEFAULT_FLOWFILE_CHECKPOINT_INTERVAL);
551     }
552
553     /**
554      * @return the restore directory or null if not configured
555      */
556     public File getRestoreDirectory() {
557         final String value = getProperty(RESTORE_DIRECTORY);
558         if (StringUtils.isBlank(value)) {
559             return null;
560         } else {
561             return new File(value);
562         }
563     }
564
565     /**
566      * @return the user authorizers file
567      */
568     public File getAuthorizerConfigurationFile() {
569         final String value = getProperty(AUTHORIZER_CONFIGURATION_FILE);
570         if (StringUtils.isBlank(value)) {
571             return new File(DEFAULT_AUTHORIZER_CONFIGURATION_FILE);
572         } else {
573             return new File(value);
574         }
575     }
576
577     /**
578      * @return the user login identity provider file
579      */
580     public File getLoginIdentityProviderConfigurationFile() {
581         final String value = getProperty(LOGIN_IDENTITY_PROVIDER_CONFIGURATION_FILE);
582         if (StringUtils.isBlank(value)) {
583             return new File(DEFAULT_LOGIN_IDENTITY_PROVIDER_CONFIGURATION_FILE);
584         } else {
585             return new File(value);
586         }
587     }
588
589     // getters for web properties //
590     public Integer getPort() {
591         Integer port = null;
592         try {
593             port = Integer.parseInt(getProperty(WEB_HTTP_PORT));
594         } catch (NumberFormatException nfe) {
595         }
596         return port;
597     }
598
599     public Integer getSslPort() {
600         Integer sslPort = null;
601         try {
602             sslPort = Integer.parseInt(getProperty(WEB_HTTPS_PORT));
603         } catch (NumberFormatException nfe) {
604         }
605         return sslPort;
606     }
607
608     public boolean isHTTPSConfigured() {
609         return getSslPort() != null;
610     }
611
612     /**
613      * Determines the HTTP/HTTPS port NiFi is configured to bind to. Prefers the HTTPS port. Throws an exception if neither is configured.
614      *
615      * @return the configured port number
616      */
617     public Integer getConfiguredHttpOrHttpsPort() throws RuntimeException {
618         if (getSslPort() != null) {
619             return getSslPort();
620         } else if (getPort() != null) {
621             return getPort();
622         } else {
623             throw new RuntimeException("The HTTP or HTTPS port must be configured");
624         }
625     }
626
627     public String getWebMaxHeaderSize() {
628         return getProperty(WEB_MAX_HEADER_SIZE, DEFAULT_WEB_MAX_HEADER_SIZE);
629     }
630
631     public int getWebThreads() {
632         return getIntegerProperty(WEB_THREADS, DEFAULT_WEB_THREADS);
633     }
634
635     public int getClusterNodeMaxConcurrentRequests() {
636         return getIntegerProperty(CLUSTER_NODE_MAX_CONCURRENT_REQUESTS, DEFAULT_CLUSTER_NODE_MAX_CONCURRENT_REQUESTS);
637     }
638
639     public File getWebWorkingDirectory() {
640         return new File(getProperty(WEB_WORKING_DIR, DEFAULT_WEB_WORKING_DIR));
641     }
642
643     public File getComponentDocumentationWorkingDirectory() {
644         return new File(getProperty(COMPONENT_DOCS_DIRECTORY, DEFAULT_COMPONENT_DOCS_DIRECTORY));
645     }
646
647     public File getNarWorkingDirectory() {
648         return new File(getProperty(NAR_WORKING_DIRECTORY, DEFAULT_NAR_WORKING_DIR));
649     }
650
651     public File getFrameworkWorkingDirectory() {
652         return new File(getNarWorkingDirectory(), "framework");
653     }
654
655     public File getExtensionsWorkingDirectory() {
656         return new File(getNarWorkingDirectory(), "extensions");
657     }
658
659     public List<Path> getNarLibraryDirectories() {
660
661         List<Path> narLibraryPaths = new ArrayList<>();
662
663         // go through each property
664         for (String propertyName : getPropertyKeys()) {
665             // determine if the property is a nar library path
666             if (StringUtils.startsWith(propertyName, NAR_LIBRARY_DIRECTORY_PREFIX)
667                     || NAR_LIBRARY_DIRECTORY.equals(propertyName)
668                     || NAR_LIBRARY_AUTOLOAD_DIRECTORY.equals(propertyName)) {
669                 // attempt to resolve the path specified
670                 String narLib = getProperty(propertyName);
671                 if (!StringUtils.isBlank(narLib)) {
672                     narLibraryPaths.add(Paths.get(narLib));
673                 }
674             }
675         }
676
677         if (narLibraryPaths.isEmpty()) {
678             narLibraryPaths.add(Paths.get(DEFAULT_NAR_LIBRARY_DIR));
679         }
680
681         return narLibraryPaths;
682     }
683
684     public File getNarAutoLoadDirectory() {
685         return new File(getProperty(NAR_LIBRARY_AUTOLOAD_DIRECTORY, DEFAULT_NAR_LIBRARY_AUTOLOAD_DIR));
686     }
687
688     /**
689      * Retrieves a URI to the index that contains URLs to all the DCAE jars to be loaded into Nifi.
690      * Refer to the genprocessor project for more info.
691      *
692      * Not setting the underlying configuration parameter "nifi.dcae.jar.index.url" is not
693      * fatal. Nifi will just skip over trying to load DCAE jars.
694      *
695      * @return
696      * @throws URISyntaxException
697      */
698     public URI getDCAEJarIndexURI() throws URISyntaxException {
699         String strUrl = getProperty(DCAE_JARS_INDEX_URL, DEFAULT_DCAE_JARS_INDEX_URL);
700
701         if (strUrl == null || strUrl.isEmpty()) {
702             return null;
703         } else {
704             return new URI(strUrl);
705         }
706     }
707
708     // getters for ui properties //
709
710     /**
711      * Get the banner text.
712      *
713      * @return The banner text
714      */
715     public String getBannerText() {
716         return this.getProperty(UI_BANNER_TEXT, StringUtils.EMPTY);
717     }
718
719     /**
720      * Returns the auto refresh interval in seconds.
721      *
722      * @return the interval over which the properties should auto refresh
723      */
724     public String getAutoRefreshInterval() {
725         return getProperty(UI_AUTO_REFRESH_INTERVAL);
726     }
727
728     // getters for cluster protocol properties //
729     public String getClusterProtocolHeartbeatInterval() {
730         return getProperty(CLUSTER_PROTOCOL_HEARTBEAT_INTERVAL,
731                 DEFAULT_CLUSTER_PROTOCOL_HEARTBEAT_INTERVAL);
732     }
733
734     public String getNodeHeartbeatInterval() {
735         return getClusterProtocolHeartbeatInterval();
736     }
737
738     public String getClusterNodeReadTimeout() {
739         return getProperty(CLUSTER_NODE_READ_TIMEOUT, DEFAULT_CLUSTER_NODE_READ_TIMEOUT);
740     }
741
742     public String getClusterNodeConnectionTimeout() {
743         return getProperty(CLUSTER_NODE_CONNECTION_TIMEOUT,
744                 DEFAULT_CLUSTER_NODE_CONNECTION_TIMEOUT);
745     }
746
747     public File getPersistentStateDirectory() {
748         final String dirName = getProperty(PERSISTENT_STATE_DIRECTORY,
749                 DEFAULT_PERSISTENT_STATE_DIRECTORY);
750         final File file = new File(dirName);
751         if (!file.exists()) {
752             file.mkdirs();
753         }
754         return file;
755     }
756
757     // getters for cluster node properties //
758     public boolean isNode() {
759         return Boolean.parseBoolean(getProperty(CLUSTER_IS_NODE));
760     }
761
762     public InetSocketAddress getClusterNodeProtocolAddress() {
763         try {
764             String socketAddress = getProperty(CLUSTER_NODE_ADDRESS);
765             if (StringUtils.isBlank(socketAddress)) {
766                 socketAddress = "localhost";
767             }
768             int socketPort = getClusterNodeProtocolPort();
769             return InetSocketAddress.createUnresolved(socketAddress, socketPort);
770         } catch (Exception ex) {
771             throw new RuntimeException("Invalid node protocol address/port due to: " + ex, ex);
772         }
773     }
774
775     public InetSocketAddress getClusterLoadBalanceAddress() {
776         try {
777             String address = getProperty(LOAD_BALANCE_ADDRESS);
778             if (StringUtils.isBlank(address)) {
779                 address = getProperty(CLUSTER_NODE_ADDRESS);
780             }
781             if (StringUtils.isBlank(address)) {
782                 address = "localhost";
783             }
784
785             final int port = getIntegerProperty(LOAD_BALANCE_PORT, DEFAULT_LOAD_BALANCE_PORT);
786             return InetSocketAddress.createUnresolved(address, port);
787         } catch (final Exception e) {
788             throw new RuntimeException("Invalid load balance address/port due to: " + e, e);
789         }
790     }
791
792     public Integer getClusterNodeProtocolPort() {
793         try {
794             return Integer.parseInt(getProperty(CLUSTER_NODE_PROTOCOL_PORT));
795         } catch (NumberFormatException nfe) {
796             return null;
797         }
798     }
799
800     /**
801      * @deprecated Use getClusterNodeProtocolCorePoolSize() and getClusterNodeProtocolMaxPoolSize() instead
802      */
803     @Deprecated()
804     public int getClusterNodeProtocolThreads() {
805         return getClusterNodeProtocolCorePoolSize();
806     }
807
808     public int getClusterNodeProtocolCorePoolSize() {
809         try {
810             return Integer.parseInt(getProperty(CLUSTER_NODE_PROTOCOL_THREADS));
811         } catch (NumberFormatException nfe) {
812             return DEFAULT_CLUSTER_NODE_PROTOCOL_THREADS;
813         }
814     }
815
816     public int getClusterNodeProtocolMaxPoolSize() {
817         try {
818             return Integer.parseInt(getProperty(CLUSTER_NODE_PROTOCOL_MAX_THREADS));
819         } catch (NumberFormatException nfe) {
820             return DEFAULT_CLUSTER_NODE_PROTOCOL_MAX_THREADS;
821         }
822     }
823
824     public boolean isClustered() {
825         return Boolean.parseBoolean(getProperty(CLUSTER_IS_NODE));
826     }
827
828     public File getClusterNodeFirewallFile() {
829         final String firewallFile = getProperty(CLUSTER_FIREWALL_FILE);
830         if (StringUtils.isBlank(firewallFile)) {
831             return null;
832         } else {
833             return new File(firewallFile);
834         }
835     }
836
837     public String getClusterProtocolManagerToNodeApiScheme() {
838         final String isSecureProperty = getProperty(CLUSTER_PROTOCOL_IS_SECURE);
839         if (Boolean.valueOf(isSecureProperty)) {
840             return "https";
841         } else {
842             return "http";
843         }
844     }
845
846     public File getKerberosConfigurationFile() {
847         final String krb5File = getProperty(KERBEROS_KRB5_FILE);
848         if (krb5File != null && krb5File.trim().length() > 0) {
849             return new File(krb5File.trim());
850         } else {
851             return null;
852         }
853     }
854
855     public String getKerberosServicePrincipal() {
856         final String servicePrincipal = getProperty(KERBEROS_SERVICE_PRINCIPAL);
857         if (!StringUtils.isBlank(servicePrincipal)) {
858             return servicePrincipal.trim();
859         } else {
860             return null;
861         }
862     }
863
864     public String getKerberosServiceKeytabLocation() {
865         final String keytabLocation = getProperty(KERBEROS_SERVICE_KEYTAB_LOCATION);
866         if (!StringUtils.isBlank(keytabLocation)) {
867             return keytabLocation.trim();
868         } else {
869             return null;
870         }
871     }
872
873     public String getKerberosSpnegoPrincipal() {
874         final String spengoPrincipal = getProperty(KERBEROS_SPNEGO_PRINCIPAL);
875         if (!StringUtils.isBlank(spengoPrincipal)) {
876             return spengoPrincipal.trim();
877         } else {
878             return null;
879         }
880     }
881
882     public String getKerberosSpnegoKeytabLocation() {
883         final String keytabLocation = getProperty(KERBEROS_SPNEGO_KEYTAB_LOCATION);
884         if (!StringUtils.isBlank(keytabLocation)) {
885             return keytabLocation.trim();
886         } else {
887             return null;
888         }
889     }
890
891     public String getKerberosAuthenticationExpiration() {
892         final String authenticationExpirationString = getProperty(KERBEROS_AUTHENTICATION_EXPIRATION, DEFAULT_KERBEROS_AUTHENTICATION_EXPIRATION);
893         if (!StringUtils.isBlank(authenticationExpirationString)) {
894             return authenticationExpirationString.trim();
895         } else {
896             return null;
897         }
898     }
899
900     /**
901      * Returns true if the Kerberos service principal and keytab location
902      * properties are populated.
903      *
904      * @return true if Kerberos service support is enabled
905      */
906     public boolean isKerberosSpnegoSupportEnabled() {
907         return !StringUtils.isBlank(getKerberosSpnegoPrincipal()) && !StringUtils.isBlank(getKerberosSpnegoKeytabLocation());
908     }
909
910     /**
911      * Returns true if the login identity provider has been configured.
912      *
913      * @return true if the login identity provider has been configured
914      */
915     public boolean isLoginIdentityProviderEnabled() {
916         return !StringUtils.isBlank(getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER));
917     }
918
919     /**
920      * Returns whether an OpenId Connect (OIDC) URL is set.
921      *
922      * @return whether an OpenId Connection URL is set
923      */
924     public boolean isOidcEnabled() {
925         return !StringUtils.isBlank(getOidcDiscoveryUrl());
926     }
927
928     /**
929      * Returns the OpenId Connect (OIDC) URL. Null otherwise.
930      *
931      * @return OIDC discovery url
932      */
933     public String getOidcDiscoveryUrl() {
934         return getProperty(SECURITY_USER_OIDC_DISCOVERY_URL);
935     }
936
937     /**
938      * Returns the OpenId Connect connect timeout. Non null.
939      *
940      * @return OIDC connect timeout
941      */
942     public String getOidcConnectTimeout() {
943         return getProperty(SECURITY_USER_OIDC_CONNECT_TIMEOUT, DEFAULT_SECURITY_USER_OIDC_CONNECT_TIMEOUT);
944     }
945
946     /**
947      * Returns the OpenId Connect read timeout. Non null.
948      *
949      * @return OIDC read timeout
950      */
951     public String getOidcReadTimeout() {
952         return getProperty(SECURITY_USER_OIDC_READ_TIMEOUT, DEFAULT_SECURITY_USER_OIDC_READ_TIMEOUT);
953     }
954
955     /**
956      * Returns the OpenId Connect client id.
957      *
958      * @return OIDC client id
959      */
960     public String getOidcClientId() {
961         return getProperty(SECURITY_USER_OIDC_CLIENT_ID);
962     }
963
964     /**
965      * Returns the OpenId Connect client secret.
966      *
967      * @return OIDC client secret
968      */
969     public String getOidcClientSecret() {
970         return getProperty(SECURITY_USER_OIDC_CLIENT_SECRET);
971     }
972
973     /**
974      * Returns the preferred json web signature algorithm. May be null/blank.
975      *
976      * @return OIDC preferred json web signature algorithm
977      */
978     public String getOidcPreferredJwsAlgorithm() {
979         return getProperty(SECURITY_USER_OIDC_PREFERRED_JWSALGORITHM);
980     }
981
982     /**
983      * Returns whether Knox SSO is enabled.
984      *
985      * @return whether Knox SSO is enabled
986      */
987     public boolean isKnoxSsoEnabled() {
988         return !StringUtils.isBlank(getKnoxUrl());
989     }
990
991     /**
992      * Returns the Knox URL.
993      *
994      * @return Knox URL
995      */
996     public String getKnoxUrl() {
997         return getProperty(SECURITY_USER_KNOX_URL);
998     }
999
1000     /**
1001      * Gets the configured Knox Audiences.
1002      *
1003      * @return Knox audiences
1004      */
1005     public Set<String> getKnoxAudiences() {
1006         final String rawAudiences = getProperty(SECURITY_USER_KNOX_AUDIENCES);
1007         if (StringUtils.isBlank(rawAudiences)) {
1008             return null;
1009         } else {
1010             final String[] audienceTokens = rawAudiences.split(",");
1011             return Stream.of(audienceTokens).map(String::trim).filter(aud -> !StringUtils.isEmpty(aud)).collect(Collectors.toSet());
1012         }
1013     }
1014
1015     /**
1016      * Returns the path to the Knox public key.
1017      *
1018      * @return path to the Knox public key
1019      */
1020     public Path getKnoxPublicKeyPath() {
1021         return Paths.get(getProperty(SECURITY_USER_KNOX_PUBLIC_KEY));
1022     }
1023
1024     /**
1025      * Returns the name of the Knox cookie.
1026      *
1027      * @return name of the Knox cookie
1028      */
1029     public String getKnoxCookieName() {
1030         return getProperty(SECURITY_USER_KNOX_COOKIE_NAME);
1031     }
1032
1033     /**
1034      * Returns true if client certificates are required for REST API. Determined
1035      * if the following conditions are all true:
1036      * <p>
1037      * - login identity provider is not populated
1038      * - Kerberos service support is not enabled
1039      * - openid connect is not enabled
1040      * - knox sso is not enabled
1041      * </p>
1042      *
1043      * @return true if client certificates are required for access to the REST API
1044      */
1045     public boolean isClientAuthRequiredForRestApi() {
1046         return !isLoginIdentityProviderEnabled() && !isKerberosSpnegoSupportEnabled() && !isOidcEnabled() && !isKnoxSsoEnabled();
1047     }
1048
1049     public InetSocketAddress getNodeApiAddress() {
1050
1051         final String rawScheme = getClusterProtocolManagerToNodeApiScheme();
1052         final String scheme = (rawScheme == null) ? "http" : rawScheme;
1053
1054         final String host;
1055         final Integer port;
1056         if ("http".equalsIgnoreCase(scheme)) {
1057             // get host
1058             if (StringUtils.isBlank(getProperty(WEB_HTTP_HOST))) {
1059                 host = "localhost";
1060             } else {
1061                 host = getProperty(WEB_HTTP_HOST);
1062             }
1063             // get port
1064             port = getPort();
1065
1066             if (port == null) {
1067                 throw new RuntimeException(String.format("The %s must be specified if running in a cluster with %s set to false.", WEB_HTTP_PORT, CLUSTER_PROTOCOL_IS_SECURE));
1068             }
1069         } else {
1070             // get host
1071             if (StringUtils.isBlank(getProperty(WEB_HTTPS_HOST))) {
1072                 host = "localhost";
1073             } else {
1074                 host = getProperty(WEB_HTTPS_HOST);
1075             }
1076             // get port
1077             port = getSslPort();
1078
1079             if (port == null) {
1080                 throw new RuntimeException(String.format("The %s must be specified if running in a cluster with %s set to true.", WEB_HTTPS_PORT, CLUSTER_PROTOCOL_IS_SECURE));
1081             }
1082         }
1083
1084         return InetSocketAddress.createUnresolved(host, port);
1085
1086     }
1087
1088     /**
1089      * Returns the database repository path. It simply returns the value
1090      * configured. No directories will be created as a result of this operation.
1091      *
1092      * @return database repository path
1093      * @throws InvalidPathException If the configured path is invalid
1094      */
1095     public Path getDatabaseRepositoryPath() {
1096         return Paths.get(getProperty(REPOSITORY_DATABASE_DIRECTORY));
1097     }
1098
1099     /**
1100      * Returns the flow file repository path. It simply returns the value
1101      * configured. No directories will be created as a result of this operation.
1102      *
1103      * @return database repository path
1104      * @throws InvalidPathException If the configured path is invalid
1105      */
1106     public Path getFlowFileRepositoryPath() {
1107         return Paths.get(getProperty(FLOWFILE_REPOSITORY_DIRECTORY));
1108     }
1109
1110     /**
1111      * Returns the content repository paths. This method returns a mapping of
1112      * file repository name to file repository paths. It simply returns the
1113      * values configured. No directories will be created as a result of this
1114      * operation.
1115      *
1116      * @return file repositories paths
1117      * @throws InvalidPathException If any of the configured paths are invalid
1118      */
1119     public Map<String, Path> getContentRepositoryPaths() {
1120         final Map<String, Path> contentRepositoryPaths = new HashMap<>();
1121
1122         // go through each property
1123         for (String propertyName : getPropertyKeys()) {
1124             // determine if the property is a file repository path
1125             if (StringUtils.startsWith(propertyName, REPOSITORY_CONTENT_PREFIX)) {
1126                 // get the repository key
1127                 final String key = StringUtils.substringAfter(propertyName,
1128                         REPOSITORY_CONTENT_PREFIX);
1129
1130                 // attempt to resolve the path specified
1131                 contentRepositoryPaths.put(key, Paths.get(getProperty(propertyName)));
1132             }
1133         }
1134         return contentRepositoryPaths;
1135     }
1136
1137     /**
1138      * Returns the provenance repository paths. This method returns a mapping of
1139      * file repository name to file repository paths. It simply returns the
1140      * values configured. No directories will be created as a result of this
1141      * operation.
1142      *
1143      * @return the name and paths of all provenance repository locations
1144      */
1145     public Map<String, Path> getProvenanceRepositoryPaths() {
1146         final Map<String, Path> provenanceRepositoryPaths = new HashMap<>();
1147
1148         // go through each property
1149         for (String propertyName : getPropertyKeys()) {
1150             // determine if the property is a file repository path
1151             if (StringUtils.startsWith(propertyName, PROVENANCE_REPO_DIRECTORY_PREFIX)) {
1152                 // get the repository key
1153                 final String key = StringUtils.substringAfter(propertyName,
1154                         PROVENANCE_REPO_DIRECTORY_PREFIX);
1155
1156                 // attempt to resolve the path specified
1157                 provenanceRepositoryPaths.put(key, Paths.get(getProperty(propertyName)));
1158             }
1159         }
1160         return provenanceRepositoryPaths;
1161     }
1162
1163     /**
1164      * Returns the number of claims to keep open for writing. Ideally, this will be at
1165      * least as large as the number of threads that will be updating the repository simultaneously but we don't want
1166      * to get too large because it will hold open up to this many FileOutputStreams.
1167      * <p>
1168      * Default is {@link #DEFAULT_MAX_FLOWFILES_PER_CLAIM}
1169      *
1170      * @return the maximum number of flow files per claim
1171      */
1172     public int getMaxFlowFilesPerClaim() {
1173         try {
1174             return Integer.parseInt(getProperty(MAX_FLOWFILES_PER_CLAIM));
1175         } catch (NumberFormatException nfe) {
1176             return DEFAULT_MAX_FLOWFILES_PER_CLAIM;
1177         }
1178     }
1179
1180     /**
1181      * Returns the maximum size, in bytes, that claims should grow before writing a new file. This means that we won't continually write to one
1182      * file that keeps growing but gives us a chance to bunch together many small files.
1183      * <p>
1184      * Default is {@link #DEFAULT_MAX_APPENDABLE_CLAIM_SIZE}
1185      *
1186      * @return the maximum appendable claim size
1187      */
1188     public String getMaxAppendableClaimSize() {
1189         return getProperty(MAX_APPENDABLE_CLAIM_SIZE, DEFAULT_MAX_APPENDABLE_CLAIM_SIZE);
1190     }
1191
1192     public String getProperty(final String key, final String defaultValue) {
1193         final String value = getProperty(key);
1194         return (value == null || value.trim().isEmpty()) ? defaultValue : value;
1195     }
1196
1197     public String getBoredYieldDuration() {
1198         return getProperty(BORED_YIELD_DURATION, DEFAULT_BORED_YIELD_DURATION);
1199     }
1200
1201     public File getStateManagementConfigFile() {
1202         return new File(getProperty(STATE_MANAGEMENT_CONFIG_FILE, DEFAULT_STATE_MANAGEMENT_CONFIG_FILE));
1203     }
1204
1205     public String getLocalStateProviderId() {
1206         return getProperty(STATE_MANAGEMENT_LOCAL_PROVIDER_ID);
1207     }
1208
1209     public String getClusterStateProviderId() {
1210         return getProperty(STATE_MANAGEMENT_CLUSTER_PROVIDER_ID);
1211     }
1212
1213     public File getEmbeddedZooKeeperPropertiesFile() {
1214         final String filename = getProperty(STATE_MANAGEMENT_ZOOKEEPER_PROPERTIES);
1215         return filename == null ? null : new File(filename);
1216     }
1217
1218     public boolean isStartEmbeddedZooKeeper() {
1219         return Boolean.parseBoolean(getProperty(STATE_MANAGEMENT_START_EMBEDDED_ZOOKEEPER));
1220     }
1221
1222     public boolean isFlowConfigurationArchiveEnabled() {
1223         return Boolean.parseBoolean(getProperty(FLOW_CONFIGURATION_ARCHIVE_ENABLED, DEFAULT_FLOW_CONFIGURATION_ARCHIVE_ENABLED));
1224     }
1225
1226     public String getFlowConfigurationArchiveDir() {
1227         return getProperty(FLOW_CONFIGURATION_ARCHIVE_DIR);
1228     }
1229
1230     public String getFlowElectionMaxWaitTime() {
1231         return getProperty(FLOW_ELECTION_MAX_WAIT_TIME, DEFAULT_FLOW_ELECTION_MAX_WAIT_TIME);
1232     }
1233
1234     public Integer getFlowElectionMaxCandidates() {
1235         return getIntegerProperty(FLOW_ELECTION_MAX_CANDIDATES, null);
1236     }
1237
1238     public String getFlowConfigurationArchiveMaxTime() {
1239         return getProperty(FLOW_CONFIGURATION_ARCHIVE_MAX_TIME, null);
1240     }
1241
1242     public String getFlowConfigurationArchiveMaxStorage() {
1243         return getProperty(FLOW_CONFIGURATION_ARCHIVE_MAX_STORAGE, null);
1244     }
1245
1246     public Integer getFlowConfigurationArchiveMaxCount() {
1247         return getIntegerProperty(FLOW_CONFIGURATION_ARCHIVE_MAX_COUNT, null);
1248     }
1249
1250     public String getVariableRegistryProperties() {
1251         return getProperty(VARIABLE_REGISTRY_PROPERTIES);
1252     }
1253
1254     public Path[] getVariableRegistryPropertiesPaths() {
1255         final List<Path> vrPropertiesPaths = new ArrayList<>();
1256
1257         final String vrPropertiesFiles = getVariableRegistryProperties();
1258         if (!StringUtils.isEmpty(vrPropertiesFiles)) {
1259
1260             final List<String> vrPropertiesFileList = Arrays.asList(vrPropertiesFiles.split(","));
1261
1262             for (String propertiesFile : vrPropertiesFileList) {
1263                 vrPropertiesPaths.add(Paths.get(propertiesFile));
1264             }
1265
1266             return vrPropertiesPaths.toArray(new Path[vrPropertiesPaths.size()]);
1267         } else {
1268             return new Path[]{};
1269         }
1270     }
1271
1272     /**
1273      * Returns the network interface list to use for HTTP. This method returns a mapping of
1274      * network interface property names to network interface names.
1275      *
1276      * @return the property name and network interface name of all HTTP network interfaces
1277      */
1278     public Map<String, String> getHttpNetworkInterfaces() {
1279         final Map<String, String> networkInterfaces = new HashMap<>();
1280
1281         // go through each property
1282         for (String propertyName : getPropertyKeys()) {
1283             // determine if the property is a network interface name
1284             if (StringUtils.startsWith(propertyName, WEB_HTTP_NETWORK_INTERFACE_PREFIX)) {
1285                 // get the network interface property key
1286                 final String key = StringUtils.substringAfter(propertyName,
1287                         WEB_HTTP_NETWORK_INTERFACE_PREFIX);
1288                 networkInterfaces.put(key, getProperty(propertyName));
1289             }
1290         }
1291         return networkInterfaces;
1292     }
1293
1294     /**
1295      * Returns the network interface list to use for HTTPS. This method returns a mapping of
1296      * network interface property names to network interface names.
1297      *
1298      * @return the property name and network interface name of all HTTPS network interfaces
1299      */
1300     public Map<String, String> getHttpsNetworkInterfaces() {
1301         final Map<String, String> networkInterfaces = new HashMap<>();
1302
1303         // go through each property
1304         for (String propertyName : getPropertyKeys()) {
1305             // determine if the property is a network interface name
1306             if (StringUtils.startsWith(propertyName, WEB_HTTPS_NETWORK_INTERFACE_PREFIX)) {
1307                 // get the network interface property key
1308                 final String key = StringUtils.substringAfter(propertyName,
1309                         WEB_HTTPS_NETWORK_INTERFACE_PREFIX);
1310                 networkInterfaces.put(key, getProperty(propertyName));
1311             }
1312         }
1313         return networkInterfaces;
1314     }
1315
1316     public int size() {
1317         return getPropertyKeys().size();
1318     }
1319
1320     public String getProvenanceRepoEncryptionKeyId() {
1321         return getProperty(PROVENANCE_REPO_ENCRYPTION_KEY_ID);
1322     }
1323
1324     /**
1325      * Returns the active provenance repository encryption key if a {@code StaticKeyProvider} is in use.
1326      * If no key ID is specified in the properties file, the default
1327      * {@code nifi.provenance.repository.encryption.key} value is returned. If a key ID is specified in
1328      * {@code nifi.provenance.repository.encryption.key.id}, it will attempt to read from
1329      * {@code nifi.provenance.repository.encryption.key.id.XYZ} where {@code XYZ} is the provided key
1330      * ID. If that value is empty, it will use the default property
1331      * {@code nifi.provenance.repository.encryption.key}.
1332      *
1333      * @return the provenance repository encryption key in hex form
1334      */
1335     public String getProvenanceRepoEncryptionKey() {
1336         String keyId = getProvenanceRepoEncryptionKeyId();
1337         String keyKey = StringUtils.isBlank(keyId) ? PROVENANCE_REPO_ENCRYPTION_KEY : PROVENANCE_REPO_ENCRYPTION_KEY + ".id." + keyId;
1338         return getProperty(keyKey, getProperty(PROVENANCE_REPO_ENCRYPTION_KEY));
1339     }
1340
1341     /**
1342      * Returns a map of keyId -> key in hex loaded from the {@code nifi.properties} file if a
1343      * {@code StaticKeyProvider} is defined. If {@code FileBasedKeyProvider} is defined, use
1344      * {@code CryptoUtils#readKeys()} instead -- this method will return an empty map.
1345      *
1346      * @return a Map of the keys identified by key ID
1347      */
1348     public Map<String, String> getProvenanceRepoEncryptionKeys() {
1349         Map<String, String> keys = new HashMap<>();
1350         List<String> keyProperties = getProvenanceRepositoryEncryptionKeyProperties();
1351
1352         // Retrieve the actual key values and store non-empty values in the map
1353         for (String prop : keyProperties) {
1354             final String value = getProperty(prop);
1355             if (!StringUtils.isBlank(value)) {
1356                 if (prop.equalsIgnoreCase(PROVENANCE_REPO_ENCRYPTION_KEY)) {
1357                     prop = getProvenanceRepoEncryptionKeyId();
1358                 } else {
1359                     // Extract nifi.provenance.repository.encryption.key.id.key1 -> key1
1360                     prop = prop.substring(prop.lastIndexOf(".") + 1);
1361                 }
1362                 keys.put(prop, value);
1363             }
1364         }
1365         return keys;
1366     }
1367
1368     /**
1369      * Returns the whitelisted proxy hostnames (and IP addresses) as a comma-delimited string.
1370      * The hosts have been normalized to the form {@code somehost.com}, {@code somehost.com:port}, or {@code 127.0.0.1}.
1371      * <p>
1372      * Note: Calling {@code NiFiProperties.getProperty(NiFiProperties.WEB_PROXY_HOST)} will not normalize the hosts.
1373      *
1374      * @return the hostname(s)
1375      */
1376     public String getWhitelistedHosts() {
1377         return StringUtils.join(getWhitelistedHostsAsList(), ",");
1378     }
1379
1380     /**
1381      * Returns the whitelisted proxy hostnames (and IP addresses) as a List. The hosts have been normalized to the form {@code somehost.com}, {@code somehost.com:port}, or {@code 127.0.0.1}.
1382      *
1383      * @return the hostname(s)
1384      */
1385     public List<String> getWhitelistedHostsAsList() {
1386         String rawProperty = getProperty(WEB_PROXY_HOST, "");
1387         List<String> hosts = Arrays.asList(rawProperty.split(","));
1388         return hosts.stream()
1389                 .map(this::normalizeHost).filter(host -> !StringUtils.isBlank(host)).collect(Collectors.toList());
1390     }
1391
1392     String normalizeHost(String host) {
1393         if (host == null || host.equalsIgnoreCase("")) {
1394             return "";
1395         } else {
1396             return host.trim();
1397         }
1398     }
1399
1400     /**
1401      * Returns the whitelisted proxy context paths as a comma-delimited string. The paths have been normalized to the form {@code /some/context/path}.
1402      * <p>
1403      * Note: Calling {@code NiFiProperties.getProperty(NiFiProperties.WEB_PROXY_CONTEXT_PATH)} will not normalize the paths.
1404      *
1405      * @return the path(s)
1406      */
1407     public String getWhitelistedContextPaths() {
1408         return StringUtils.join(getWhitelistedContextPathsAsList(), ",");
1409     }
1410
1411     /**
1412      * Returns the whitelisted proxy context paths as a list of paths. The paths have been normalized to the form {@code /some/context/path}.
1413      *
1414      * @return the path(s)
1415      */
1416     public List<String> getWhitelistedContextPathsAsList() {
1417         String rawProperty = getProperty(WEB_PROXY_CONTEXT_PATH, "");
1418         List<String> contextPaths = Arrays.asList(rawProperty.split(","));
1419         return contextPaths.stream()
1420                 .map(this::normalizeContextPath).collect(Collectors.toList());
1421     }
1422
1423     private String normalizeContextPath(String cp) {
1424         if (cp == null || cp.equalsIgnoreCase("")) {
1425             return "";
1426         } else {
1427             String trimmedCP = cp.trim();
1428             // Ensure it starts with a leading slash and does not end in a trailing slash
1429             // There's a potential for the path to be something like bad/path/// but this is semi-trusted data from an admin-accessible file and there are way worse possibilities here
1430             trimmedCP = trimmedCP.startsWith("/") ? trimmedCP : "/" + trimmedCP;
1431             trimmedCP = trimmedCP.endsWith("/") ? trimmedCP.substring(0, trimmedCP.length() - 1) : trimmedCP;
1432             return trimmedCP;
1433         }
1434     }
1435
1436     private List<String> getProvenanceRepositoryEncryptionKeyProperties() {
1437         // Filter all the property keys that define a key
1438         return getPropertyKeys().stream().filter(k ->
1439                 k.startsWith(PROVENANCE_REPO_ENCRYPTION_KEY_ID + ".") || k.equalsIgnoreCase(PROVENANCE_REPO_ENCRYPTION_KEY)
1440         ).collect(Collectors.toList());
1441     }
1442
1443     public Long getDefaultBackPressureObjectThreshold() {
1444         long backPressureCount;
1445         try {
1446             String backPressureCountStr = getProperty(BACKPRESSURE_COUNT);
1447             if (backPressureCountStr == null || backPressureCountStr.trim().isEmpty()) {
1448                 backPressureCount = DEFAULT_BACKPRESSURE_COUNT;
1449             } else {
1450                 backPressureCount = Long.parseLong(backPressureCountStr);
1451             }
1452         } catch (NumberFormatException nfe) {
1453             backPressureCount = DEFAULT_BACKPRESSURE_COUNT;
1454         }
1455         return backPressureCount;
1456     }
1457
1458     public String getDefaultBackPressureDataSizeThreshold() {
1459         return getProperty(BACKPRESSURE_SIZE, DEFAULT_BACKPRESSURE_SIZE);
1460     }
1461
1462     /**
1463      * Creates an instance of NiFiProperties. This should likely not be called
1464      * by any classes outside of the NiFi framework but can be useful by the
1465      * framework for default property loading behavior or helpful in tests
1466      * needing to create specific instances of NiFiProperties. If properties
1467      * file specified cannot be found/read a runtime exception will be thrown.
1468      * If one is not specified no properties will be loaded by default.
1469      *
1470      * @param propertiesFilePath   if provided properties will be loaded from
1471      *                             given file; else will be loaded from System property. Can be null.
1472      * @param additionalProperties allows overriding of properties with the
1473      *                             supplied values. these will be applied after loading from any properties
1474      *                             file. Can be null or empty.
1475      * @return NiFiProperties
1476      */
1477     public static NiFiProperties createBasicNiFiProperties(final String propertiesFilePath, final Map<String, String> additionalProperties) {
1478         final Map<String, String> addProps = (additionalProperties == null) ? Collections.EMPTY_MAP : additionalProperties;
1479         final Properties properties = new Properties();
1480         final String nfPropertiesFilePath = (propertiesFilePath == null)
1481                 ? System.getProperty(NiFiProperties.PROPERTIES_FILE_PATH)
1482                 : propertiesFilePath;
1483         if (nfPropertiesFilePath != null) {
1484             final File propertiesFile = new File(nfPropertiesFilePath.trim());
1485             if (!propertiesFile.exists()) {
1486                 throw new RuntimeException("Properties file doesn't exist \'"
1487                         + propertiesFile.getAbsolutePath() + "\'");
1488             }
1489             if (!propertiesFile.canRead()) {
1490                 throw new RuntimeException("Properties file exists but cannot be read \'"
1491                         + propertiesFile.getAbsolutePath() + "\'");
1492             }
1493             InputStream inStream = null;
1494             try {
1495                 inStream = new BufferedInputStream(new FileInputStream(propertiesFile));
1496                 properties.load(inStream);
1497             } catch (final Exception ex) {
1498                 throw new RuntimeException("Cannot load properties file due to "
1499                         + ex.getLocalizedMessage(), ex);
1500             } finally {
1501                 if (null != inStream) {
1502                     try {
1503                         inStream.close();
1504                     } catch (final Exception ex) {
1505                         /**
1506                          * do nothing *
1507                          */
1508                     }
1509                 }
1510             }
1511         }
1512         addProps.entrySet().stream().forEach((entry) -> {
1513             properties.setProperty(entry.getKey(), entry.getValue());
1514         });
1515         return new NiFiProperties() {
1516             @Override
1517             public String getProperty(String key) {
1518                 return properties.getProperty(key);
1519             }
1520
1521             @Override
1522             public Set<String> getPropertyKeys() {
1523                 return properties.stringPropertyNames();
1524             }
1525         };
1526     }
1527
1528     /**
1529      * This method is used to validate the NiFi properties when the file is loaded
1530      * for the first time. The objective is to stop NiFi startup in case a property
1531      * is not correctly configured and could cause issues afterwards.
1532      */
1533     public void validate() {
1534         // REMOTE_INPUT_HOST should be a valid hostname
1535         String remoteInputHost = getProperty(REMOTE_INPUT_HOST);
1536         if (!StringUtils.isBlank(remoteInputHost) && remoteInputHost.split(":").length > 1) { // no scheme/port needed here (http://)
1537             throw new IllegalArgumentException(remoteInputHost + " is not a correct value for " + REMOTE_INPUT_HOST + ". It should be a valid hostname without protocol or port.");
1538         }
1539         // Other properties to validate...
1540     }
1541 }