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