diff options
author | 2019-03-14 15:06:40 +0530 | |
---|---|---|
committer | 2019-03-18 15:25:23 +0530 | |
commit | be11dee889f5a740d584458b62804e5fd4296e53 (patch) | |
tree | 2cc5e14c29df1a40f8e7bbe3bb08fffa38e023b8 /src/main/java/org/onap | |
parent | d76c2d0f61bfb4373b13fcdb6fc3317467dd19b4 (diff) |
Issue-ID: DCAEGEN2-1055 Generic RestConfCollector
Change-Id: I1800affa2b34cbb7487c0d8411e078adec5a0c48
Signed-off-by: s00370346 <swarup.nayak1@huawei.com>
Diffstat (limited to 'src/main/java/org/onap')
52 files changed, 2676 insertions, 892 deletions
diff --git a/src/main/java/org/onap/dcae/ApplicationException.java b/src/main/java/org/onap/dcae/ApplicationException.java new file mode 100644 index 0000000..60624da --- /dev/null +++ b/src/main/java/org/onap/dcae/ApplicationException.java @@ -0,0 +1,44 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae; + +import org.apache.commons.configuration.ConfigurationException; + +public class ApplicationException extends RuntimeException { + + public ApplicationException(ConfigurationException ex) { + super(ex); + } + + public ApplicationException(String message, Exception ex) { + super(message, ex); + } + + public ApplicationException(Exception ex) { + super(ex); + } + + public ApplicationException(String message) { + super(message); + } +} diff --git a/src/main/java/org/onap/dcae/ApplicationSettings.java b/src/main/java/org/onap/dcae/ApplicationSettings.java new file mode 100644 index 0000000..c7e42c5 --- /dev/null +++ b/src/main/java/org/onap/dcae/ApplicationSettings.java @@ -0,0 +1,208 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae; + +import com.google.common.annotations.VisibleForTesting; +import io.vavr.Function1; +import io.vavr.collection.HashMap; +import io.vavr.collection.List; +import io.vavr.collection.Map; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Iterator; + +/** + * Abstraction over application configuration. + * Its job is to provide easily discoverable (by method names lookup) and type safe access to configuration properties. + */ +public class ApplicationSettings { + + private static final Logger log = LoggerFactory.getLogger(ApplicationSettings.class); + + private final String appInvocationDir; + private final String configurationFileLocation; + private final PropertiesConfiguration properties = new PropertiesConfiguration(); + + + public ApplicationSettings(String[] args, Function1<String[], Map<String, String>> argsParser) { + this(args, argsParser, System.getProperty("user.dir")); + } + + public ApplicationSettings(String[] args, Function1<String[], Map<String, String>> argsParser, String appInvocationDir) { + log.info("New ApplicationSettings........"); + this.appInvocationDir = appInvocationDir; + properties.setDelimiterParsingDisabled(true); + Map<String, String> parsedArgs = argsParser.apply(args); + configurationFileLocation = findOutConfigurationFileLocation(parsedArgs); + loadPropertiesFromFile(); + parsedArgs.filterKeys(k -> !"c".equals(k)).forEach(this::addOrUpdate); + } + + + public void reloadProperties() { + try { + log.info("Reloading Properties ...."); + properties.load(configurationFileLocation); + properties.refresh(); + } catch (ConfigurationException ex) { + log.error("Cannot load properties cause:", ex); + throw new ApplicationException(ex); + } + } + + public void loadPropertiesFromFile() { + try { + properties.load(configurationFileLocation); + Iterator<String> itr = properties.getKeys(); + while (itr.hasNext()) { + String key = itr.next(); + log.info(" Key " + key + " value" + properties.getString(key)); + } + } catch (ConfigurationException ex) { + log.error("Cannot load properties cause:", ex); + throw new ApplicationException(ex); + } + } + + + public boolean authorizationEnabled() { + return properties.getInt("collector.header.authflag", 0) > 0; + } + + private String findOutConfigurationFileLocation(Map<String, String> parsedArgs) { + return prependWithUserDirOnRelative(parsedArgs.get("c").getOrElse("etc/collector.properties")); + } + + public Path configurationFileLocation() { + return Paths.get(configurationFileLocation); + } + + public int maximumAllowedQueuedEvents() { + return properties.getInt("collector.rcc.inputQueue.maxPending", 1024 * 4); + } + + public int httpPort() { + return properties.getInt("collector.rcc.service.port", 8686); + } + + public int httpsPort() { + return properties.getInt("collector.rcc.service.secure.port", 8687); + } + + + public boolean httpsEnabled() { + return httpsPort() > 0; + } + + public String rcc_keystorePasswordFileLocation() { + return prependWithUserDirOnRelative(properties.getString("collector.keystore.passwordfile", "etc/rcc_passwordfile")); + } + + public String rcc_keystoreFileLocation() { + return prependWithUserDirOnRelative(properties.getString("collector.keystore.file.location", "etc/keystore")); + } + + public String keystorePasswordFileLocation() { + return prependWithUserDirOnRelative(properties.getString("collector.rcc.keystore.passwordfile", "etc/passwordfile")); + } + + public String keystoreFileLocation() { + return prependWithUserDirOnRelative(properties.getString("collector.rcc.keystore.file.location", "etc/sdnc.p12")); + } + + public boolean clientTlsAuthenticationEnabled() { + return httpsEnabled() && properties.getInt("collector.rcc.service.secure.clientauth", 0) > 0; + } + + public Map<String, String> validAuthorizationCredentials() { + return prepareUsersMap(properties.getString("collector.header.authlist", null)); + } + + private Map<String, String> prepareUsersMap(@Nullable String allowedUsers) { + return allowedUsers == null ? HashMap.empty() + : List.of(allowedUsers.split("\\|")) + .map(t -> t.split(",")) + .toMap(t -> t[0].trim(), t -> t[1].trim()); + } + + public String keystoreAlias() { + return properties.getString("collector.rcc.keystore.alias", "tomcat"); + } + + public String truststorePasswordFileLocation() { + return prependWithUserDirOnRelative(properties.getString("collector.rcc.truststore.passwordfile", "etc/trustpasswordfile")); + } + + public String truststoreFileLocation() { + return prependWithUserDirOnRelative(properties.getString("collector.rcc.truststore.file.location", "etc/truststore.onap.client.jks")); + } + + public String rcc_policy() { + return properties.getString("rcc_policy", ""); + } + + public String dMaaPConfigurationFileLocation() { + return prependWithUserDirOnRelative(properties.getString("collector.dmaapfile", "etc/DmaapConfig.json")); + } + + public String dMaaPStreamsMapping() { + return properties.getString("collector.rcc.dmaap.streamid", null); + } + + private void updateProperty(String key, String value) { + if (properties.containsKey(key)) { + properties.setProperty(key, value); + log.info("Retrives property: " + key + "Value " + value); + } else { + properties.addProperty(key, value); + } + } + + public void addOrUpdate(String key, String value) { + if (properties.containsKey(key)) { + properties.setProperty(key, value); + } else { + properties.addProperty(key, value); + } + } + + + private String prependWithUserDirOnRelative(String filePath) { + if (!Paths.get(filePath).isAbsolute()) { + filePath = Paths.get(appInvocationDir, filePath).toString(); + } + return filePath; + } + + @VisibleForTesting + String getStringDirectly(String key) { + return properties.getString(key); + } +} + diff --git a/src/main/java/org/onap/dcae/CLIUtils.java b/src/main/java/org/onap/dcae/CLIUtils.java new file mode 100644 index 0000000..eeab465 --- /dev/null +++ b/src/main/java/org/onap/dcae/CLIUtils.java @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae; + +import io.vavr.collection.Map; + +import java.util.HashMap; + +public class CLIUtils { + + public static Map<String, String> processCmdLine(String[] args) { + final java.util.Map<String, String> map = new HashMap<>(); + + String argumentName = null; + + for (String arg : args) { + if (isArgumentName(arg)) { + argumentName = resolveArgumentName(arg); + map.put(argumentName, ""); + } else { + map.put(argumentName, arg); + } + } + + return io.vavr.collection.HashMap.ofAll(map); + } + + private static String resolveArgumentName(String arg) { + return arg.substring(1); + } + + private static boolean isArgumentName(String arg) { + return arg.startsWith("-"); + } +} diff --git a/src/main/java/org/onap/dcae/RestConfCollector.java b/src/main/java/org/onap/dcae/RestConfCollector.java new file mode 100644 index 0000000..1812d23 --- /dev/null +++ b/src/main/java/org/onap/dcae/RestConfCollector.java @@ -0,0 +1,189 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae; + +import io.vavr.collection.Map; +import org.json.JSONArray; +import org.json.JSONObject; +import org.onap.dcae.common.EventData; +import org.onap.dcae.common.EventProcessor; +import org.onap.dcae.common.publishing.DMaaPConfigurationParser; +import org.onap.dcae.common.publishing.EventPublisher; +import org.onap.dcae.common.publishing.PublisherConfig; +import org.onap.dcae.controller.AccessController; +import org.onap.dcae.controller.ConfigLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; + +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.concurrent.*; + +@SpringBootApplication(exclude = {GsonAutoConfiguration.class, SecurityAutoConfiguration.class}) +public class RestConfCollector { + private static final Logger oplog = LoggerFactory.getLogger("org.onap.dcae.common.output"); + private static final int MAX_THREADS = 20; + private static Logger log = LoggerFactory.getLogger(RestConfCollector.class); + public static LinkedBlockingQueue<EventData> fProcessingInputQueue; + private static ApplicationSettings properties; + private static ConfigurableApplicationContext context; + private static ConfigLoader configLoader; + private static SpringApplication app; + private static ScheduledFuture<?> scheduleFeatures; + private static ExecutorService executor; + private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; + private static EventPublisher eventPublisher; + private static EventProcessor eventProcessor; + + /* List of Controllers */ + private static java.util.Map<String, AccessController> controllerStore = new ConcurrentHashMap<>(); + + + public static void main(String[] args) { + oplog.info("RestconfController starting"); + app = new SpringApplication(RestConfCollector.class); + properties = new ApplicationSettings(args, CLIUtils::processCmdLine); + scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); + init(); + app.setAddCommandLineProperties(true); + context = app.run(); + configLoader.updateConfig(); + controllerConfig(properties); + oplog.info("RestConfController running ....."); + } + + + public static void restartApplication() { + Thread thread = new Thread(() -> { + controllerConfigCleanup(); + context.close(); + properties.reloadProperties(); + scheduleFeatures.cancel(true); + init(); + controllerConfig(properties); + context = SpringApplication.run(RestConfCollector.class); + }); + thread.setDaemon(false); + thread.start(); + } + + + private static void init() { + fProcessingInputQueue = new LinkedBlockingQueue<>(properties.maximumAllowedQueuedEvents()); + createConfigLoader(); + createSchedulePoolExecutor(); + createExecutors(); + } + + private static Map<String, PublisherConfig> getDmapConfig() { + return DMaaPConfigurationParser. + parseToDomainMapping(Paths.get(properties.dMaaPConfigurationFileLocation())).get(); + } + + @Bean + @Lazy + public ApplicationSettings applicationSettings() { + return properties; + } + + @Bean + public LinkedBlockingQueue<EventData> inputQueue() { + return fProcessingInputQueue; + } + + public static java.util.Map<String, String[]> parseStreamIdToStreamHashMapping(String streamId) { + + java.util.Map<String, String[]> streamidHash = new HashMap<>(); + String[] list = streamId.split("\\|"); + for (String aList : list) { + String domain = aList.split("=")[0]; + String[] streamIdList = aList.substring(aList.indexOf('=') + 1).split(","); + streamidHash.put(domain, streamIdList); + oplog.info("adding domain " + domain + " count" + streamIdList.length); + } + return streamidHash; + } + + private static void controllerConfig(ApplicationSettings properties) { + oplog.info("Policy received " + properties.rcc_policy()); + if (!properties.rcc_policy().equals("")) { + JSONArray contollers = new JSONArray(properties.rcc_policy()); + for (int i = 0; i < contollers.length(); i++) { + JSONObject controller = contollers.getJSONObject(i); + oplog.info(" object " + controller.toString()); + AccessController acClr = new AccessController(controller, + properties); + controllerStore.put(controller.get("controller_name").toString(), acClr); + oplog.info("Activating controller " + acClr.getCfgInfo().getController_name()); + acClr.activate(); + } + } + } + + private static void controllerConfigCleanup() { + controllerStore.clear(); + } + + public static void handleEvents(EventData ev) throws Exception { + if (!fProcessingInputQueue.offer(ev)) { + throw new Exception(); + } + log.info("RestConfCollector.handleEvents:EVENTS has been published successfully!"); + } + + private static void createConfigLoader() { + log.info("dMaaPConfigurationFileLocation " + properties.dMaaPConfigurationFileLocation() + " " + properties.configurationFileLocation()); + + configLoader = ConfigLoader.create(getEventPublisher()::reconfigure, + Paths.get(properties.dMaaPConfigurationFileLocation()), + properties.configurationFileLocation()); + } + + private static EventPublisher getEventPublisher() { + return EventPublisher.createPublisher(oplog, getDmapConfig()); + } + + private static void createSchedulePoolExecutor() { + scheduleFeatures = scheduledThreadPoolExecutor.scheduleAtFixedRate(configLoader::updateConfig, + 10, + 10, + TimeUnit.MINUTES); + } + + private static void createExecutors() { + eventPublisher = EventPublisher.createPublisher(oplog, getDmapConfig()); + eventProcessor = new EventProcessor(eventPublisher, + parseStreamIdToStreamHashMapping(properties.dMaaPStreamsMapping())); + + executor = Executors.newFixedThreadPool(MAX_THREADS); + for (int i = 0; i < MAX_THREADS; ++i) { + executor.execute(eventProcessor); + } + } +} diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/DataChangeEventListener.java b/src/main/java/org/onap/dcae/collectors/restconf/common/DataChangeEventListener.java deleted file mode 100755 index 98bb74a..0000000 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/DataChangeEventListener.java +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf - * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.dcae.collectors.restconf.common; - -import org.glassfish.jersey.media.sse.EventListener; -import org.glassfish.jersey.media.sse.InboundEvent; -import org.json.JSONArray; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DataChangeEventListener implements EventListener { - private static final Logger log = LoggerFactory.getLogger(DataChangeEventListener.class); - private RestConfContext ctx; - - public DataChangeEventListener(RestConfContext ctx) { - this.ctx = ctx; - } - - @Override - public void onEvent(InboundEvent event) { - JSONArray jsonArrayMod; - log.info("On SSE Event is received"); - String s = event.readData(); - JSONObject jsonObj = new JSONObject(s); - jsonArrayMod = new JSONArray().put(jsonObj); - try { - RestConfProc.handleEvents(jsonArrayMod); - } catch (Exception e) { - log.error("Error in DataChangeEventListener ", e.getMessage()); - } - } -} diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/EventProcessor.java b/src/main/java/org/onap/dcae/collectors/restconf/common/EventProcessor.java deleted file mode 100755 index 763cece..0000000 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/EventProcessor.java +++ /dev/null @@ -1,88 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf - * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.dcae.collectors.restconf.common; - - -import org.json.JSONObject; -import org.onap.dcae.collectors.restconf.common.event.publishing.EventPublisher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -public class EventProcessor implements Runnable { - private static final Logger log = LoggerFactory.getLogger(EventProcessor.class); - - static Map<String, String[]> streamidHash = new HashMap<>(); - public JSONObject event; - private EventPublisher eventPublisher; - - public EventProcessor(EventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; - streamidHash = parseStreamIdToStreamHashMapping(new RestConfProc().streamID); - } - - private Map<String, String[]> parseStreamIdToStreamHashMapping(String streamId) { - Map<String, String[]> streamidHash = new HashMap<>(); - String[] list = streamId.split("\\|"); - for (String aList : list) { - String domain = aList.split("=")[0]; - String[] streamIdList = aList.substring(aList.indexOf('=') + 1).split(","); - streamidHash.put(domain, streamIdList); - } - return streamidHash; - } - - @Override - public void run() { - try { - - while (true) { - event = RestConfProc.fProcessingInputQueue.take(); - // As long as the producer is running we remove elements from - // the queue. - log.info("QueueSize:" + RestConfProc.fProcessingInputQueue.size() + "\tEventProcessor\tRemoving element: " + - event); - String[] streamIdList = streamidHash.get("route"); - log.debug("streamIdList:" + Arrays.toString(streamIdList)); - - if (streamIdList.length == 0) { - log.error("No StreamID defined for publish - Message dropped" + event); - } else { - sendEventsToStreams(streamIdList); - } - log.debug("Event published" + event); - } - } catch (Exception e) { - log.error("EventProcessor InterruptedException" + e.getMessage()); - Thread.currentThread().interrupt(); - } - } - - private void sendEventsToStreams(String[] streamIdList) { - for (String aStreamIdList : streamIdList) { - log.info("Invoking publisher for streamId:" + aStreamIdList); - eventPublisher.sendEvent(event, aStreamIdList); - } - } -} diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfCollector.java b/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfCollector.java deleted file mode 100755 index 508cf66..0000000 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfCollector.java +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf - * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.dcae.collectors.restconf.common; - -import com.att.nsa.cmdLine.NsaCommandLineUtil; -import com.att.nsa.drumlin.service.framework.DrumlinServlet; -import com.att.nsa.drumlin.till.nv.impl.nvPropertiesFile; -import com.att.nsa.drumlin.till.nv.impl.nvReadableStack; -import com.att.nsa.drumlin.till.nv.impl.nvReadableTable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.URL; -import java.util.Map; - -public class RestConfCollector { - - public static final Logger eplog = LoggerFactory.getLogger("org.onap.restconf.common.error"); - - public static void main(String[] args) { - try { - final Map<String, String> argMap = NsaCommandLineUtil.processCmdLine(args, true); - final String config = NsaCommandLineUtil.getSetting(argMap, Constants.KCONFIG, "collector.properties"); - final URL settingStream = DrumlinServlet.findStream(config, RestConfCollector.class); - - final nvReadableStack settings = new nvReadableStack(); - settings.push(new nvPropertiesFile(settingStream)); - settings.push(new nvReadableTable(argMap)); - - RestConfProc restConfProc = new RestConfProc(settings); - Map<String, String> paraMap = restConfProc.getParaMap(); - String restApiURL = paraMap.get(Constants.KSETTING_REST_API_URL); - String sseEventsURL = paraMap.get(Constants.KSETTING_SSE_CONNECT_URL); - String trustStoreFileName = paraMap.get(Constants.KSETTING_TRUST_STORE_FILENAME); - String keyStoreFileName = paraMap.get(Constants.KSETTING_KEY_STORE_FILENAME); - String[] listRestApiURL = restApiURL.split(";"); - String[] listSseEventsURL = sseEventsURL.split(";"); - String[] listTrustStoreFileName = trustStoreFileName.split(";"); - String[] listKeyStoreFileName = keyStoreFileName.split(";"); - for (int i = 0; i < listRestApiURL.length; i++) { - paraMap.put(Constants.KSETTING_REST_API_URL, "https://" + listRestApiURL[i] + - "/restconf/operations/ietf-subscribed-notifications:establish-subscription"); - paraMap.put(Constants.KSETTING_SSE_CONNECT_URL, listSseEventsURL[i]); - paraMap.put(Constants.KSETTING_TRUST_STORE_FILENAME, listTrustStoreFileName[i]); - paraMap.put(Constants.KSETTING_KEY_STORE_FILENAME, listKeyStoreFileName[i]); - restConfProc.establishSubscription(paraMap, restConfProc.getCtx(), listRestApiURL[i]); - } - - } catch (Exception e) { - RestConfCollector.eplog.error("Fatal error during application startup", e); - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfProc.java b/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfProc.java deleted file mode 100755 index cfebe3b..0000000 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfProc.java +++ /dev/null @@ -1,336 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf - * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.dcae.collectors.restconf.common; - -import com.att.nsa.drumlin.till.nv.rrNvReadable; -import org.glassfish.jersey.media.sse.EventSource; -import org.glassfish.jersey.media.sse.SseFeature; -import org.json.JSONArray; -import org.json.JSONObject; -import org.onap.dcae.collectors.restconf.common.event.publishing.DMaaPConfigurationParser; -import org.onap.dcae.collectors.restconf.common.event.publishing.EventPublisher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.HttpHeaders; -import java.nio.file.Paths; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.Base64; - -import static org.onap.dcae.collectors.restconf.common.RestapiCallNodeUtil.getParameters; -import static org.onap.dcae.collectors.restconf.common.RestapiCallNodeUtil.addAuthType; - -public class RestConfProc { - - private static final Logger log = LoggerFactory.getLogger(RestConfProc.class); - - public static String format; - - private static RestConfContext ctx = new RestConfContext(); - - private static final Logger oplog = LoggerFactory.getLogger("org.onap.restconf.common.output"); - - private Map<String, PersistentConnection> runnableInfo = new ConcurrentHashMap<>(); - - private final Map<String, String> paraMap = new HashMap<>(); - private static String cambriaConfigFile; - - public static LinkedBlockingQueue<JSONObject> fProcessingInputQueue; - - public static String streamID; - private ExecutorService executor = Executors.newCachedThreadPool(); - - public RestConfProc() { - } - - private void parseInputParameters(rrNvReadable settings) { - String tempFileName; - String restApiUrl; - String httpMetthod; - String respPrefix; - String skipSending; - String sseConnectUrl; - String restapiUser; - String restapiPassword; - String trustStoreFileName; - String trustStorePassword; - String keyStoreFileName; - String keyStorePassword; - String[] currentConfigFile; - - currentConfigFile = settings.getStrings(Constants.KSETTING_DMAAPCONFIGS, Constants.KDEFAULT_DMAAPCONFIGS); - cambriaConfigFile = currentConfigFile[0]; - - tempFileName = settings.getString(Constants.KDEFAULT_TEMP_FILENAME, null); - restApiUrl = settings.getString(Constants.KSETTING_REST_API_URL, null); - httpMetthod = settings.getString(Constants.KSETTING_HTTP_METHOD, null); - respPrefix = settings.getString(Constants.KSETTING_RESP_PREFIX, null); - skipSending = settings.getString(Constants.KSETTING_SKIP_SENDING, null); - sseConnectUrl = settings.getString(Constants.KSETTING_SSE_CONNECT_URL, null); - restapiUser = settings.getString(Constants.KSETTING_UNAME, null); - restapiPassword = settings.getString(Constants.KSETTING_PASSWORD, null); - trustStoreFileName = settings.getString(Constants.KSETTING_TRUST_STORE_FILENAME, null); - trustStorePassword = settings.getString(Constants.KSETTING_TRUST_STORE_PASSWORD, null); - keyStoreFileName = settings.getString(Constants.KSETTING_KEY_STORE_FILENAME, null); - keyStorePassword = settings.getString(Constants.KSETTING_KEY_STORE_PASSWORD, null); - format = settings.getString(Constants.KSETTING_FORMAT, null); - streamID = "route=route_failure"; - - paraMap.put(Constants.KDEFAULT_TEMP_FILENAME, tempFileName); - paraMap.put(Constants.KSETTING_REST_API_URL, restApiUrl); - paraMap.put(Constants.KSETTING_HTTP_METHOD, httpMetthod); - paraMap.put(Constants.KSETTING_RESP_PREFIX, respPrefix); - paraMap.put(Constants.KSETTING_SKIP_SENDING, skipSending); - paraMap.put(Constants.KSETTING_SSE_CONNECT_URL, sseConnectUrl); - paraMap.put(Constants.KSETTING_FORMAT, format); - paraMap.put(Constants.KSETTING_UNAME, restapiUser); - paraMap.put(Constants.KSETTING_PASSWORD, restapiPassword); - paraMap.put(Constants.KSETTING_TRUST_STORE_FILENAME, trustStoreFileName); - paraMap.put(Constants.KSETTING_TRUST_STORE_PASSWORD, trustStorePassword); - paraMap.put(Constants.KSETTING_KEY_STORE_FILENAME, keyStoreFileName); - paraMap.put(Constants.KSETTING_KEY_STORE_PASSWORD, keyStorePassword); - - ctx.setAttribute("prop.encoding-json", "encoding-json"); - ctx.setAttribute("restapi-result.response-code", "200"); - ctx.setAttribute("restapi-result.ietf-subscribed-notifications:output.identifier", "100"); - } - - public RestConfProc(rrNvReadable settings) { - - parseInputParameters(settings); - - fProcessingInputQueue = new LinkedBlockingQueue<>(Constants.KDEFAULT_MAXQUEUEDEVENTS); - - EventProcessor ep = new EventProcessor(EventPublisher.createPublisher(oplog, - DMaaPConfigurationParser - .parseToDomainMapping(Paths.get(cambriaConfigFile)) - .get())); - ExecutorService executor = Executors.newFixedThreadPool(20); - for (int i = 0; i < 20; ++i) { - executor.execute(ep); - } - } - - /** - * To establish a subscription with controller by sending HTTP request - * - * @param paramMap holds the input configuration - * @param ctx restconf context - * @param url url to send subscription request - * @throws Exception exception - */ - public void establishSubscription(Map<String, String> paramMap, - RestConfContext ctx, - String url) throws Exception { - - RestapiCallNode restApiCallNode = new RestapiCallNode(); - - Map<String, String> params = new HashMap<>(); - params.put("restapiUrl", "https://" + url + "/controller/v2/tokens"); - params.put("httpMethod", "post"); - params.put("templateFileName", "./etc/access-token.json"); - params.put("skipSending", "false"); - params.put("format", "json"); - params.put("restapiUser", "test123"); - params.put("restapiPassword", "Changeme_123"); - params.put(Constants.KSETTING_TRUST_STORE_FILENAME, - paramMap.get(Constants.KSETTING_TRUST_STORE_FILENAME)); - params.put(Constants.KSETTING_TRUST_STORE_PASSWORD, "adminadmin"); - params.put(Constants.KSETTING_KEY_STORE_FILENAME, - paramMap.get(Constants.KSETTING_KEY_STORE_FILENAME)); - params.put(Constants.KSETTING_KEY_STORE_PASSWORD, "adminadmin"); - - String httpResponse = null; - try { - restApiCallNode.sendRequest(params, ctx, null); - httpResponse = ctx.getAttribute("httpResponse"); - JSONObject jsonObj = new JSONObject(httpResponse); - JSONObject data = jsonObj.getJSONObject("data"); - String tokenId = data.get("token_id").toString(); - paramMap.put("customHttpHeaders", "X-ACCESS-TOKEN=" + tokenId); - paramMap.put("TokenId", tokenId); - } catch (Exception e) { - log.info("Access token is not supported" + e.getMessage()); - log.info("http response" + httpResponse); - } - - restApiCallNode.sendRequest(paramMap, ctx, null); - - establishPersistentConnection(paramMap, ctx); - } - - /** - * To establish persistent connection after receiving successful subscription response from controller - * - * @param paramMap holds the input configuration - * @param ctx restconf context - */ - public void establishPersistentConnection(Map<String, String> paramMap, RestConfContext ctx) { - - // check whether response is ok - if (ctx.getAttribute(Constants.RESPONSE_CODE).equals(Constants.RESPONSE_CODE_200)) { - - String id = ctx.getAttribute(Constants.OUTPUT_IDENTIFIER); - - String url = paramMap.get(Constants.KSETTING_SSE_CONNECT_URL); - - PersistentConnection connection = new PersistentConnection(url, ctx, paramMap); - runnableInfo.put(id, connection); - executor.execute(connection); - } else { - // error response is already updated in ctx - log.info("Failed to subscribe"); - } - } - - /** - * Get input parameter map - * - * @return input parameters map - */ - public Map<String, String> getParaMap() { - return paraMap; - } - - - /** - * Get restConf context which has information about message encoding type - * - * @return restconf context - */ - public RestConfContext getCtx() { - return ctx; - } - - public class PersistentConnection implements Runnable { - private String url; - private RestConfContext ctx; - private Map<String, String> paramMap; - private volatile boolean running = true; - - public PersistentConnection(String url, RestConfContext ctx, Map<String, String> paramMap) { - this.url = url; - this.ctx = ctx; - this.paramMap = paramMap; - } - - @Override - public void run() { - Parameters p = null; - try { - p = getParameters(paramMap); - } catch (Exception e) { - log.error("Exception occured!", e); - Thread.currentThread().interrupt(); - } - - Client client = ignoreSslClient().register(SseFeature.class); - WebTarget target = addAuthType(client, p).target(url); - String token = paramMap.get("TokenId"); - String headerName = "X-ACCESS-TOKEN"; - if (token == null) { - headerName = HttpHeaders.AUTHORIZATION; - if(null!=p) { - token = getAuthorizationToken(p.restapiUser, p.restapiPassword); - } - } - AdditionalHeaderWebTarget newTarget = new AdditionalHeaderWebTarget(target, token, headerName); - EventSource eventSource = EventSource.target(newTarget).build(); - eventSource.register(new DataChangeEventListener(ctx)); - eventSource.open(); - log.debug("Connected to SSE source"); - while (running) { - try { - log.debug("SSE state " + eventSource.isOpen()); - Thread.sleep(5000); - } catch (InterruptedException ie) { - log.debug("Exception: " + ie.getMessage()); - Thread.currentThread().interrupt(); - } - } - eventSource.close(); - log.info("Closed connection to SSE source"); - } - } - - private String getAuthorizationToken(String userName, String password) { - return "Basic " + Base64.getEncoder().encodeToString(( - userName + ":" + password).getBytes()); - } - - /** - * To process the array of events which are received from controller - * - * @param a JSONArray - * @throws Exception exception - */ - public static void handleEvents(JSONArray a) throws Exception { - for (int i = 0; i < a.length(); i++) { - if (!fProcessingInputQueue.offer(a.getJSONObject(i))) { - throw new Exception(); - } - } - log.debug("RestConfCollector.handleEvents:EVENTS has been published successfully!"); - } - - private Client ignoreSslClient() { - SSLContext sslcontext = null; - - try { - sslcontext = SSLContext.getInstance("TLS"); - sslcontext.init(null, new TrustManager[]{new X509TrustManager() { - @Override - public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { - } - - @Override - public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - } }, new java.security.SecureRandom()); - } catch (NoSuchAlgorithmException | KeyManagementException e) { - throw new IllegalStateException(e); - } - - return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build(); - } -} - - diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RetryPolicy.java b/src/main/java/org/onap/dcae/collectors/restconf/common/RetryPolicy.java deleted file mode 100755 index 6c62394..0000000 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RetryPolicy.java +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf - * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.dcae.collectors.restconf.common; - -public class RetryPolicy { - private String[] hostnames; - private Integer maximumRetries; - - public Integer getMaximumRetries() { - return maximumRetries; - } - - public String getNextHostName(String uri) throws RetryException { - Integer position = null; - - for (int i = 0; i < hostnames.length; i++) { - if (uri.contains(hostnames[i])) { - position = i; - break; - } - } - - if (position == null) { - throw new RetryException("No match found for the provided uri[" + uri + "] " + - "so the next host name could not be retreived"); - } - position++; - - if (position > hostnames.length - 1) { - position = 0; - } - return hostnames[position]; - } - - public RetryPolicy(String[] hostnames, Integer maximumRetries) { - this.hostnames = hostnames; - this.maximumRetries = maximumRetries; - } - -} diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/AdditionalHeaderWebTarget.java b/src/main/java/org/onap/dcae/common/AdditionalHeaderWebTarget.java index e814778..fe61155 100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/AdditionalHeaderWebTarget.java +++ b/src/main/java/org/onap/dcae/common/AdditionalHeaderWebTarget.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; @@ -26,7 +26,7 @@ import javax.ws.rs.core.UriBuilder; import java.net.URI; import java.util.Map; -class AdditionalHeaderWebTarget implements WebTarget { +public class AdditionalHeaderWebTarget implements WebTarget { private WebTarget base; private String token; private String headerName; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/AnyNode.java b/src/main/java/org/onap/dcae/common/AnyNode.java index 860fecc..8980f1b 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/AnyNode.java +++ b/src/main/java/org/onap/dcae/common/AnyNode.java @@ -1,8 +1,9 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018 Nokia Networks Intellectual Property. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +18,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import io.vavr.collection.List; import io.vavr.collection.Set; @@ -26,15 +26,19 @@ import io.vavr.control.Option; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.stream.StreamSupport; import static io.vavr.API.Set; +/** + * This class is a wrapper for 2 most used entities of org.json lib: JSONArray and JSONObject and comprises utility + * methods for fast access of json structures without need to explicitly coerce between them. While using this, bear in + * mind it does not contain exception handling - it is assumed that when using, the parsed json structure is known. + * + * @author koblosz + */ public class AnyNode { - private static final Logger log = LoggerFactory.getLogger(AnyNode.class); private Object obj; @@ -46,46 +50,18 @@ public class AnyNode { return new AnyNode(new JSONObject(content)); } - /** - * Returns key set of underlying object. It is assumed that underlying object is of type org.json.JSONObject. - * - * @return key set of underlying objects - */ public Set<String> keys() { return Set(asJsonObject().keySet().toArray(new String[]{})); } - /** - * Returns value associated with specified key wrapped with AnyValue object. It is assumed that this is of type - * org.json.JSONObject. - * - * @param key for querying value from jsonobject - * @return value associated with specified key - */ public AnyNode get(String key) { return new AnyNode(asJsonObject().get(key)); } - /** - * Returns string representation of this. If it happens to have null, the value is treated as - * org.json.JSONObject.NULL and "null" string is returned then. - * - * @return string representation of this - */ public String toString() { return this.obj.toString(); } - /** - * Returns optional of object under specified key, wrapped with AnyNode object. - * If underlying object is not of type org.json.JSONObject - * or underlying object has no given key - * or given key is null - * then Optional.empty will be returned. - * - * @param key for querying value from AnyNode object - * @return optional of object under specified key - */ public Option<AnyNode> getAsOption(String key) { try { AnyNode value = get(key); @@ -94,39 +70,20 @@ public class AnyNode { } return Option.some(value); } catch (JSONException ex) { - log.error(ex.getMessage(), ex); return Option.none(); } } - /** - * Converts underlying object to map representation with map values wrapped with AnyNode object. It is assumed that - * underlying object is of type org.json.JSONObject. - * - * @return converts underlying object to map representation - */ public List<AnyNode> toList() { return List.ofAll(StreamSupport.stream(((JSONArray) this.obj).spliterator(), false).map(AnyNode::new)); } - /** - * Checks if specified key is present in this. It is assumed that this is of type JSONObject. - * - * @param key is used to check presence in anynode object - * @return true if specified key is present in this - */ public boolean has(String key) { return !getAsOption(key).isEmpty(); } - /** - * Returns as JSONObject. - * - * @return jsonobject - */ private JSONObject asJsonObject() { return (JSONObject) this.obj; } - } diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/AuthType.java b/src/main/java/org/onap/dcae/common/AuthType.java index 2072631..d87321e 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/AuthType.java +++ b/src/main/java/org/onap/dcae/common/AuthType.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; public enum AuthType { NONE, BASIC, DIGEST, OAUTH, Unspecified; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/Constants.java b/src/main/java/org/onap/dcae/common/Constants.java index 5f8925d..1fe5624 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/Constants.java +++ b/src/main/java/org/onap/dcae/common/Constants.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,25 +18,29 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; public class Constants { public static final String KDEFAULT_TEMP_FILENAME = "templateFileName"; + public static final String KDEFAULT_REQUESTBODY = "requestBody"; public static final String KSETTING_REST_API_URL = "restapiUrl"; + public static final String KSETTING_REST_UNAME = "restapiUser"; + public static final String KSETTING_REST_PASSWORD = "restapiPassword"; public static final String KSETTING_HTTP_METHOD = "httpMethod"; public static final String KSETTING_RESP_PREFIX = "responsePrefix"; public static final String KSETTING_SKIP_SENDING = "skipSending"; public static final String KSETTING_FORMAT = "format"; - public static final String KSETTING_DMAAPCONFIGS = "collector.dmaapfile"; - public static final String[] KDEFAULT_DMAAPCONFIGS = new String[]{"./etc/DmaapConfig.json"}; public static final String KSETTING_SSE_CONNECT_URL = "sseConnectURL"; - public static final int KDEFAULT_MAXQUEUEDEVENTS = 1024 * 4; - public static final String RESPONSE_CODE = "restapi-result.response-code"; - public static final String OUTPUT_IDENTIFIER = "restapi-result.ietf-subscribed-notifications:output.identifier"; - public static final String RESPONSE_CODE_200 = "200"; - public static final String KCONFIG = "c"; - public static final String KSETTING_UNAME = "restapiUser"; - public static final String KSETTING_PASSWORD = "restapiPassword"; + public static final String KSETTING_AUTH_TYPE = "authType"; + public static final String KSETTING_CONTENT_TYPE = "contentType"; + public static final String KSETTING_OAUTH_CONSUMER_KEY = "oAuthConsumerKey"; + public static final String KSETTING_OAUTH_CONSUMER_SECRET = "oAuthConsumerSecret"; + public static final String KSETTING_OAUTH_SIGNATURE_METHOD = "oAuthSignatureMethod"; + public static final String KSETTING_OAUTH_VERSION = "oAuthVersion"; + public static final String KSETTING_TOKENID = "tokenId"; + public static final String KSETTING_CUSTOMHTTP_HEADER = "customHttpHeaders"; + public static final String KSETTING_DUMP_HEADER = "dumpHeaders"; + public static final String KSETTING_RETURN_REQUEST_PAYLOAD = "returnRequestPayload"; public static final String KSETTING_TRUST_STORE_FILENAME = "trustStoreFileName"; public static final String KSETTING_TRUST_STORE_PASSWORD = "trustStorePassword"; public static final String KSETTING_KEY_STORE_FILENAME = "keyStoreFileName"; diff --git a/src/main/java/org/onap/dcae/common/DataChangeEventListener.java b/src/main/java/org/onap/dcae/common/DataChangeEventListener.java new file mode 100755 index 0000000..6e13f73 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/DataChangeEventListener.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.restconf + * ================================================================================ + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.common; + +import org.glassfish.jersey.media.sse.EventListener; +import org.glassfish.jersey.media.sse.InboundEvent; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.onap.dcae.RestConfCollector; +import org.onap.dcae.controller.PersistentEventConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DataChangeEventListener implements EventListener { + private static final Logger log = LoggerFactory.getLogger(DataChangeEventListener.class); + private PersistentEventConnection conn; + + public DataChangeEventListener(PersistentEventConnection conn) { + this.conn = conn; + } + + @Override + public void onEvent(InboundEvent event) { + try { + log.info("SSE Event is received"); + String s = event.readData(); + jsonType type = isJSONValid(s); + if (type == jsonType.OBJECT) { + JSONObject jsonObj = new JSONObject(s); + EventData ev = new EventData(this.conn, jsonObj); + log.info("SSE Event in json " + jsonObj.toString()); + RestConfCollector.handleEvents(ev); + } else if (type == jsonType.ARRAY) { + JSONArray jsonArr = new JSONArray(s); + for (int j = 0; j < jsonArr.length(); j++) { + JSONObject jsonObj = jsonArr.getJSONObject(j); + EventData ev = new EventData(this.conn, jsonObj); + log.info("SSE Event in json " + jsonObj.toString()); + RestConfCollector.handleEvents(ev); + } + } else { + log.info("Received heart beat "); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private enum jsonType { + OBJECT, ARRAY, NONE; + } + + public jsonType isJSONValid(String test) { + try { + new JSONObject(test); + log.info("Received a Json object"); + } catch (JSONException ex) { + try { + new JSONArray(test); + return jsonType.ARRAY; + } catch (JSONException ex1) { + return jsonType.NONE; + } + } + return jsonType.OBJECT; + } +} diff --git a/src/main/java/org/onap/dcae/common/EventConnectionState.java b/src/main/java/org/onap/dcae/common/EventConnectionState.java new file mode 100644 index 0000000..3e53247 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/EventConnectionState.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.restconf + * ================================================================================ + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.common; + +public enum EventConnectionState { + + INIT, SUBSCRIBED, UNSUBSCRIBED, Unspecified; + + public static EventConnectionState fromString(String s) { + if ("init".equalsIgnoreCase(s)) { + return INIT; + } + if ("subscribed".equalsIgnoreCase(s)) { + return SUBSCRIBED; + } + if ("unsubscribed".equalsIgnoreCase(s)) { + return UNSUBSCRIBED; + } + if ("unspecified".equalsIgnoreCase(s)) { + return Unspecified; + } + throw new IllegalArgumentException("Invalid value for format: " + s); + } + +} diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RetryException.java b/src/main/java/org/onap/dcae/common/EventData.java index aa40c33..b97d8e4 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RetryException.java +++ b/src/main/java/org/onap/dcae/common/EventData.java @@ -1,8 +1,8 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,26 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.dcae.common; -package org.onap.dcae.collectors.restconf.common; +import org.json.JSONObject; +import org.onap.dcae.controller.PersistentEventConnection; -public class RetryException extends Exception { - public RetryException(String message) { - super(message); +public class EventData { + private PersistentEventConnection conn; + private JSONObject eventObj; + + + public EventData(PersistentEventConnection conn, JSONObject eventObj) { + this.conn = conn; + this.eventObj = eventObj; + } + + public PersistentEventConnection getConn() { + return conn; + } + + public JSONObject getEventObj() { + return eventObj; } } diff --git a/src/main/java/org/onap/dcae/common/EventProcessor.java b/src/main/java/org/onap/dcae/common/EventProcessor.java new file mode 100644 index 0000000..bb0f095 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/EventProcessor.java @@ -0,0 +1,103 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.collectors.restconf
+ * ================================================================================
+ * Copyright (C) 2018-2019 Huawei. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dcae.common;
+
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.onap.dcae.RestConfCollector;
+import org.onap.dcae.common.publishing.EventPublisher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class EventProcessor implements Runnable {
+ private static final Logger log = LoggerFactory.getLogger(EventProcessor.class);
+
+ private Map<String, String[]> streamidHash = new HashMap<>();
+ public EventData ev;
+ private EventPublisher eventPublisher;
+
+ public EventProcessor(EventPublisher eventPublisher, Map<String, String[]> streamidHash) {
+ this.eventPublisher = eventPublisher;
+ this.streamidHash.putAll(streamidHash);
+ }
+
+
+ @Override
+ public void run() {
+ try {
+
+ while (true) {
+ ev = RestConfCollector.fProcessingInputQueue.take();
+
+ // As long as the producer is running we remove elements from
+ // the queue.
+ log.info("QueueSize:" + RestConfCollector.fProcessingInputQueue.size() + "\tEventProcessor\tRemoving element: " +
+ ev.getEventObj());
+ /*@TODO: Right now all event publish to single domain and consume by VES collector. Later maybe send to specific domain */
+ String[] streamIdList = streamidHash.get("notification");
+ log.info("streamIdList:" + Arrays.toString(streamIdList));
+
+ if (streamIdList.length == 0) {
+ log.error("No StreamID defined for publish - Message dropped" + ev.getEventObj());
+ } else {
+ sendEventsToStreams(streamIdList, ev);
+ }
+ log.info("Event published" + ev.getEventObj());
+ }
+ } catch (Exception e) {
+ log.error("EventProcessor InterruptedException" + e.getMessage());
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ private void sendEventsToStreams(String[] streamIdList, EventData ev) {
+ for (String aStreamIdList : streamIdList) {
+ log.info("Invoking publisher for streamId:" + aStreamIdList);
+ if (!ev.getConn().getEvent_ruleId().equals("")) {
+ JSONObject customHeader = new JSONObject();
+ customHeader.put("rule-id", ev.getConn().getEvent_ruleId());
+ eventPublisher.sendEvent(overrideEvent(customHeader, ev.getEventObj()), aStreamIdList);
+ } else {
+ eventPublisher.sendEvent(ev.getEventObj(), aStreamIdList);
+ }
+ }
+ }
+
+ private static JSONObject overrideEvent(JSONObject json1, JSONObject json2) {
+ JSONObject mergedJSON;
+ try {
+ mergedJSON = new JSONObject(json1, JSONObject.getNames(json1));
+ for (String key : JSONObject.getNames(json2)) {
+ mergedJSON.put(key, json2.get(key));
+ }
+
+ } catch (JSONException e) {
+ throw new RuntimeException("JSON Exception" + e);
+ }
+ log.info("Merged json " + mergedJSON);
+ return mergedJSON;
+ }
+}
diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/Format.java b/src/main/java/org/onap/dcae/common/Format.java index 710a576..3539684 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/Format.java +++ b/src/main/java/org/onap/dcae/common/Format.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; public enum Format { JSON, XML, NONE; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/HttpMethod.java b/src/main/java/org/onap/dcae/common/HttpMethod.java index b5c8e71..730ff2d 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/HttpMethod.java +++ b/src/main/java/org/onap/dcae/common/HttpMethod.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; public enum HttpMethod { GET, POST, PUT, DELETE, PATCH; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/HttpResponse.java b/src/main/java/org/onap/dcae/common/HttpResponse.java index 01505c3..3d69ec8 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/HttpResponse.java +++ b/src/main/java/org/onap/dcae/common/HttpResponse.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import javax.ws.rs.core.MultivaluedMap; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/JsonParser.java b/src/main/java/org/onap/dcae/common/JsonParser.java index 16a5b7d..6ce02f2 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/JsonParser.java +++ b/src/main/java/org/onap/dcae/common/JsonParser.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/Parameters.java b/src/main/java/org/onap/dcae/common/Parameters.java index b0f7dfc..5bc85a5 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/Parameters.java +++ b/src/main/java/org/onap/dcae/common/Parameters.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import java.util.Set; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfContext.java b/src/main/java/org/onap/dcae/common/RestConfContext.java index e1ea001..0f95151 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RestConfContext.java +++ b/src/main/java/org/onap/dcae/common/RestConfContext.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import java.util.HashMap; import java.util.Set; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RestapiCallNode.java b/src/main/java/org/onap/dcae/common/RestapiCallNode.java index 33abca9..af0245d 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RestapiCallNode.java +++ b/src/main/java/org/onap/dcae/common/RestapiCallNode.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,17 +18,14 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientHandlerException; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.UniformInterfaceException; -import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.*; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; import com.sun.jersey.api.client.filter.HTTPDigestAuthFilter; +import com.sun.jersey.api.client.filter.LoggingFilter; import com.sun.jersey.client.urlconnection.HTTPSProperties; import com.sun.jersey.oauth.client.OAuthClientFilter; import com.sun.jersey.oauth.signature.OAuthParameters; @@ -43,34 +40,28 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.UriBuilder; import java.io.FileInputStream; import java.io.IOException; import java.net.SocketException; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyStore; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; -import static org.onap.dcae.collectors.restconf.common.RestapiCallNodeUtil.getParameters; -import static org.onap.dcae.collectors.restconf.common.RestapiCallNodeUtil.parseParam; +import static org.onap.dcae.common.RestapiCallNodeUtil.getParameters; +import static org.onap.dcae.common.RestapiCallNodeUtil.parseParam; public class RestapiCallNode { private static final Logger log = LoggerFactory.getLogger(RestapiCallNode.class); public void sendRequest(Map<String, String> paramMap, RestConfContext ctx, Integer retryCount) throws Exception { - RetryPolicy retryPolicy = null; HttpResponse r = new HttpResponse(); try { Parameters p = getParameters(paramMap); String pp = p.responsePrefix != null ? p.responsePrefix + '.' : ""; String req = null; if (p.templateFileName != null) { + log.info("p.templateFileName " + p.templateFileName); String reqTemplate = readFile(p.templateFileName); req = buildXmlJsonRequest(ctx, reqTemplate, p.format); } else if (p.requestBody != null) { @@ -102,8 +93,10 @@ public class RestapiCallNode { } if (mm != null) { - for (Map.Entry<String, String> entry : mm.entrySet()) + for (Map.Entry<String, String> entry : mm.entrySet()) { ctx.setAttribute(pp + entry.getKey(), entry.getValue()); + log.info("ctx.setAttribute :=> {} value {} ", pp + entry.getKey(), entry.getValue()); + } } } } @@ -115,34 +108,13 @@ public class RestapiCallNode { log.error("Error sending the request: " + e.getMessage(), e); String prefix = parseParam(paramMap, "responsePrefix", false, null); - if (null == retryPolicy || !shouldRetry) { + if (!shouldRetry || (retryCount == null) || (retryCount == 0)) { setFailureResponseStatus(ctx, prefix, e.getMessage(), r); } else { - if (retryCount == null) { - retryCount = 0; - } - String retryMessage = retryCount + " attempts were made out of " + retryPolicy.getMaximumRetries() + - " maximum retries."; - log.debug(retryMessage); try { - retryCount = retryCount + 1; - if (retryCount < retryPolicy.getMaximumRetries() + 1) { - URI uri = new URI(paramMap.get("restapiUrl")); - String hostname = uri.getHost(); - String retryString = retryPolicy.getNextHostName(uri.toString()); - URI uriTwo = new URI(retryString); - URI retryUri = UriBuilder.fromUri(uri).host(uriTwo.getHost()).port(uriTwo.getPort()).scheme( - uriTwo.getScheme()).build(); - paramMap.put("restapiUrl", retryUri.toString()); - log.debug("URL was set to {}", retryUri.toString()); - log.debug("Failed to communicate with host {}. Request will be re-attempted using the host {}.", - hostname, retryString); - log.debug("This is retry attempt {} out of {}", retryCount, retryPolicy.getMaximumRetries()); - sendRequest(paramMap, ctx, retryCount); - } else { - log.debug("Maximum retries reached, calling setFailureResponseStatus."); - setFailureResponseStatus(ctx, prefix, e.getMessage(), r); - } + retryCount = retryCount - 1; + log.debug("This is retry attempt {} ", retryCount); + sendRequest(paramMap, ctx, retryCount); } catch (Exception ex) { log.error("Could not attempt retry.", ex); String retryErrorMessage = @@ -165,8 +137,9 @@ public class RestapiCallNode { template = expandRepeats(ctx, template, 1); Map<String, String> mm = new HashMap<>(); - for (String s : ctx.getAttributeKeySet()) + for (String s : ctx.getAttributeKeySet()) { mm.put(s, ctx.getAttribute(s)); + } StringBuilder ss = new StringBuilder(); int i = 0; while (i < template.length()) { @@ -317,14 +290,14 @@ public class RestapiCallNode { client.addFilter(new HTTPDigestAuthFilter(p.restapiUser, p.restapiPassword)); } else { throw new Exception("oAUTH authentication type selected but all restapiUser and restapiPassword " + - "parameters doesn't exist", new Throwable()); + "parameters doesn't exist", new Throwable()); } } else if (p.authtype == AuthType.BASIC) { if (p.restapiUser != null && p.restapiPassword != null) { client.addFilter(new HTTPBasicAuthFilter(p.restapiUser, p.restapiPassword)); } else { throw new Exception("oAUTH authentication type selected but all restapiUser and restapiPassword " + - "parameters doesn't exist", new Throwable()); + "parameters doesn't exist", new Throwable()); } } else if (p.authtype == AuthType.OAUTH) { if (p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null && p.oAuthSignatureMethod != null) { @@ -337,8 +310,8 @@ public class RestapiCallNode { .consumerSecret(p.oAuthConsumerSecret); client.addFilter(new OAuthClientFilter(client.getProviders(), params, secrets)); } else { - throw new Exception("oAUTH authentication type selected but all oAuthConsumerKey, oAuthConsumerSecret " + - "and oAuthSignatureMethod parameters doesn't exist", new Throwable()); + throw new Exception("oAUTH authentication type selected but all oAuthConsumerKey, voAuthConsumerSecret " + + "and oAuthSignatureMethod parameters doesn't exist", new Throwable()); } } } @@ -346,7 +319,6 @@ public class RestapiCallNode { } protected HttpResponse sendHttpRequest(String request, Parameters p) throws Exception { - ClientConfig config = new DefaultClientConfig(); SSLContext ssl = null; if (p.ssl && p.restapiUrl.startsWith("https")) { @@ -356,17 +328,20 @@ public class RestapiCallNode { HostnameVerifier hostnameVerifier = (hostname, session) -> true; config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, - new HTTPSProperties(hostnameVerifier, ssl)); + new HTTPSProperties(hostnameVerifier, ssl)); } logProperties(config.getProperties()); Client client = Client.create(config); client.setConnectTimeout(5000); + client.addFilter(new LoggingFilter()); WebResource webResource = addAuthType(client, p).resource(p.restapiUrl); log.info("Sending request:"); log.info(request); + log.info("URL: " + p.restapiUrl + " method " + p.httpMethod.toString() + " Custome headr " + p.customHttpHeaders); + long t1 = System.currentTimeMillis(); HttpResponse r = new HttpResponse(); @@ -390,19 +365,17 @@ public class RestapiCallNode { for (String singlePair : keyValuePairs) { int equalPosition = singlePair.indexOf('='); webResourceBuilder.header(singlePair.substring(0, equalPosition), - singlePair.substring(equalPosition + 1, singlePair.length())); + singlePair.substring(equalPosition + 1, singlePair.length())); } } - webResourceBuilder.header("X-ECOMP-RequestID", org.slf4j.MDC.get("X-ECOMP-RequestID")); - ClientResponse response; try { response = webResourceBuilder.method(p.httpMethod.toString(), ClientResponse.class, request); } catch (UniformInterfaceException | ClientHandlerException e) { throw new Exception("Exception while sending http request to client " - + e.getLocalizedMessage(), e); + + e.getLocalizedMessage(), e); } r.code = response.getStatus(); @@ -452,6 +425,7 @@ public class RestapiCallNode { KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); KeyStore ks = KeyStore.getInstance("PKCS12"); char[] pwd = p.keyStorePassword.toCharArray(); + log.info("pwd " + pwd + " " + p.keyStorePassword); ks.load(in, pwd); kmf.init(ks, pwd); @@ -490,21 +464,4 @@ public class RestapiCallNode { for (String name : ll) log.info("--- {}:{}", name, String.valueOf(mm.get(name))); } - - private static class FileParam { - - public String fileName; - public String url; - public String user; - public String password; - public HttpMethod httpMethod; - public String responsePrefix; - public boolean skipSending; - public String oAuthConsumerKey; - public String oAuthConsumerSecret; - public String oAuthSignatureMethod; - public String oAuthVersion; - public AuthType authtype; - } - }
\ No newline at end of file diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RestapiCallNodeUtil.java b/src/main/java/org/onap/dcae/common/RestapiCallNodeUtil.java index 0e1d03b..1ff00dd 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RestapiCallNodeUtil.java +++ b/src/main/java/org/onap/dcae/common/RestapiCallNodeUtil.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import org.glassfish.jersey.client.oauth1.ConsumerCredentials; @@ -37,18 +37,30 @@ public class RestapiCallNodeUtil { private static final Logger log = LoggerFactory.getLogger(RestapiCallNodeUtil.class); + private RestapiCallNodeUtil() { // Preventing instantiation of the same. } + public static String getUriMethod(Boolean authEnabled) { + /*@TODO: As per configuration */ +// String uri; +// if (authEnabled) { +// uri = "https://"; +// } else { +// uri = "http://"; +// } + return "https://"; + } + public static Parameters getParameters(Map<String, String> paramMap) throws Exception { Parameters p = new Parameters(); p.templateFileName = parseParam(paramMap, "templateFileName", false, null); p.requestBody = parseParam(paramMap, "requestBody", false, null); p.restapiUrl = parseParam(paramMap, "restapiUrl", true, null); validateUrl(p.restapiUrl); - p.restapiUser = parseParam(paramMap, "restapiUser", false, null); - p.restapiPassword = parseParam(paramMap, "restapiPassword", false, null); + p.restapiUser = null;//parseParam(paramMap, "restapiUser", false, null); + p.restapiPassword = null;//parseParam(paramMap, "restapiPassword", false, null); p.oAuthConsumerKey = parseParam(paramMap, "oAuthConsumerKey", false, null); p.oAuthConsumerSecret = parseParam(paramMap, "oAuthConsumerSecret", false, null); p.oAuthSignatureMethod = parseParam(paramMap, "oAuthSignatureMethod", false, null); @@ -72,9 +84,11 @@ public class RestapiCallNodeUtil { p.partner = parseParam(paramMap, "partner", false, null); p.dumpHeaders = Boolean.valueOf(parseParam(paramMap, "dumpHeaders", false, null)); p.returnRequestPayload = Boolean.valueOf(parseParam(paramMap, "returnRequestPayload", false, null)); + log.info(p.toString()); return p; } + public static String parseParam(Map<String, String> paramMap, String name, boolean required, String def) throws Exception { String s = paramMap.get(name); @@ -132,43 +146,45 @@ public class RestapiCallNodeUtil { } public static Client addAuthType(Client client, Parameters p) { - if (p.authtype == AuthType.Unspecified) { - if (p.restapiUser != null && p.restapiPassword != null) { - client.register(HttpAuthenticationFeature.basic(p.restapiUser, p.restapiPassword)); - } else if (p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null - && p.oAuthSignatureMethod != null) { - Feature oAuth1Feature = OAuth1ClientSupport - .builder(new ConsumerCredentials(p.oAuthConsumerKey, p.oAuthConsumerSecret)) - .version(p.oAuthVersion).signatureMethod(p.oAuthSignatureMethod).feature().build(); - client.register(oAuth1Feature); - } - } else { - if (p.authtype == AuthType.DIGEST) { - if (p.restapiUser != null && p.restapiPassword != null) { - client.register(HttpAuthenticationFeature.digest(p.restapiUser, p.restapiPassword)); - } else { - throw new IllegalArgumentException( - "oAUTH authentication type selected but all restapiUser and restapiPassword " + - "parameters doesn't exist", new Throwable()); - } - } else if (p.authtype == AuthType.BASIC) { + if (p != null) { + if (p.authtype == AuthType.Unspecified) { if (p.restapiUser != null && p.restapiPassword != null) { client.register(HttpAuthenticationFeature.basic(p.restapiUser, p.restapiPassword)); - } else { - throw new IllegalArgumentException( - "oAUTH authentication type selected but all restapiUser and restapiPassword " + - "parameters doesn't exist", new Throwable()); - } - } else if (p.authtype == AuthType.OAUTH) { - if (p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null && p.oAuthSignatureMethod != null) { + } else if (p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null + && p.oAuthSignatureMethod != null) { Feature oAuth1Feature = OAuth1ClientSupport .builder(new ConsumerCredentials(p.oAuthConsumerKey, p.oAuthConsumerSecret)) .version(p.oAuthVersion).signatureMethod(p.oAuthSignatureMethod).feature().build(); client.register(oAuth1Feature); - } else { - throw new IllegalArgumentException( - "oAUTH authentication type selected but all oAuthConsumerKey, oAuthConsumerSecret " + - "and oAuthSignatureMethod parameters doesn't exist", new Throwable()); + } + } else { + if (p.authtype == AuthType.DIGEST) { + if (p.restapiUser != null && p.restapiPassword != null) { + client.register(HttpAuthenticationFeature.digest(p.restapiUser, p.restapiPassword)); + } else { + throw new IllegalArgumentException( + "oAUTH authentication type selected but all restapiUser and restapiPassword " + + "parameters doesn't exist", new Throwable()); + } + } else if (p.authtype == AuthType.BASIC) { + if (p.restapiUser != null && p.restapiPassword != null) { + client.register(HttpAuthenticationFeature.basic(p.restapiUser, p.restapiPassword)); + } else { + throw new IllegalArgumentException( + "oAUTH authentication type selected but all restapiUser and restapiPassword " + + "parameters doesn't exist", new Throwable()); + } + } else if (p.authtype == AuthType.OAUTH) { + if (p.oAuthConsumerKey != null && p.oAuthConsumerSecret != null && p.oAuthSignatureMethod != null) { + Feature oAuth1Feature = OAuth1ClientSupport + .builder(new ConsumerCredentials(p.oAuthConsumerKey, p.oAuthConsumerSecret)) + .version(p.oAuthVersion).signatureMethod(p.oAuthSignatureMethod).feature().build(); + client.register(oAuth1Feature); + } else { + throw new IllegalArgumentException( + "oAUTH authentication type selected but all oAuthConsumerKey, oAuthConsumerSecret " + + "and oAuthSignatureMethod parameters doesn't exist", new Throwable()); + } } } } diff --git a/src/main/java/org/onap/dcae/common/SSLContextCreator.java b/src/main/java/org/onap/dcae/common/SSLContextCreator.java new file mode 100644 index 0000000..db3d123 --- /dev/null +++ b/src/main/java/org/onap/dcae/common/SSLContextCreator.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.common; + +import org.springframework.boot.web.server.Ssl; + +import java.nio.file.Path; + +public class SSLContextCreator { + private final String keyStorePassword; + private final String certAlias; + private final Path keyStoreFile; + + private Path trustStoreFile; + private String trustStorePassword; + private boolean hasTlsClientAuthentication = false; + + public static SSLContextCreator create(final Path keyStoreFile, final String certAlias, final String password) { + return new SSLContextCreator(keyStoreFile, certAlias, password); + } + + private SSLContextCreator(final Path keyStoreFile, final String certAlias, final String password) { + this.certAlias = certAlias; + this.keyStoreFile = keyStoreFile; + this.keyStorePassword = password; + } + + public SSLContextCreator withTlsClientAuthentication(final Path trustStoreFile, final String password) { + hasTlsClientAuthentication = true; + this.trustStoreFile = trustStoreFile; + this.trustStorePassword = password; + + return this; + } + + private void configureKeyStore(final Ssl ssl) { + final String keyStore = keyStoreFile.toAbsolutePath().toString(); + + ssl.setKeyStore(keyStore); + ssl.setKeyPassword(keyStorePassword); + ssl.setKeyAlias(certAlias); + } + + private void configureTrustStore(final Ssl ssl) { + final String trustStore = trustStoreFile.toAbsolutePath().toString(); + + ssl.setTrustStore(trustStore); + ssl.setTrustStorePassword(trustStorePassword); + ssl.setClientAuth(Ssl.ClientAuth.NEED); + } + + public Ssl build() { + final Ssl ssl = new Ssl(); + ssl.setEnabled(true); + + configureKeyStore(ssl); + + if (hasTlsClientAuthentication) { + configureTrustStore(ssl); + } + + return ssl; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/XmlJsonUtil.java b/src/main/java/org/onap/dcae/common/XmlJsonUtil.java index 6cac728..877f9e5 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/XmlJsonUtil.java +++ b/src/main/java/org/onap/dcae/common/XmlJsonUtil.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/XmlParser.java b/src/main/java/org/onap/dcae/common/XmlParser.java index 80bf2fc..06a4a66 100755 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/XmlParser.java +++ b/src/main/java/org/onap/dcae/common/XmlParser.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.dcaegen2.collectors.restconf * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.common; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPConfigurationParser.java b/src/main/java/org/onap/dcae/common/publishing/DMaaPConfigurationParser.java index 7e65d34..dada578 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPConfigurationParser.java +++ b/src/main/java/org/onap/dcae/common/publishing/DMaaPConfigurationParser.java @@ -1,8 +1,9 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,27 +18,29 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - -package org.onap.dcae.collectors.restconf.common.event.publishing; +package org.onap.dcae.common.publishing; import io.vavr.collection.List; import io.vavr.collection.Map; import io.vavr.control.Option; import io.vavr.control.Try; -import org.onap.dcae.collectors.restconf.common.AnyNode; +import org.onap.dcae.common.AnyNode; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import static io.vavr.API.List; -import static io.vavr.API.Try; -import static io.vavr.API.Tuple; -import static io.vavr.API.unchecked; -import static org.onap.dcae.collectors.restconf.common.event.publishing.VavrUtils.enhanceError; -import static org.onap.dcae.collectors.restconf.common.event.publishing.VavrUtils.f; +import org.json.JSONObject; + +import static io.vavr.API.*; +import static org.onap.dcae.common.publishing.VavrUtils.enhanceError; +import static org.onap.dcae.common.publishing.VavrUtils.f; -public class DMaaPConfigurationParser { +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +@SuppressWarnings("mapFailure takes a generic varargs, unchecked because of Javas type system limitation, actually safe to do") +public final class DMaaPConfigurationParser { public static Try<Map<String, PublisherConfig>> parseToDomainMapping(Path configLocation) { return readFromFile(configLocation) @@ -45,6 +48,11 @@ public class DMaaPConfigurationParser { .flatMap(DMaaPConfigurationParser::toConfigMap); } + public static Try<Map<String, PublisherConfig>> parseToDomainMapping(JSONObject config) { + return toJSON(config.toString()) + .flatMap(DMaaPConfigurationParser::toConfigMap); + } + private static Try<String> readFromFile(Path configLocation) { return Try(() -> new String(Files.readAllBytes(configLocation))) .mapFailure(enhanceError(f("Could not read DMaaP configuration from location: '%s'", configLocation))); @@ -57,8 +65,7 @@ public class DMaaPConfigurationParser { private static Try<Map<String, PublisherConfig>> toConfigMap(AnyNode config) { return Try(() -> usesLegacyFormat(config) ? parseLegacyFormat(config) : parseNewFormat(config)) - .mapFailure(enhanceError( - f("Parsing DMaaP configuration: '%s' failed, probably it is in unexpected format", config))); + .mapFailure(enhanceError(f("Parsing DMaaP configuration: '%s' failed, probably it is in unexpected format", config))); } private static boolean usesLegacyFormat(AnyNode dMaaPConfig) { @@ -103,5 +110,4 @@ public class DMaaPConfigurationParser { .map(credentials -> new PublisherConfig(destinations, topic, credentials._1, credentials._2)) .getOrElse(new PublisherConfig(destinations, topic)); } - } diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPEventPublisher.java b/src/main/java/org/onap/dcae/common/publishing/DMaaPEventPublisher.java index 4c14275..1209b38 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPEventPublisher.java +++ b/src/main/java/org/onap/dcae/common/publishing/DMaaPEventPublisher.java @@ -1,8 +1,10 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +20,10 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common.event.publishing; +package org.onap.dcae.common.publishing; import com.att.nsa.cambria.client.CambriaBatchingPublisher; +import io.vavr.collection.Map; import io.vavr.control.Try; import org.json.JSONObject; import org.slf4j.Logger; @@ -28,27 +31,38 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -public class DMaaPEventPublisher implements EventPublisher { +import static org.onap.dcae.common.publishing.VavrUtils.f; +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +class DMaaPEventPublisher implements EventPublisher { private static final int PENDING_MESSAGE_LOG_THRESHOLD = 100; private static final Logger log = LoggerFactory.getLogger(DMaaPEventPublisher.class); private final DMaaPPublishersCache publishersCache; private final Logger outputLogger; - DMaaPEventPublisher(DMaaPPublishersCache DMaaPPublishersCache, + DMaaPEventPublisher(DMaaPPublishersCache publishersCache, Logger outputLogger) { - this.publishersCache = DMaaPPublishersCache; + this.publishersCache = publishersCache; this.outputLogger = outputLogger; } @Override public void sendEvent(JSONObject event, String domain) { + publishersCache.getPublisher(domain) .onEmpty(() -> - log.warn(VavrUtils.f("Could not find event publisher for domain: '%s', dropping message: '%s'", domain, event))) + log.warn(f("Could not find event publisher for domain: '%s', dropping message: '%s'", domain, event))) .forEach(publisher -> sendEvent(event, domain, publisher)); } + @Override + public void reconfigure(Map<String, PublisherConfig> dMaaPConfig) { + log.info("reconfigure "); + publishersCache.reconfigure(dMaaPConfig); + } + private void sendEvent(JSONObject event, String domain, CambriaBatchingPublisher publisher) { Try.run(() -> uncheckedSendEvent(event, domain, publisher)) .onFailure(exc -> closePublisher(event, domain, exc)); @@ -56,20 +70,18 @@ public class DMaaPEventPublisher implements EventPublisher { private void uncheckedSendEvent(JSONObject event, String domain, CambriaBatchingPublisher publisher) throws IOException { - System.out.println("printing publisher information" + publisher); int pendingMsgs = publisher.send("MyPartitionKey", event.toString()); if (pendingMsgs > PENDING_MESSAGE_LOG_THRESHOLD) { log.info("Pending messages count: " + pendingMsgs); } - String infoMsg = VavrUtils.f("Event: '%s' scheduled to be send asynchronously on domain: '%s'", event, domain); + String infoMsg = f("Event: '%s' scheduled to be send asynchronously on domain: '%s'", event, domain); log.info(infoMsg); outputLogger.info(infoMsg); } private void closePublisher(JSONObject event, String domain, Throwable e) { - log.error(VavrUtils.f("Unable to schedule event: '%s' on domain: '%s'. Closing publisher and dropping message.", - event, domain), e); + log.error(f("Unable to schedule event: '%s' on domain: '%s'. Closing publisher and dropping message.", + event, domain), e); publishersCache.closePublisherFor(domain); } - } diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPPublishersBuilder.java b/src/main/java/org/onap/dcae/common/publishing/DMaaPPublishersBuilder.java index e6c7600..8020b60 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPPublishersBuilder.java +++ b/src/main/java/org/onap/dcae/common/publishing/DMaaPPublishersBuilder.java @@ -1,8 +1,9 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +18,7 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - -package org.onap.dcae.collectors.restconf.common.event.publishing; +package org.onap.dcae.common.publishing; import com.att.nsa.cambria.client.CambriaBatchingPublisher; import com.att.nsa.cambria.client.CambriaClientBuilders; @@ -26,15 +26,14 @@ import com.att.nsa.cambria.client.CambriaClientBuilders.PublisherBuilder; import io.vavr.control.Try; import static io.vavr.API.Try; -import static org.onap.dcae.collectors.restconf.common.event.publishing.VavrUtils.enhanceError; -import static org.onap.dcae.collectors.restconf.common.event.publishing.VavrUtils.f; +import static org.onap.dcae.common.publishing.VavrUtils.enhanceError; +import static org.onap.dcae.common.publishing.VavrUtils.f; /** * @author Pawel Szalapski (pawel.szalapski@nokia.com) */ final class DMaaPPublishersBuilder { - @SuppressWarnings("mapFailure takes a generic varargs, unchecked because of Javas type system limitation, actually safe to do") static Try<CambriaBatchingPublisher> buildPublisher(PublisherConfig config) { return Try(() -> builder(config).build()) .mapFailure(enhanceError(f("DMaaP client builder throws exception for this configuration: '%s'", config))); diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPPublishersCache.java b/src/main/java/org/onap/dcae/common/publishing/DMaaPPublishersCache.java index 6974bc9..8f4c761 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/DMaaPPublishersCache.java +++ b/src/main/java/org/onap/dcae/common/publishing/DMaaPPublishersCache.java @@ -1,8 +1,10 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +19,10 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - -package org.onap.dcae.collectors.restconf.common.event.publishing; +package org.onap.dcae.common.publishing; import com.att.nsa.cambria.client.CambriaBatchingPublisher; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.cache.RemovalListener; -import com.google.common.cache.RemovalNotification; +import com.google.common.cache.*; import io.vavr.collection.Map; import io.vavr.control.Option; import org.slf4j.Logger; @@ -37,9 +34,12 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import static io.vavr.API.Option; -import static org.onap.dcae.collectors.restconf.common.event.publishing.VavrUtils.f; +import static org.onap.dcae.common.publishing.VavrUtils.f; -public class DMaaPPublishersCache { +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +class DMaaPPublishersCache { private static final Logger log = LoggerFactory.getLogger(DMaaPPublishersCache.class); private final LoadingCache<String, CambriaBatchingPublisher> publishersCache; @@ -74,6 +74,17 @@ public class DMaaPPublishersCache { publishersCache.invalidate(streamId); } + synchronized void reconfigure(Map<String, PublisherConfig> newConfig) { + log.info("reconfigure in DMaaPPublishersCache"); + Map<String, PublisherConfig> currentConfig = dMaaPConfiguration.get(); + Map<String, PublisherConfig> removedConfigurations = currentConfig + .filterKeys(domain -> !newConfig.containsKey(domain)); + Map<String, PublisherConfig> changedConfigurations = newConfig + .filterKeys(e -> currentConfig.containsKey(e) && !currentConfig.get(e).equals(newConfig.get(e))); + dMaaPConfiguration.set(newConfig); + removedConfigurations.merge(changedConfigurations).forEach(e -> publishersCache.invalidate(e._1)); + } + static class OnPublisherRemovalListener implements RemovalListener<String, CambriaBatchingPublisher> { @Override @@ -86,10 +97,11 @@ public class DMaaPPublishersCache { java.util.List<?> stuck = publisher.close(timeout, unit); if (!stuck.isEmpty()) { log.error(f("Publisher got stuck and did not manage to close in '%s' '%s', " - + "%s messages were dropped", stuck.size(), timeout, unit)); + + "%s messages were dropped", stuck.size(), timeout, unit)); } } catch (InterruptedException | IOException e) { log.error("Could not close Cambria publisher, some messages might have been dropped", e); + Thread.currentThread().interrupt(); } } } @@ -107,4 +119,5 @@ public class DMaaPPublishersCache { .get(); } } + } diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/EventPublisher.java b/src/main/java/org/onap/dcae/common/publishing/EventPublisher.java index 28aace8..91736ec 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/EventPublisher.java +++ b/src/main/java/org/onap/dcae/common/publishing/EventPublisher.java @@ -1,8 +1,9 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +18,15 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common.event.publishing; - +package org.onap.dcae.common.publishing; import io.vavr.collection.Map; import org.json.JSONObject; import org.slf4j.Logger; +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ public interface EventPublisher { static EventPublisher createPublisher(Logger outputLogger, Map<String, PublisherConfig> dMaaPConfig) { @@ -32,4 +35,5 @@ public interface EventPublisher { void sendEvent(JSONObject event, String domain); + void reconfigure(Map<String, PublisherConfig> dMaaPConfig); } diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/PublisherConfig.java b/src/main/java/org/onap/dcae/common/publishing/PublisherConfig.java index 0e14a42..67aca1d 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/PublisherConfig.java +++ b/src/main/java/org/onap/dcae/common/publishing/PublisherConfig.java @@ -1,8 +1,9 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +18,18 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common.event.publishing; +package org.onap.dcae.common.publishing; import io.vavr.collection.List; import io.vavr.control.Option; import java.util.Objects; -public class PublisherConfig { +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +public final class PublisherConfig { + private final List<String> destinations; private final String topic; private String userName; diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/VavrUtils.java b/src/main/java/org/onap/dcae/common/publishing/VavrUtils.java index 4a82bed..1db4e18 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/event/publishing/VavrUtils.java +++ b/src/main/java/org/onap/dcae/common/publishing/VavrUtils.java @@ -1,8 +1,8 @@ /*- * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,16 +17,20 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - -package org.onap.dcae.collectors.restconf.common.event.publishing; +package org.onap.dcae.common.publishing; import io.vavr.API; import io.vavr.API.Match.Case; +import java.util.function.Consumer; +import org.slf4j.Logger; import static io.vavr.API.$; +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +public final class VavrUtils { -public class VavrUtils { private VavrUtils() { // utils aggregator } @@ -34,7 +38,7 @@ public class VavrUtils { /** * Shortcut for 'string interpolation' */ - static String f(String msg, Object... args) { + public static String f(String msg, Object... args) { return String.format(msg, args); } @@ -42,7 +46,17 @@ public class VavrUtils { * Wrap failure with a more descriptive message of what has failed and chain original cause. Used to provide a * context for errors instead of raw exception. */ - static Case<Throwable, Throwable> enhanceError(String msg) { + public static Case<Throwable, Throwable> enhanceError(String msg) { return API.Case($(), e -> new RuntimeException(msg, e)); } + + public static Case<Throwable, Throwable> enhanceError(String pattern, Object... arguments) { + return API.Case($(), e -> new RuntimeException(f(pattern, arguments), e)); + } + + public static Consumer<Throwable> logError(Logger withLogger) { + return e -> withLogger.error(e.getMessage(), e); + } + + } diff --git a/src/main/java/org/onap/dcae/controller/AccessController.java b/src/main/java/org/onap/dcae/controller/AccessController.java new file mode 100644 index 0000000..83673b8 --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/AccessController.java @@ -0,0 +1,243 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.restconf + * ================================================================================ + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.onap.dcae.ApplicationException; +import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.common.Constants; +import org.onap.dcae.common.RestConfContext; +import org.onap.dcae.common.RestapiCallNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static java.nio.file.Files.readAllBytes; +import static org.onap.dcae.common.RestapiCallNodeUtil.getUriMethod; + +public class AccessController { + private static final Logger log = LoggerFactory.getLogger(AccessController.class); + /* Collector properties */ + private ApplicationSettings properties; + + /* Controller specific information */ + private ControllerConfigInfo cfgInfo; + private RestConfContext ctx; + RestapiCallNode restApiCallNode; + + /* Maps of Events */ + private Map<String, PersistentEventConnection> eventList = new ConcurrentHashMap<>(); + private ExecutorService executor = Executors.newCachedThreadPool(); + private Map<String, String> paraMap; + + public AccessController(JSONObject controller, + ApplicationSettings properties) { + this.cfgInfo = new ControllerConfigInfo(controller.get("controller_name").toString(), + controller.get("controller_restapiUrl").toString(), + controller.get("controller_restapiUser").toString(), + controller.get("controller_restapiPassword").toString(), + controller.get("controller_accessTokenUrl").toString(), + controller.get("controller_accessTokenFile").toString(), + controller.get("controller_subscriptionUrl").toString(), + controller.get("controller_accessTokenMethod").toString(), + controller.get("controller_subsMethod").toString()); + this.properties = properties; + this.ctx = new RestConfContext(); + this.restApiCallNode = new RestapiCallNode(); + this.paraMap = new HashMap<>(); + + prepareControllerParamMap(); + + log.info("AccesController Created {} {} {} {} {} {}", + this.cfgInfo.getController_name(), + this.cfgInfo.getController_restapiUrl(), + this.cfgInfo.getController_restapiPassword(), + this.cfgInfo.getController_restapiUser(), + this.cfgInfo.getController_accessTokenUrl(), + this.cfgInfo.getController_accessTokenFile()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AccessController)) return false; + AccessController that = (AccessController) o; + return that.cfgInfo.getController_name().equals(that.cfgInfo.getController_name()); + } + + @Override + public int hashCode() { + return Objects.hash(this.cfgInfo.getController_name()); + } + + public RestapiCallNode getRestApiCallNode() { + return restApiCallNode; + } + + private void fetch_TokenId() { + + + modifyControllerParamMap(Constants.KSETTING_REST_API_URL, getUriMethod(this.properties.authorizationEnabled()) + cfgInfo.getController_restapiUrl() + cfgInfo.getController_accessTokenUrl()); + modifyControllerParamMap(Constants.KDEFAULT_TEMP_FILENAME, cfgInfo.getController_accessTokenFile()); + modifyControllerParamMap(Constants.KSETTING_REST_UNAME, cfgInfo.getController_restapiUser()); + modifyControllerParamMap(Constants.KSETTING_REST_PASSWORD, cfgInfo.getController_restapiPassword()); + modifyControllerParamMap(Constants.KSETTING_HTTP_METHOD, cfgInfo.getController_accessTokenMethod()); + + String httpResponse = null; + try { + + restApiCallNode.sendRequest(this.paraMap, ctx, null); + String key = getControllerParamMapValue(Constants.KSETTING_RESP_PREFIX).concat(".").concat("httpResponse"); + httpResponse = ctx.getAttribute(key); + log.info("httpResponse ", httpResponse + " key " + key); + JSONObject jsonObj = new JSONObject(httpResponse); + log.info("jsonObj ", jsonObj.toString()); + //JSONObject data = jsonObj.getJSONObject("data"); + //String tokenId = data.get("accessSession").toString(); + //@TODO: Make return field dynamic + String tokenId = jsonObj.get("accessSession").toString(); + log.info("token 1" + tokenId); + modifyControllerParamMap(Constants.KSETTING_TOKENID, tokenId); + modifyControllerParamMap(Constants.KSETTING_CUSTOMHTTP_HEADER, "X-ACCESS-TOKEN=" + tokenId); + } catch (Exception e) { + log.info("Access token is not supported" + e.getMessage()); + log.info("http response " + httpResponse); + } + } + + public void activate() { + fetch_TokenId(); + printControllerParamMap(); + /* Create eventlist from properties */ + JSONArray contollers = new JSONArray(properties.rcc_policy()); + for (int i = 0; i < contollers.length(); i++) { + JSONObject controller = contollers.getJSONObject(i); + if (controller.get("controller_name").equals(this.getCfgInfo().getController_name())) { + JSONArray eventlists = controller.getJSONArray("event_details"); + for (int j = 0; j < eventlists.length(); j++) { + JSONObject event = eventlists.getJSONObject(j); + String name = event.get("event_name").toString(); + PersistentEventConnection conn = new PersistentEventConnection(name, + event.get("event_description").toString(), + Boolean.parseBoolean(event.get("event_sseventUrlEmbed").toString()), + event.get("event_sseventsField").toString(), + event.get("event_sseventsUrl").toString(), + event.get("event_subscriptionTemplate").toString(), + event.get("event_unSubscriptionTemplate").toString(), + event.get("event_ruleId").toString(), + this); + + eventList.put(name, conn); + executor.execute(conn); + } + } + } + } + + public RestConfContext getCtx() { + return ctx; + } + + public ApplicationSettings getProperties() { + return properties; + } + + public ControllerConfigInfo getCfgInfo() { + return cfgInfo; + } + + public Map<String, String> getParaMap() { + return this.paraMap; + } + + private void prepareControllerParamMap() { + /* Adding the fields in ParaMap */ + paraMap.put(Constants.KDEFAULT_TEMP_FILENAME, null); + paraMap.put(Constants.KSETTING_REST_API_URL, null); + paraMap.put(Constants.KSETTING_HTTP_METHOD, "post"); + paraMap.put(Constants.KSETTING_RESP_PREFIX, "responsePrefix"); + paraMap.put(Constants.KSETTING_SKIP_SENDING, "false"); + paraMap.put(Constants.KSETTING_SSE_CONNECT_URL, null); + paraMap.put(Constants.KSETTING_FORMAT, "json"); + + paraMap.put(Constants.KSETTING_REST_UNAME, null); + paraMap.put(Constants.KSETTING_REST_PASSWORD, null); + paraMap.put(Constants.KDEFAULT_REQUESTBODY, null); + + paraMap.put(Constants.KSETTING_AUTH_TYPE, "unspecified"); + paraMap.put(Constants.KSETTING_CONTENT_TYPE, "application/json"); + paraMap.put(Constants.KSETTING_OAUTH_CONSUMER_KEY, null); + paraMap.put(Constants.KSETTING_OAUTH_CONSUMER_SECRET, null); + paraMap.put(Constants.KSETTING_OAUTH_SIGNATURE_METHOD, null); + paraMap.put(Constants.KSETTING_OAUTH_VERSION, null); + + paraMap.put(Constants.KSETTING_CUSTOMHTTP_HEADER, null); + paraMap.put(Constants.KSETTING_TOKENID, null); + paraMap.put(Constants.KSETTING_DUMP_HEADER, "false"); + paraMap.put(Constants.KSETTING_RETURN_REQUEST_PAYLOAD, "false"); + + paraMap.put(Constants.KSETTING_TRUST_STORE_FILENAME, this.getProperties().truststoreFileLocation()); + String trustPassword = getKeyStorePassword(toAbsolutePath(this.getProperties().truststorePasswordFileLocation())); + paraMap.put(Constants.KSETTING_TRUST_STORE_PASSWORD, trustPassword); + paraMap.put(Constants.KSETTING_KEY_STORE_FILENAME, this.getProperties().keystoreFileLocation()); + String KeyPassword = getKeyStorePassword(toAbsolutePath(this.getProperties().keystorePasswordFileLocation())); + paraMap.put(Constants.KSETTING_KEY_STORE_PASSWORD, KeyPassword); + + } + + private Path toAbsolutePath(final String path) { + return Paths.get(path).toAbsolutePath(); + } + + private String getKeyStorePassword(final Path location) { + try { + return new String(readAllBytes(location)); + } catch (Exception e) { + log.error("Could not read password from: '" + location + "'.", e); + throw new ApplicationException(e); + } + } + + public void modifyControllerParamMap(String fieldName, String value) { + paraMap.put(fieldName, value); + } + + public String getControllerParamMapValue(String fieldName) { + return paraMap.get(fieldName); + } + + public void printControllerParamMap() { + log.info("----------------Controller Param Map-------------------"); + for (String name : paraMap.keySet()) { + String value = paraMap.get(name); + log.info(name + " : " + value); + } + } +} diff --git a/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java b/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java new file mode 100644 index 0000000..4542fb5 --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/ConfigFilesFacade.java @@ -0,0 +1,131 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import io.vavr.CheckedRunnable; +import io.vavr.Tuple2; +import io.vavr.collection.Map; +import io.vavr.control.Try; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.PropertiesConfiguration; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileNotFoundException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import static io.vavr.API.Try; +import static org.onap.dcae.common.publishing.VavrUtils.*; +import static org.onap.dcae.controller.Conversions.toList; + +class ConfigFilesFacade { + + private static Logger log = LoggerFactory.getLogger(ConfigFilesFacade.class); + + private final Path dMaaPConfigPath; + private final Path propertiesPath; + + public ConfigFilesFacade(Path dMaaPConfigPath, Path propertiesPath) { + this.dMaaPConfigPath = dMaaPConfigPath; + this.propertiesPath = propertiesPath; + } + + Try<Map<String, String>> readCollectorProperties() { + log.info(f("Reading collector properties from path: '%s'", propertiesPath)); + return Try(this::readProperties) + .map(prop -> toList(prop.getKeys()).toMap(k -> k, k -> (String) prop.getProperty(k))) + .mapFailure(enhanceError("Unable to read properties configuration from path '%s'", propertiesPath)) + .onFailure(logError(log)) + .peek(props -> log.info(f("Read following collector properties: '%s'", props))); + } + + Try<JSONObject> readDMaaPConfiguration() { + log.info(f("Reading DMaaP configuration from file: '%s'", dMaaPConfigPath)); + return readFile(dMaaPConfigPath) + .recover(FileNotFoundException.class, __ -> "{}") + .mapFailure(enhanceError("Unable to read DMaaP configuration from file '%s'", dMaaPConfigPath)) + .flatMap(Conversions::toJson) + .onFailure(logError(log)) + .peek(props -> log.info(f("Read following DMaaP properties: '%s'", props))); + } + + Try<Void> writeDMaaPConfiguration(JSONObject dMaaPConfiguration) { + log.info(f("Writing DMaaP configuration '%s' into file '%s'", dMaaPConfiguration, dMaaPConfigPath)); + return writeFile(dMaaPConfigPath, indentConfiguration(dMaaPConfiguration.toString())) + .mapFailure(enhanceError("Could not save new DMaaP configuration to path '%s'", dMaaPConfigPath)) + .onFailure(logError(log)) + .peek(__ -> log.info("Written successfully")); + } + + + Try<Void> writeProperties(Map<String, String> properties) { + log.info(f("Writing properties configuration '%s' into file '%s'", properties, propertiesPath)); + return Try.run(saveProperties(properties)) + .mapFailure(enhanceError("Could not save properties to path '%s'", properties)) + .onFailure(logError(log)) + .peek(__ -> log.info("Written successfully")); + } + + private Try<String> readFile(Path path) { + return Try(() -> new String(Files.readAllBytes(path), StandardCharsets.UTF_8)) + .mapFailure(enhanceError("Could not read content from path: '%s'", path)); + } + + private Try<Void> writeFile(Path path, String content) { + return Try.run(() -> Files.write(path, content.getBytes())) + .mapFailure(enhanceError("Could not write content to path: '%s'", path)); + } + + private PropertiesConfiguration readProperties() throws ConfigurationException { + PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration(); + propertiesConfiguration.setDelimiterParsingDisabled(true); + propertiesConfiguration.load(propertiesPath.toFile()); + return propertiesConfiguration; + } + + private CheckedRunnable saveProperties(Map<String, String> properties) { + return () -> { + PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration(propertiesPath.toFile()); + propertiesConfiguration.setEncoding(null); + for (Tuple2<String, String> property : properties) { + updateProperty(propertiesConfiguration, property); + } + propertiesConfiguration.save(); + }; + } + + private void updateProperty(PropertiesConfiguration propertiesConfiguration, Tuple2<String, String> property) { + if (propertiesConfiguration.containsKey(property._1)) { + propertiesConfiguration.setProperty(property._1, property._2); + } else { + propertiesConfiguration.addProperty(property._1, property._2); + } + } + + private String indentConfiguration(String configuration) { + return new JSONObject(configuration).toString(4); + } + +} diff --git a/src/main/java/org/onap/dcae/controller/ConfigLoader.java b/src/main/java/org/onap/dcae/controller/ConfigLoader.java new file mode 100644 index 0000000..1b7e60b --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/ConfigLoader.java @@ -0,0 +1,147 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import io.vavr.Function0; +import io.vavr.Function1; +import io.vavr.collection.HashMap; +import io.vavr.collection.Map; +import io.vavr.control.Try; +import org.json.JSONObject; +import org.onap.dcae.RestConfCollector; +import org.onap.dcae.common.publishing.PublisherConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.util.function.Consumer; + +import static org.onap.dcae.common.publishing.DMaaPConfigurationParser.parseToDomainMapping; +import static org.onap.dcae.controller.ConfigParsing.getDMaaPConfig; +import static org.onap.dcae.controller.ConfigParsing.getProperties; +import static org.onap.dcae.controller.EnvPropertiesReader.readEnvProps; + +public class ConfigLoader { + + private static final String SKIP_MSG = "Skipping dynamic configuration update"; + private static Logger log = LoggerFactory.getLogger(ConfigLoader.class); + private final Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer; + private final ConfigFilesFacade configFilesFacade; + private final Function1<EnvProps, Try<JSONObject>> configurationSource; + private final Function0<Map<String, String>> envVariablesSupplier; + private boolean toRestart = false; + + ConfigLoader(Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer, + ConfigFilesFacade configFilesFacade, + Function1<EnvProps, Try<JSONObject>> configurationSource, + Function0<Map<String, String>> envVariablesSupplier) { + this.eventPublisherReconfigurer = eventPublisherReconfigurer; + this.configFilesFacade = configFilesFacade; + this.configurationSource = configurationSource; + this.envVariablesSupplier = envVariablesSupplier; + } + + public static ConfigLoader create(Consumer<Map<String, PublisherConfig>> eventPublisherReconfigurer, + Path dMaaPConfigFile, Path propertiesConfigFile) { + log.info("ConfigLoader create ...."); + return new ConfigLoader(eventPublisherReconfigurer, + new ConfigFilesFacade(dMaaPConfigFile, propertiesConfigFile), + ConfigSource::getAppConfig, + () -> HashMap.ofAll(System.getenv())); + } + + public void updateConfig() { + log.info("Trying to dynamically update config from Config Binding Service"); + readEnvProps(envVariablesSupplier.get()) + .onEmpty(() -> log.warn(SKIP_MSG)) + .forEach(this::updateConfig); + } + + private void updateConfig(EnvProps props) { + configurationSource.apply(props) + .onFailure(logSkip()) + .onSuccess(newConf -> { + updateConfigurationProperties(newConf); + updateDMaaPProperties(newConf); + reloadApplication(); + } + ); + } + + private void reloadApplication() { + if (toRestart) { + log.info("New app config - Application will be restarted"); + RestConfCollector.restartApplication(); + } + } + + private void updateDMaaPProperties(JSONObject newConf) { + configFilesFacade.readDMaaPConfiguration() + .onFailure(logSkip()) + .onSuccess(oldDMaaPConf -> getDMaaPConfig(newConf) + .onEmpty(() -> log.warn(SKIP_MSG)) + .forEach(newDMaaPConf -> compareAndOverwriteDMaaPConfig(oldDMaaPConf, newDMaaPConf))); + } + + + private void updateConfigurationProperties(JSONObject newConf) { + configFilesFacade.readCollectorProperties() + .onFailure(logSkip()) + .onSuccess(oldProps -> compareAndOverwritePropertiesConfig(newConf, oldProps)); + } + + private void compareAndOverwritePropertiesConfig(JSONObject newConf, Map<String, String> oldProps) { + Map<String, String> newProperties = getProperties(newConf); + Map<String, String> result = oldProps.filterKeys((s) -> newProperties.keySet().contains(s)); + if (!result.equals(newProperties)) { + configFilesFacade.writeProperties(newProperties) + .onSuccess(__ -> { + toRestart = true; + log.info("New properties configuration written to file"); + }) + .onFailure(logSkip()); + } else { + log.info("Collector properties from CBS are the same as currently used ones. " + SKIP_MSG); + } + } + + private void compareAndOverwriteDMaaPConfig(JSONObject oldDMaaPConf, JSONObject newDMaaPConf) { + if (!oldDMaaPConf.toString().equals(newDMaaPConf.toString())) { + parseToDomainMapping(newDMaaPConf) + .onFailure(exc -> log.error(SKIP_MSG, exc)) + .onSuccess(eventPublisherReconfigurer) + .onSuccess(parsedConfig -> + configFilesFacade.writeDMaaPConfiguration(newDMaaPConf) + .onFailure(logSkip()) + .onSuccess(__ -> { + toRestart = true; + log.info("New dMaaP configuration written to file"); + })); + } else { + log.info("DMaaP config from CBS is the same as currently used one. " + SKIP_MSG); + } + } + + private Consumer<Throwable> logSkip() { + return __ -> log.error(SKIP_MSG); + } +} diff --git a/src/main/java/org/onap/dcae/controller/ConfigParsing.java b/src/main/java/org/onap/dcae/controller/ConfigParsing.java new file mode 100644 index 0000000..fea3451 --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/ConfigParsing.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import io.vavr.collection.Map; +import io.vavr.control.Option; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.vavr.API.Try; +import static io.vavr.API.Tuple; +import static org.onap.dcae.common.publishing.VavrUtils.f; +import static org.onap.dcae.controller.Conversions.toList; + +interface ConfigParsing { + + Logger log = LoggerFactory.getLogger(ConfigParsing.class); + + static Option<JSONObject> getDMaaPConfig(JSONObject configuration) { + log.info(f("Getting DMaaP configuration from app configuration: '%s'", configuration)); + return toList(configuration.toMap().entrySet().iterator()) + .filter(t -> t.getKey().startsWith("streams_publishes")) + .headOption() + .flatMap(e -> Try(() -> configuration.getJSONObject(e.getKey())).toOption()) + .onEmpty(() -> log.warn(f("App configuration '%s' is missing DMaaP configuration ('streams_publishes' key) " + + "or DMaaP configuration is not a valid json document", configuration))) + .peek(dMaaPConf -> log.info(f("Found following DMaaP configuration: '%s'", dMaaPConf))); + } + + static Map<String, String> getProperties(JSONObject configuration) { + log.info(f("Getting properties configuration from app configuration: '%s'", configuration)); + Map<String, String> confEntries = toList(configuration.toMap().entrySet().iterator()) + .toMap(e -> Tuple(e.getKey(), String.valueOf(e.getValue()))) + .filterKeys(e -> !e.startsWith("streams_publishes")); + log.info(f("Found following app properties: '%s'", confEntries)); + return confEntries; + } + +} diff --git a/src/main/java/org/onap/dcae/controller/ConfigSource.java b/src/main/java/org/onap/dcae/controller/ConfigSource.java new file mode 100644 index 0000000..78cb147 --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/ConfigSource.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.Unirest; +import io.vavr.control.Try; +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.vavr.API.Try; +import static org.onap.dcae.common.publishing.VavrUtils.enhanceError; +import static org.onap.dcae.common.publishing.VavrUtils.f; + +final class ConfigSource { + + private static final Logger log = LoggerFactory.getLogger(ConfigSource.class); + + static Try<JSONObject> getAppConfig(EnvProps envProps) { + log.info("Fetching app configuration from CBS"); + return callConsulForCBSConfiguration(envProps) + .peek(strBody -> log.info(f("Received following CBS configuration from Consul '%s'", strBody))) + .flatMap(Conversions::toJsonArray) + .flatMap(ConfigSource::withdrawCatalog) + .flatMap(json -> constructFullCBSUrl(envProps, json)) + .flatMap(cbsUrl -> callCBSForAppConfig(envProps, cbsUrl)) + .flatMap(Conversions::toJson) + .peek(jsonNode -> log.info(f("Received app configuration: '%s'", jsonNode))) + .onFailure(exc -> log.error("Could not fetch application config", exc)); + } + + private static Try<String> callConsulForCBSConfiguration(EnvProps envProps) { + return executeGet(envProps.consulProtocol + "://" + envProps.consulHost + ":" + + envProps.consulPort + "/v1/catalog/service/" + envProps.cbsName) + .mapFailure(enhanceError("Unable to retrieve CBS configuration from Consul")); + } + + private static Try<String> constructFullCBSUrl(EnvProps envProps, JSONObject json) { + return Try(() -> envProps.cbsProtocol + "://" + json.get("ServiceAddress").toString() + ":" + + json.get("ServicePort").toString()) + .mapFailure(enhanceError("ServiceAddress / ServicePort missing from CBS conf: '%s'", json)); + } + + private static Try<JSONObject> withdrawCatalog(JSONArray json) { + return Try(() -> new JSONObject(json.get(0).toString())) + .mapFailure(enhanceError("CBS response '%s' is in invalid format," + + " most probably is it not a list of configuration objects", json)); + } + + private static Try<String> callCBSForAppConfig(EnvProps envProps, String cbsUrl) { + log.info("Calling CBS for application config"); + return executeGet(cbsUrl + "/service_component/" + envProps.appName) + .mapFailure(enhanceError("Unable to fetch configuration from CBS")); + } + + + private static Try<String> executeGet(String url) { + log.info(f("Calling HTTP GET on url: '%s'", url)); + return Try(() -> Unirest.get(url).asString()) + .mapFailure(enhanceError("Http call (GET '%s') failed.", url)) + .filter( + res -> res.getStatus() == 200, + res -> new RuntimeException(f("HTTP call (GET '%s') failed with status %s and body '%s'", + url, res.getStatus(), res.getBody()))) + .map(HttpResponse::getBody) + .peek(body -> log.info(f("HTTP GET on '%s' returned body '%s'", url, body))); + } + +} diff --git a/src/main/java/org/onap/dcae/controller/ControllerConfigInfo.java b/src/main/java/org/onap/dcae/controller/ControllerConfigInfo.java new file mode 100644 index 0000000..2941b9b --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/ControllerConfigInfo.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.restconf + * ================================================================================ + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +public class ControllerConfigInfo { + private String controller_name; + private String controller_restapiUrl; + private String controller_restapiUser; + private String controller_restapiPassword; + private String controller_accessTokenUrl; + private String controller_accessTokenFile; + private String controller_subscriptionUrl; + private String controller_accessTokenMethod; + private String controller_subsMethod; + + public ControllerConfigInfo(String controller_name, + String controller_restapiUrl, + String controller_restapiUser, + String controller_restapiPassword, + String controller_accessTokenUrl, + String controller_accessTokenFile, + String controller_subscriptionUrl, + String controller_accessTokenMethod, + String controller_subsMethod) { + this.controller_name = controller_name; + this.controller_restapiUrl = controller_restapiUrl; + this.controller_restapiUser = controller_restapiUser; + this.controller_restapiPassword = controller_restapiPassword; + this.controller_accessTokenUrl = controller_accessTokenUrl; + this.controller_accessTokenFile = controller_accessTokenFile; + this.controller_subscriptionUrl = controller_subscriptionUrl; + this.controller_accessTokenMethod = controller_accessTokenMethod; + this.controller_subsMethod = controller_subsMethod; + } + + public String getController_name() { + return controller_name; + } + + public String getController_restapiUrl() { + return controller_restapiUrl; + } + + public String getController_restapiUser() { + return controller_restapiUser; + } + + public String getController_restapiPassword() { + return controller_restapiPassword; + } + + public String getController_accessTokenUrl() { + return controller_accessTokenUrl; + } + + public String getController_accessTokenFile() { + return controller_accessTokenFile; + } + + public String getController_accessTokenMethod() { + return controller_accessTokenMethod; + } + + public String getController_subsMethod() { + return controller_subsMethod; + } + + public String getController_subscriptionUrl() { + return controller_subscriptionUrl; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/dcae/controller/Conversions.java b/src/main/java/org/onap/dcae/controller/Conversions.java new file mode 100644 index 0000000..0a3e7c7 --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/Conversions.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import static org.onap.dcae.common.publishing.VavrUtils.enhanceError; + +import io.vavr.API; +import io.vavr.collection.List; +import io.vavr.control.Try; +import java.util.Iterator; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.StreamSupport; +import org.json.JSONArray; +import org.json.JSONObject; + +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +interface Conversions { + + static Try<JSONObject> toJson(String strBody) { + return API.Try(() -> new JSONObject(strBody)) + .mapFailure(enhanceError("Value '%s' is not a valid JSON document", strBody)); + } + + static Try<JSONArray> toJsonArray(String strBody) { + return API.Try(() -> new JSONArray(strBody)) + .mapFailure(enhanceError("Value '%s' is not a valid JSON array", strBody)); + } + + static <T> List<T> toList(Iterator<T> iterator) { + return List.ofAll(StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)); + } + +} diff --git a/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java b/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java new file mode 100644 index 0000000..3feeacc --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/EnvPropertiesReader.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import io.vavr.collection.Map; +import io.vavr.control.Option; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.vavr.API.List; +import static io.vavr.API.Try; +import static org.onap.dcae.common.publishing.VavrUtils.f; + +final class EnvPropertiesReader { + + private final static Logger log = LoggerFactory.getLogger(EnvPropertiesReader.class); + + static Option<EnvProps> readEnvProps(Map<String, String> environmentVariables) { + log.info("Loading necessary environment variables for dynamic configuration update"); + int consulPort = getConsulPort(environmentVariables); + String consulProtocol = getConsulProtocol(environmentVariables); + String cbsProtocol = getCbsProtocol(environmentVariables); + Option<String> consulHost = getConsulHost(environmentVariables); + Option<String> cbsServiceName = getCBSName(environmentVariables); + Option<String> collectorAppName = getAppName(environmentVariables); + return Option.sequence(List(consulHost, cbsServiceName, collectorAppName)) + .map(e -> new EnvProps(consulProtocol, e.get(0), consulPort, cbsProtocol, e.get(1), e.get(2))) + .onEmpty(() -> log.warn("Some required environment variables are missing")) + .peek(props -> log.info(f("Discovered following environment variables: '%s'", props))); + } + + private static Option<String> getAppName(Map<String, String> environmentVariables) { + return environmentVariables.get("HOSTNAME") + .orElse(environmentVariables.get("SERVICE_NAME")) + .onEmpty(() -> log.warn("App service name (as registered in CBS) (env var: 'HOSTNAME' / 'SERVICE_NAME') " + + "is missing error environment variables.")); + } + + private static Option<String> getCBSName(Map<String, String> environmentVariables) { + return environmentVariables.get("CONFIG_BINDING_SERVICE") + .onEmpty(() -> log.warn("Name of CBS Service (as registered in Consul) (env var: 'CONFIG_BINDING_SERVICE') " + + "is missing from environment variables.")); + } + + private static Integer getConsulPort(Map<String, String> environmentVariables) { + return environmentVariables.get("CONSUL_PORT") + .flatMap(str -> Try(() -> Integer.valueOf(str)) + .onFailure(exc -> log.warn("Consul port is not an integer value", exc)) + .toOption()) + .onEmpty(() -> log.warn("Consul port (env var: 'CONSUL_PORT') is missing from environment variables. " + + "Using default value of 8500")) + .getOrElse(8500); + } + + private static Option<String> getConsulHost(Map<String, String> environmentVariables) { + return environmentVariables.get("CONSUL_HOST") + .onEmpty(() -> log.warn("Consul host (env var: 'CONSUL_HOST') (without port) " + + "is missing from environment variables.")); + } + + private static String getConsulProtocol(Map<String, String> environmentVariables) { + return getProtocolFrom("CONSUL_PROTOCOL", environmentVariables); + } + + private static String getCbsProtocol(Map<String, String> environmentVariables) { + return getProtocolFrom("CBS_PROTOCOL", environmentVariables); + } + + private static String getProtocolFrom(String variableName, Map<String, String> environmentVariables) { + return environmentVariables.get(variableName) + .onEmpty(() -> log.warn("Consul protocol (env var: '" + variableName + "') is missing " + + "from environment variables.")) + .getOrElse("http"); + } + +} diff --git a/src/main/java/org/onap/dcae/controller/EnvProps.java b/src/main/java/org/onap/dcae/controller/EnvProps.java new file mode 100644 index 0000000..a2d381d --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/EnvProps.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.controller; + +import java.util.Objects; + +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +final class EnvProps { + + final String consulProtocol; + final String consulHost; + final int consulPort; + final String cbsName; + final String cbsProtocol; + final String appName; + + EnvProps(String consulProtocol, String consulHost, int consulPort, String cbsProtocol, String cbsName, String appName) { + this.consulProtocol = consulProtocol; + this.consulHost = consulHost; + this.consulPort = consulPort; + this.cbsProtocol = cbsProtocol; + this.cbsName = cbsName; + this.appName = appName; + } + + @Override + public String toString() { + return "EnvProps{" + + "consulProtocol='" + consulProtocol + '\'' + + ", consulHost='" + consulHost + '\'' + + ", consulPort=" + consulPort + + ", cbsProtocol='" + cbsProtocol + '\'' + + ", cbsName='" + cbsName + '\'' + + ", appName='" + appName + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EnvProps envProps = (EnvProps) o; + return consulPort == envProps.consulPort && + Objects.equals(consulProtocol, envProps.consulProtocol) && + Objects.equals(consulHost, envProps.consulHost) && + Objects.equals(cbsProtocol, envProps.cbsProtocol) && + Objects.equals(cbsName, envProps.cbsName) && + Objects.equals(appName, envProps.appName); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/dcae/controller/PersistentEventConnection.java b/src/main/java/org/onap/dcae/controller/PersistentEventConnection.java new file mode 100644 index 0000000..1c0d85b --- /dev/null +++ b/src/main/java/org/onap/dcae/controller/PersistentEventConnection.java @@ -0,0 +1,207 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.collectors.restconf + * ================================================================================ + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.controller; + +import org.glassfish.jersey.media.sse.EventSource; +import org.glassfish.jersey.media.sse.SseFeature; +import org.onap.dcae.common.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.HttpHeaders; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import static org.onap.dcae.common.RestapiCallNodeUtil.*; + +public class PersistentEventConnection implements Runnable { + public String event_name; + private String event_description; + private boolean event_sseventUrlEmbed; + private String event_sseventsField; + private String event_sseventsUrl; + private String event_subscriptionTemplate; + private String event_unSubscriptionTemplate; + private String event_ruleId; + private EventConnectionState state; + private volatile boolean running = true; + private static final Logger log = LoggerFactory.getLogger(PersistentEventConnection.class); + + + private RestConfContext ctx; + private AccessController parentCtrllr; + private Map<String, String> eventParaMap; + + public PersistentEventConnection(String event_name, + String event_description, + boolean event_sseventUrlEmbed, + String event_sseventsField, + String event_sseventsUrl, + String event_subscriptionTemplate, + String event_unSubscriptionTemplate, + String event_ruleId, + AccessController parentCtrllr) { + this.event_name = event_name; + this.event_description = event_description; + this.event_sseventUrlEmbed = event_sseventUrlEmbed; + this.event_sseventsField = event_sseventsField; + this.event_sseventsUrl = event_sseventsUrl; + this.event_subscriptionTemplate = event_subscriptionTemplate; + this.event_unSubscriptionTemplate = event_unSubscriptionTemplate; + this.event_ruleId = event_ruleId; + this.state = EventConnectionState.INIT; + + this.ctx = new RestConfContext(); + for (String s : parentCtrllr.getCtx().getAttributeKeySet()) { + this.ctx.setAttribute(s, ctx.getAttribute(s)); + } + this.parentCtrllr = parentCtrllr; + this.eventParaMap = new HashMap<>(); + this.eventParaMap.putAll(parentCtrllr.getParaMap()); + printEventParamMap(); + log.info("New persistent connection created " + event_name); + } + + @Override + public void run() { + Parameters p = null; + try { + modifyEventParamMap(Constants.KSETTING_REST_API_URL, getUriMethod(parentCtrllr.getProperties().authorizationEnabled()) + + parentCtrllr.getCfgInfo().getController_restapiUrl() + + parentCtrllr.getCfgInfo().getController_subscriptionUrl()); + modifyEventParamMap(Constants.KDEFAULT_TEMP_FILENAME, event_subscriptionTemplate); + modifyEventParamMap(Constants.KSETTING_REST_UNAME, parentCtrllr.getCfgInfo().getController_restapiUser()); + modifyEventParamMap(Constants.KSETTING_REST_PASSWORD, parentCtrllr.getCfgInfo().getController_restapiPassword()); + modifyEventParamMap(Constants.KSETTING_HTTP_METHOD, parentCtrllr.getCfgInfo().getController_subsMethod()); + + parentCtrllr.getRestApiCallNode().sendRequest(eventParaMap, ctx, null); + } catch (Exception e) { + log.error("Exception occured!", e); + Thread.currentThread().interrupt(); + } + + /* Retrieve url from result and construct SSE url */ + if (event_sseventUrlEmbed) { + String key = getEventParamMapValue(Constants.KSETTING_RESP_PREFIX).concat(".").concat(event_sseventsField); + log.info("key " + key); + this.event_sseventsUrl = ctx.getAttribute(key); + } + + log.info("SSE received url " + event_sseventsUrl); + try { + p = getParameters(eventParaMap); + } catch (Exception e) { + log.error("Exception occured!", e); + Thread.currentThread().interrupt(); + } + printEventParamMap(); + String url = getUriMethod(parentCtrllr.getProperties().authorizationEnabled()) + + parentCtrllr.getCfgInfo().getController_restapiUrl() + event_sseventsUrl; + Client client = ignoreSslClient().register(SseFeature.class); + WebTarget target = addAuthType(client, p).target(url); + String tokenId = getEventParamMapValue(Constants.KSETTING_TOKENID); + String headerName = "X-ACCESS-TOKEN"; + if (tokenId == null) { + headerName = HttpHeaders.AUTHORIZATION; + tokenId = getAuthorizationToken(parentCtrllr.getCfgInfo().getController_restapiUser(), + parentCtrllr.getCfgInfo().getController_restapiPassword()); + } + AdditionalHeaderWebTarget newTarget = new AdditionalHeaderWebTarget(target, tokenId, headerName); + EventSource eventSource = EventSource.target(newTarget).build(); + eventSource.register(new DataChangeEventListener(this)); + eventSource.open(); + log.info("Connected to SSE source"); + while (running) { + try { + log.info("SSE state " + eventSource.isOpen()); + Thread.sleep(5000); + } catch (InterruptedException ie) { + log.info("Exception: " + ie.getMessage()); + Thread.currentThread().interrupt(); + running = false; + } + } + eventSource.close(); + log.info("Closed connection to SSE source"); + } + + private String getAuthorizationToken(String userName, String password) { + return "Basic " + Base64.getEncoder().encodeToString(( + userName + ":" + password).getBytes()); + } + + private Client ignoreSslClient() { + SSLContext sslcontext = null; + + try { + sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(null, new TrustManager[]{new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }}, new java.security.SecureRandom()); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new IllegalStateException(e); + } + + return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build(); + } + + public String getEvent_ruleId() { + return event_ruleId; + } + + public void modifyEventParamMap(String fieldName, String value) { + eventParaMap.put(fieldName, value); + } + + public String getEventParamMapValue(String fieldName) { + return eventParaMap.get(fieldName); + } + + public void printEventParamMap() { + log.info("----------------Event Param Map-------------------"); + for (String name : eventParaMap.keySet()) { + String value = eventParaMap.get(name); + log.info(name + " : " + value); + } + } +} diff --git a/src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java b/src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java new file mode 100644 index 0000000..654ad20 --- /dev/null +++ b/src/main/java/org/onap/dcae/restapi/ApiAuthInterceptor.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.restapi; + +import io.vavr.control.Option; +import java.io.IOException; +import java.util.Base64; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.onap.dcae.ApplicationSettings; +import org.onap.dcaegen2.services.sdk.security.CryptPassword; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +final class ApiAuthInterceptor extends HandlerInterceptorAdapter { + + private static final Logger LOG = LoggerFactory.getLogger(ApiAuthInterceptor.class); + private final CryptPassword cryptPassword = new CryptPassword(); + private final ApplicationSettings applicationSettings; + + + + ApiAuthInterceptor(ApplicationSettings applicationSettings) { + this.applicationSettings = applicationSettings; + + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, + Object handler) throws IOException { + if (applicationSettings.authorizationEnabled()) { + String authorizationHeader = request.getHeader("Authorization"); + if (authorizationHeader == null || !isAuthorized(authorizationHeader)) { + response.setStatus(400); + + response.getWriter().write(ApiException.UNAUTHORIZED_USER.toJSON().toString()); + return false; + } + } + return true; + } + + private boolean isAuthorized(String authorizationHeader) { + try { + String encodedData = authorizationHeader.split(" ")[1]; + String decodedData = new String(Base64.getDecoder().decode(encodedData)); + String providedUser = decodedData.split(":")[0].trim(); + String providedPassword = decodedData.split(":")[1].trim(); + Option<String> maybeSavedPassword = applicationSettings.validAuthorizationCredentials().get(providedUser); + boolean userRegistered = maybeSavedPassword.isDefined(); + return userRegistered && cryptPassword.matches(providedPassword,maybeSavedPassword.get()); + } catch (Exception e) { + LOG.warn(String.format("Could not check if user is authorized (header: '%s')), probably malformed header.", + authorizationHeader), e); + return false; + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/dcae/restapi/ApiConfiguration.java b/src/main/java/org/onap/dcae/restapi/ApiConfiguration.java new file mode 100644 index 0000000..28a61bc --- /dev/null +++ b/src/main/java/org/onap/dcae/restapi/ApiConfiguration.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.restapi; + +import org.onap.dcae.ApplicationSettings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@EnableWebMvc +@Configuration +public class ApiConfiguration implements WebMvcConfigurer { + + private final ApplicationSettings applicationSettings; + + + @Autowired + ApiConfiguration(ApplicationSettings applicationSettings) { + this.applicationSettings = applicationSettings; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new ApiAuthInterceptor(applicationSettings)); + } +} diff --git a/src/main/java/org/onap/dcae/restapi/ApiException.java b/src/main/java/org/onap/dcae/restapi/ApiException.java new file mode 100644 index 0000000..d8c21b1 --- /dev/null +++ b/src/main/java/org/onap/dcae/restapi/ApiException.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.restapi; + +import com.google.common.base.CaseFormat; +import org.json.JSONObject; + +/** + * @author Pawel Szalapski (pawel.szalapski@nokia.com) + */ +public enum ApiException { + UNAUTHORIZED_USER(ExceptionType.POLICY_EXCEPTION, "POL2000", "Unauthorized user", 401); + + public final int httpStatusCode; + private final ExceptionType type; + private final String code; + private final String details; + + ApiException(ExceptionType type, String code, String details, int httpStatusCode) { + this.type = type; + this.code = code; + this.details = details; + this.httpStatusCode = httpStatusCode; + } + + public JSONObject toJSON() { + JSONObject exceptionTypeNode = new JSONObject(); + exceptionTypeNode.put("messageId", code); + exceptionTypeNode.put("text", details); + + JSONObject requestErrorNode = new JSONObject(); + requestErrorNode.put(type.toString(), exceptionTypeNode); + + JSONObject rootNode = new JSONObject(); + rootNode.put("requestError", requestErrorNode); + return rootNode; + } + + public enum ExceptionType { + POLICY_EXCEPTION; + + @Override + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, this.name()); + } + } + +} diff --git a/src/main/java/org/onap/dcae/collectors/restconf/common/RetryPolicyStore.java b/src/main/java/org/onap/dcae/restapi/RccRestController.java index 0d1762f..75cfa15 100755..100644 --- a/src/main/java/org/onap/dcae/collectors/restconf/common/RetryPolicyStore.java +++ b/src/main/java/org/onap/dcae/restapi/RccRestController.java @@ -1,8 +1,8 @@ -/*- +/* * ============LICENSE_START======================================================= - * org.onap.dcaegen2.collectors.restconf + * org.onap.dcaegen2.restconfcollector * ================================================================================ - * Copyright (C) 2018 Huawei. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,36 +18,24 @@ * ============LICENSE_END========================================================= */ -package org.onap.dcae.collectors.restconf.common; +package org.onap.dcae.restapi; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; +@RestController +public class RccRestController { + private static final Logger log = LoggerFactory.getLogger(RccRestController.class); -public class RetryPolicyStore { - private static final Logger log = LoggerFactory.getLogger(RetryPolicyStore.class); - - HashMap<String, RetryPolicy> retryPolicies; - public String proxyServers; - - public String getProxyServers() { - return proxyServers; - } - - public void setProxyServers(String admServers) { - this.proxyServers = admServers; - String[] adminServersArray = admServers.split(","); - RetryPolicy adminPortalRetry = new RetryPolicy(adminServersArray, adminServersArray.length); - retryPolicies.put("dme2proxy", adminPortalRetry); + @GetMapping("/") + String mainPage() { + return "Welcome to RestConfCollector"; } - public RetryPolicyStore() { - retryPolicies = new HashMap<>(); + @GetMapping("/healthcheck") + public String healthy() { + return "hello"; } - - public RetryPolicy getRetryPolicy(String policyName) { - return (this.retryPolicies.get(policyName)); - } - -} +}
\ No newline at end of file diff --git a/src/main/java/org/onap/dcae/restapi/ServletConfig.java b/src/main/java/org/onap/dcae/restapi/ServletConfig.java new file mode 100644 index 0000000..6a6a761 --- /dev/null +++ b/src/main/java/org/onap/dcae/restapi/ServletConfig.java @@ -0,0 +1,108 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.restapi; + +import org.onap.dcae.ApplicationException; +import org.onap.dcae.ApplicationSettings; +import org.onap.dcae.common.SSLContextCreator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static java.nio.file.Files.readAllBytes; + +@Component +public class ServletConfig implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> { + + private static final Logger log = LoggerFactory.getLogger(ServletConfig.class); + + @Autowired + private ApplicationSettings properties; + + @Override + public void customize(ConfigurableServletWebServerFactory container) { + final boolean hasClientTlsAuthentication = properties.clientTlsAuthenticationEnabled(); + log.info("WebServerFactoryCustomizer initializing........"); + if (hasClientTlsAuthentication || properties.authorizationEnabled()) { + container.setSsl(hasClientTlsAuthentication ? httpsContextWithTlsAuthentication() : simpleHttpsContext()); + container.setPort(properties.httpsPort()); + } else { + container.setPort(properties.httpPort()); + } + } + + private SSLContextCreator simpleHttpsContextBuilder() { + log.info("Enabling SSL"); + + final Path keyStore = toAbsolutePath(properties.rcc_keystoreFileLocation()); + log.info("Using keyStore path: " + keyStore); + + final Path keyStorePasswordLocation = toAbsolutePath(properties.rcc_keystorePasswordFileLocation()); + final String keyStorePassword = getKeyStorePassword(keyStorePasswordLocation); + log.info("Using keyStore password from: " + keyStorePasswordLocation); + + final String alias = properties.keystoreAlias(); + + return SSLContextCreator.create(keyStore, alias, keyStorePassword); + } + + private Ssl simpleHttpsContext() { + return simpleHttpsContextBuilder().build(); + } + + private Ssl httpsContextWithTlsAuthentication() { + final SSLContextCreator sslContextCreator = simpleHttpsContextBuilder(); + + log.info("Enabling TLS client authorization"); + + final Path trustStore = toAbsolutePath(properties.truststoreFileLocation()); + log.info("Using trustStore path: " + trustStore); + + final Path trustPasswordFileLocation = toAbsolutePath(properties.truststorePasswordFileLocation()); + final String trustStorePassword = getKeyStorePassword(trustPasswordFileLocation); + log.info("Using trustStore password from: " + trustPasswordFileLocation); + + return sslContextCreator.withTlsClientAuthentication(trustStore, trustStorePassword).build(); + } + + private Path toAbsolutePath(final String path) { + return Paths.get(path).toAbsolutePath(); + } + + private String getKeyStorePassword(final Path location) { + try { + return new String(readAllBytes(location)); + } catch (IOException e) { + log.error("Could not read keystore password from: '" + location + "'.", e); + throw new ApplicationException(e); + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/dcae/restapi/SwaggerConfig.java b/src/main/java/org/onap/dcae/restapi/SwaggerConfig.java new file mode 100644 index 0000000..fc47ba8 --- /dev/null +++ b/src/main/java/org/onap/dcae/restapi/SwaggerConfig.java @@ -0,0 +1,44 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.restapi; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.any()) + .paths(PathSelectors.any()) + .build(); + } + +} diff --git a/src/main/java/org/onap/dcae/restapi/WebMvcConfig.java b/src/main/java/org/onap/dcae/restapi/WebMvcConfig.java new file mode 100644 index 0000000..d015b45 --- /dev/null +++ b/src/main/java/org/onap/dcae/restapi/WebMvcConfig.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.dcaegen2.restconfcollector + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. + * Copyright (C) 2018-2019 Huawei. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.dcae.restapi; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + +@Configuration +public class WebMvcConfig extends WebMvcConfigurationSupport { + + @Override + protected void addResourceHandlers(ResourceHandlerRegistry registry) { + registry + .addResourceHandler("swagger-ui.html") + .addResourceLocations("classpath:/META-INF/resources/"); + + registry + .addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/"); + + registry + .addResourceHandler("**") + .addResourceLocations("classpath:/templates/"); + } + + @Bean + public InternalResourceViewResolver jspViewResolver() { + InternalResourceViewResolver resolver = new InternalResourceViewResolver(); + resolver.setPrefix("/"); + resolver.setSuffix(".html"); + return resolver; + } + +} |