diff options
author | 2020-04-08 09:31:13 +0200 | |
---|---|---|
committer | 2020-04-08 09:43:31 +0000 | |
commit | 3c494af52c476a86ae1389991b464914517774b8 (patch) | |
tree | e6d9b4f261eac5f7b3fd0f42e740840a106842e6 /pnfsimulator/src/main | |
parent | 75496bfc5b2f7e03e49ab4929d1f20962b39c992 (diff) |
Move PNF simulator from /test/mocks to new project
This code is a copy of pnfsimulator located in integration repository
(/test/mocks/pnfsimulator) with added profile "docker" in pom.xml
located in pnfsimulator and netconfsimulator subprojects
Issue-ID: INT-1517
Signed-off-by: Bartosz Gardziejewski <bartosz.gardziejewski@nokia.com>
Change-Id: I725fa0530c41b13cb12705979dee8b8b354dc1a1
Diffstat (limited to 'pnfsimulator/src/main')
60 files changed, 3930 insertions, 0 deletions
diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java new file mode 100644 index 0000000..e0eace2 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator; + +import javax.annotation.PostConstruct; + +import org.onap.pnfsimulator.filesystem.WatcherService; +import org.onap.pnfsimulator.template.FsToDbTemplateSynchronizer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +@SpringBootApplication +@EnableAsync +public class Main { + + private final WatcherService watcherService; + private final FsToDbTemplateSynchronizer fsToDbTemplateSynchronizer; + + @Autowired + public Main(WatcherService watcherService, + FsToDbTemplateSynchronizer fsToDbTemplateSynchronizer) { + this.watcherService = watcherService; + this.fsToDbTemplateSynchronizer = fsToDbTemplateSynchronizer; + } + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } + + @PostConstruct + public void createWatchers() { + fsToDbTemplateSynchronizer.synchronize(); + watcherService.createWatcher(); + } +} + + diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java new file mode 100644 index 0000000..6e0e18e --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator; + +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +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 +@EnableConfigurationProperties(SSLAuthenticationHelper.class) +@EnableSwagger2 +public class SwaggerConfig { + + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("org.onap.pnfsimulator")) + .paths(PathSelectors.any()) + .build(); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Row.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Row.java new file mode 100644 index 0000000..f9a167b --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Row.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.db; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Field; + +public abstract class Row { + @Id + @Field("_id") + protected String id; + + public String getId() { + return id; + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Storage.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Storage.java new file mode 100644 index 0000000..ad98ce0 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Storage.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.db; + +import com.google.gson.JsonObject; + +import java.util.List; +import java.util.Optional; + +public interface Storage<T extends Row> { + + List<T> getAll(); + + Optional<T> get(String rowId); + + void persist(T row); + + boolean tryPersistOrOverwrite(T row, boolean overwrite); + + void delete(String rowId); + + List<String> getIdsByContentCriteria(JsonObject queryJson); +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventData.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventData.java new file mode 100644 index 0000000..23b1c21 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventData.java @@ -0,0 +1,76 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.event; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Field; + +@Builder +@Getter +@Setter +public class EventData { + @Id + private String id; + + @Field("template") + @JsonInclude + private String template; + + @Field("patched") + @JsonInclude + private String patched; + + @Field("input") + @JsonInclude + private String input; + + @Field("keywords") + @JsonInclude + private String keywords; + + @Field("incrementValue") + @JsonInclude + private int incrementValue; + + protected EventData(String id, String template, String patched, String input, String keywords, int incrementValue) { + this.id = id; + this.template = template; + this.patched = patched; + this.input = input; + this.keywords = keywords; + this.incrementValue = incrementValue; + } + + @Override + public String toString() { + return "EventData{" + + "id='" + id + '\'' + + ", template='" + template + '\'' + + ", patched='" + patched + '\'' + + ", input='" + input + '\'' + + ", keywords='" + keywords + '\'' + + '}'; + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataRepository.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataRepository.java new file mode 100644 index 0000000..d1a66ab --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataRepository.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.event; + +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface EventDataRepository extends MongoRepository<EventData, String> { +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataService.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataService.java new file mode 100644 index 0000000..3568f01 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataService.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.event; + +import com.google.gson.JsonObject; +import java.util.List; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class EventDataService { + private final EventDataRepository repository; + + @Autowired + public EventDataService(EventDataRepository repository) { + this.repository = repository; + } + + private EventData persistEventData(String templateString, String patchedString, String inputString, String keywordsString) { + EventData eventData = EventData.builder() + .template(templateString) + .patched(patchedString) + .input(inputString) + .keywords(keywordsString) + .build(); + return repository.save(eventData); + } + + public EventData persistEventData(JsonObject templateJson, JsonObject patchedJson, JsonObject inputJson, + JsonObject keywordsJson) { + return persistEventData(templateJson.toString(), + patchedJson.toString(), + inputJson.toString(), + keywordsJson.toString()); + } + + public List<EventData> getAllEvents() { + return repository.findAll(); + } + + public Optional<EventData> getById(String id) { + return repository.findById(id); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherConfig.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherConfig.java new file mode 100644 index 0000000..3535e33 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherConfig.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.filesystem; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +public class WatcherConfig { + + @Bean + public TaskExecutor watcherTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setThreadNamePrefix("pnfsimulator_fs_watcher"); + executor.initialize(); + return executor; + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessor.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessor.java new file mode 100644 index 0000000..56a5696 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessor.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.filesystem; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchEvent.Kind; +import java.time.Instant; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import lombok.extern.slf4j.Slf4j; +import org.bson.json.JsonParseException; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.Template; +import org.bson.Document; + +@Slf4j +public enum WatcherEventProcessor { + CREATED(StandardWatchEventKinds.ENTRY_CREATE) { + @Override + public void processEvent(Path path, Storage<Template> storage) throws IOException { + String content = getContent(path); + String fileName = path.getFileName().toString(); + Document documentsContent = Document.parse(content); + storage.persist(new Template(fileName, documentsContent, Instant.now().getNano())); + log.info("DB record created for template: " + fileName); + } + }, + MODIFIED(StandardWatchEventKinds.ENTRY_MODIFY) { + @Override + public void processEvent(Path path, Storage<Template> storage) throws IOException { + String fileName = path.getFileName().toString(); + String content = getContent(path); + Document documentsContent = Document.parse(content); + Template template = storage.get(fileName).orElse(new Template(fileName, documentsContent, Instant.now().getNano())); + template.setContent(documentsContent); + storage.persist(template); + log.info("DB record modified for template: " + fileName); + } + }, + DELETED(StandardWatchEventKinds.ENTRY_DELETE) { + @Override + public void processEvent(Path path, Storage<Template> storage) { + String fileName = path.getFileName().toString(); + storage.delete(fileName); + log.info("DB record deleted for template: " + fileName); + } + }; + + private final Kind<Path> pathKind; + + String getContent(Path path) throws IOException { + try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) { + return lines.collect(Collectors.joining(System.lineSeparator())); + } catch (IOException e) { + log.error("Could not get content due to: " + e.getMessage() + " " + e.getCause(), e); + throw e; + } + } + + WatcherEventProcessor(Kind<Path> pathKind) { + this.pathKind = pathKind; + } + + public abstract void processEvent(Path templateName, Storage<Template> storage) throws IOException; + + static void process(WatchEvent<?> event, Storage<Template> storage, Path templatesDir) { + Optional<WatcherEventProcessor> watcherEventProcessor = getWatcherEventProcessor(event); + watcherEventProcessor.ifPresent(processor -> { + try { + final Path templatePath = templatesDir.resolve((Path) event.context()); + processor.processEvent(templatePath, storage); + } catch (IOException e) { + log.error("Error during processing DB record for template.", e); + } catch (JsonParseException e) { + log.error("Invalid JSON format provided for template.", e); + } + }); + } + + private static Optional<WatcherEventProcessor> getWatcherEventProcessor(WatchEvent<?> event) { + return Arrays.stream(values()).filter(value -> value.pathKind.equals(event.kind())).findFirst(); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherService.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherService.java new file mode 100644 index 0000000..26b684d --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherService.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.filesystem; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.task.TaskExecutor; +import org.springframework.stereotype.Service; + +@Service +public class WatcherService { + + private TaskExecutor taskExecutor; + private ApplicationContext applicationContext; + + @Autowired + public WatcherService(ApplicationContext applicationContext, TaskExecutor taskExecutor) { + this.taskExecutor = taskExecutor; + this.applicationContext = applicationContext; + } + + public void createWatcher() { + taskExecutor.execute(applicationContext.getBean(WatcherThread.class)); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherThread.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherThread.java new file mode 100644 index 0000000..a202b1f --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherThread.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.filesystem; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import lombok.extern.slf4j.Slf4j; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.Template; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class WatcherThread implements Runnable { + + private final WatchService watchService; + private final Storage<Template> storage; + private final Path templatesDir; + + WatcherThread(String templatesDir, WatchService watchService, Storage<Template> storage) throws IOException { + this.watchService = watchService; + this.storage = storage; + this.templatesDir = Paths.get(templatesDir); + registerDirectory(this.templatesDir); + } + + @Autowired + public WatcherThread(@Value("${templates.dir}") String templatesDir, Storage<Template> storage) throws IOException { + this(templatesDir, FileSystems.getDefault().newWatchService(), storage); + } + + private void registerDirectory(Path path) throws IOException { + path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, + StandardWatchEventKinds.ENTRY_MODIFY); + } + + @Override + public void run() { + while (true) { + WatchKey key; + try { + key = watchService.take(); + for (WatchEvent<?> event : key.pollEvents()) { + WatcherEventProcessor.process(event, storage, templatesDir); + } + key.reset(); + } catch (InterruptedException e) { + log.error("Watch service interrupted.", e.getMessage()); + Thread.currentThread().interrupt(); + return; + } + + } + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/logging/MDCVariables.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/logging/MDCVariables.java new file mode 100644 index 0000000..5678f4f --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/logging/MDCVariables.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.logging; + +public final class MDCVariables { + + public static final String X_ONAP_REQUEST_ID = "X-ONAP-RequestID"; + public static final String X_INVOCATION_ID = "X-InvocationID"; + public static final String REQUEST_ID = "RequestID"; + public static final String INVOCATION_ID = "InvocationID"; + public static final String INSTANCE_UUID = "InstanceUUID"; + public static final String RESPONSE_CODE = "ResponseCode"; + public static final String SERVICE_NAME = "ServiceName"; + + private MDCVariables() { + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java new file mode 100644 index 0000000..0e4bd56 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java @@ -0,0 +1,219 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.rest; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonSyntaxException; +import org.json.JSONException; +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataService; +import org.onap.pnfsimulator.rest.model.FullEvent; +import org.onap.pnfsimulator.rest.model.SimulatorRequest; +import org.onap.pnfsimulator.rest.util.DateUtil; +import org.onap.pnfsimulator.rest.util.ResponseBuilder; +import org.onap.pnfsimulator.simulator.SimulatorService; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; +import org.quartz.SchedulerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.GeneralSecurityException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.onap.pnfsimulator.logging.MDCVariables.INSTANCE_UUID; +import static org.onap.pnfsimulator.logging.MDCVariables.INVOCATION_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.REQUEST_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.RESPONSE_CODE; +import static org.onap.pnfsimulator.logging.MDCVariables.SERVICE_NAME; +import static org.onap.pnfsimulator.logging.MDCVariables.X_INVOCATION_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.X_ONAP_REQUEST_ID; +import static org.onap.pnfsimulator.rest.util.ResponseBuilder.MESSAGE; +import static org.onap.pnfsimulator.rest.util.ResponseBuilder.TIMESTAMP; +import static org.springframework.http.HttpStatus.ACCEPTED; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; + +@RestController +@RequestMapping("/simulator") +public class SimulatorController { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorController.class); + private static final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); + private static final String INCORRECT_TEMPLATE_MESSAGE = "Cannot start simulator, template %s is not in valid format: %s"; + private static final String NOT_EXISTING_TEMPLATE = "Cannot start simulator - template %s not found."; + private final DateFormat responseDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss,SSS"); + private final SimulatorService simulatorService; + private EventDataService eventDataService; + + @Autowired + public SimulatorController(SimulatorService simulatorService, + EventDataService eventDataService) { + this.simulatorService = simulatorService; + this.eventDataService = eventDataService; + } + + @PostMapping("test") + @Deprecated + public ResponseEntity test(@Valid @RequestBody SimulatorRequest simulatorRequest) { + MDC.put("test", "test"); + LOGGER.info(ENTRY, simulatorRequest.toString()); + return buildResponse(OK, ImmutableMap.of(MESSAGE, "message1234")); + } + + @PostMapping(value = "start") + public ResponseEntity start(@RequestHeader HttpHeaders headers, + @Valid @RequestBody SimulatorRequest triggerEventRequest) { + logContextHeaders(headers, "/simulator/start"); + LOGGER.info(ENTRY, "Simulator started"); + + try { + return processRequest(triggerEventRequest); + + } catch (JSONException | JsonSyntaxException e) { + MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); + LOGGER.warn("Cannot trigger event, invalid json format: {}", e.getMessage()); + LOGGER.debug("Received json has invalid format", e); + return buildResponse(BAD_REQUEST, ImmutableMap.of(MESSAGE, String + .format(INCORRECT_TEMPLATE_MESSAGE, triggerEventRequest.getTemplateName(), + e.getMessage()))); + } catch (GeneralSecurityException e ){ + MDC.put(RESPONSE_CODE, INTERNAL_SERVER_ERROR.toString() ); + LOGGER.error("Client certificate validation failed: {}", e.getMessage()); + return buildResponse(INTERNAL_SERVER_ERROR, + ImmutableMap.of(MESSAGE, "Invalid or misconfigured client certificate")); + } + catch (IOException e) { + MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); + LOGGER.warn("Json validation failed: {}", e.getMessage()); + return buildResponse(BAD_REQUEST, + ImmutableMap.of(MESSAGE, String.format(NOT_EXISTING_TEMPLATE, triggerEventRequest.getTemplateName()))); + } catch (Exception e) { + MDC.put(RESPONSE_CODE, INTERNAL_SERVER_ERROR.toString()); + LOGGER.error("Cannot trigger event - unexpected exception", e); + return buildResponse(INTERNAL_SERVER_ERROR, + ImmutableMap.of(MESSAGE, "Unexpected exception: " + e.getMessage())); + } finally { + MDC.clear(); + } + } + + @GetMapping("all-events") + @Deprecated + public ResponseEntity allEvents() { + List<EventData> eventDataList = eventDataService.getAllEvents(); + StringBuilder sb = new StringBuilder(); + eventDataList.forEach(e -> sb.append(e).append(System.lineSeparator())); + + return ResponseBuilder + .status(OK).put(MESSAGE, sb.toString()) + .build(); + } + + @GetMapping("config") + public ResponseEntity getConfig() { + SimulatorConfig configToGet = simulatorService.getConfiguration(); + return buildResponse(OK, ImmutableMap.of("simulatorConfig", configToGet)); + } + + @PutMapping("config") + public ResponseEntity updateConfig(@Valid @RequestBody SimulatorConfig newConfig) { + SimulatorConfig updatedConfig = simulatorService.updateConfiguration(newConfig); + return buildResponse(OK, ImmutableMap.of("simulatorConfig", updatedConfig)); + } + + @PostMapping("cancel/{jobName}") + public ResponseEntity cancelEvent(@PathVariable String jobName) throws SchedulerException { + LOGGER.info(ENTRY, "Cancel called on {}.", jobName); + boolean isCancelled = simulatorService.cancelEvent(jobName); + return createCancelEventResponse(isCancelled); + } + + @PostMapping("cancel") + public ResponseEntity cancelAllEvent() throws SchedulerException { + LOGGER.info(ENTRY, "Cancel called on all jobs"); + boolean isCancelled = simulatorService.cancelAllEvents(); + return createCancelEventResponse(isCancelled); + } + + @PostMapping("event") + public ResponseEntity sendEventDirectly(@RequestHeader HttpHeaders headers, @Valid @RequestBody FullEvent event) + throws IOException, GeneralSecurityException{ + logContextHeaders(headers, "/simulator/event"); + LOGGER.info(ENTRY, "Trying to send one-time event directly to VES Collector"); + simulatorService.triggerOneTimeEvent(event); + return buildResponse(ACCEPTED, ImmutableMap.of(MESSAGE, "One-time direct event sent successfully")); + } + + private ResponseEntity processRequest(SimulatorRequest triggerEventRequest) + throws IOException, SchedulerException, GeneralSecurityException { + + String jobName = simulatorService.triggerEvent(triggerEventRequest); + MDC.put(RESPONSE_CODE, OK.toString()); + return buildResponse(OK, ImmutableMap.of(MESSAGE, "Request started", "jobName", jobName)); + } + + private ResponseEntity buildResponse(HttpStatus endStatus, Map<String, Object> parameters) { + ResponseBuilder builder = ResponseBuilder + .status(endStatus) + .put(TIMESTAMP, DateUtil.getTimestamp(responseDateFormat)); + parameters.forEach(builder::put); + return builder.build(); + } + + private void logContextHeaders(HttpHeaders headers, String serviceName) { + MDC.put(REQUEST_ID, headers.getFirst(X_ONAP_REQUEST_ID)); + MDC.put(INVOCATION_ID, headers.getFirst(X_INVOCATION_ID)); + MDC.put(INSTANCE_UUID, UUID.randomUUID().toString()); + MDC.put(SERVICE_NAME, serviceName); + } + + private ResponseEntity createCancelEventResponse(boolean isCancelled) { + if (isCancelled) { + return buildResponse(OK, ImmutableMap.of(MESSAGE, "Event(s) was cancelled")); + } else { + return buildResponse(NOT_FOUND, ImmutableMap.of(MESSAGE, "Simulator was not able to cancel event(s)")); + } + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/TemplateController.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/TemplateController.java new file mode 100644 index 0000000..444e23b --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/TemplateController.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.rest; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import javax.validation.Valid; + +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.rest.model.TemplateRequest; +import org.onap.pnfsimulator.rest.model.SearchExp; +import org.onap.pnfsimulator.template.Template; +import org.onap.pnfsimulator.template.search.IllegalJsonValueException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + + +@RestController +@RequestMapping("/template") +public class TemplateController { + static final String TEMPLATE_NOT_FOUND_MSG = "A template with given name does not exist"; + static final String CANNOT_OVERRIDE_TEMPLATE_MSG = "Cannot overwrite existing template. Use override=true to override"; + private final Storage<Template> service; + private static final Logger LOG = LoggerFactory.getLogger(TemplateController.class); + + @Autowired + public TemplateController(Storage<Template> service) { + this.service = service; + } + + @GetMapping("list") + public ResponseEntity<?> list() { + return new ResponseEntity<>(service.getAll(), HttpStatus.OK); + } + + @GetMapping("get/{templateName}") + public ResponseEntity<?> get(@PathVariable String templateName) { + Optional<Template> template = service.get(templateName); + if (!template.isPresent()) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.TEXT_PLAIN); + return new ResponseEntity<>(TEMPLATE_NOT_FOUND_MSG, headers, HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(template, HttpStatus.OK); + } + + @PostMapping("upload") + public ResponseEntity<?> upload( + @RequestBody @Valid TemplateRequest templateRequest, + @RequestParam(required = false) boolean override) { + String msg = ""; + HttpStatus status = HttpStatus.CREATED; + Template template = new Template(templateRequest.getName(), templateRequest.getTemplate(), Instant.now().getNano()); + if (!service.tryPersistOrOverwrite(template, override)) { + status = HttpStatus.CONFLICT; + msg = CANNOT_OVERRIDE_TEMPLATE_MSG; + } + return new ResponseEntity<>(msg, status); + } + + @PostMapping("search") + public ResponseEntity<?> searchByCriteria(@RequestBody SearchExp queryJson) { + try { + List<String> templateNames = service.getIdsByContentCriteria(queryJson.getSearchExpr()); + return new ResponseEntity<>(templateNames, HttpStatus.OK); + } catch (IllegalJsonValueException ex) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, String.format("Try again with correct parameters. Cause: %s", ex.getMessage()), ex); + } + + } + + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/FullEvent.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/FullEvent.java new file mode 100644 index 0000000..77d9b3d --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/FullEvent.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * FULL-EVENT + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.rest.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.rest.util.JsonObjectDeserializer; +import org.springframework.lang.Nullable; + +import javax.validation.constraints.NotNull; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@ToString +@EqualsAndHashCode +public class FullEvent { + + @Nullable + private String vesServerUrl; + + @NotNull + @JsonDeserialize(using = JsonObjectDeserializer.class) + private JsonObject event; +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SearchExp.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SearchExp.java new file mode 100644 index 0000000..41d112f --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SearchExp.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.rest.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.rest.util.JsonObjectDeserializer; + +import javax.validation.constraints.NotNull; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class SearchExp { + + @NotNull + @JsonDeserialize(using = JsonObjectDeserializer.class) + private JsonObject searchExpr; +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorParams.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorParams.java new file mode 100644 index 0000000..787583e --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorParams.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.rest.model; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import org.springframework.lang.Nullable; + +@Getter +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +public class SimulatorParams { + + @NotNull + private String vesServerUrl; + + @Nullable + private Integer repeatInterval; + + @Nullable + private Integer repeatCount; + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java new file mode 100644 index 0000000..2b06658 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.rest.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.gson.JsonObject; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.rest.util.JsonObjectDeserializer; +import org.springframework.lang.Nullable; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +public class SimulatorRequest { + + @NotNull + private SimulatorParams simulatorParams; + + @NotNull + private String templateName; + + @Nullable + @JsonDeserialize(using = JsonObjectDeserializer.class) + private JsonObject patch; + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/TemplateRequest.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/TemplateRequest.java new file mode 100644 index 0000000..d5a77f0 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/TemplateRequest.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.rest.model; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.bson.Document; + +@Getter +@Setter +@ToString +public class TemplateRequest { + private String name; + private Document template; + + public TemplateRequest(String name, Document template) { + this.name = name; + this.template = template; + } + + public TemplateRequest() { + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/DateUtil.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/DateUtil.java new file mode 100644 index 0000000..9a5c9ca --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/DateUtil.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.rest.util; + +import java.text.DateFormat; +import java.util.Date; + +public final class DateUtil { + + private DateUtil() { + } + + public static String getTimestamp(DateFormat dateFormat) { + + return dateFormat.format(new Date()); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/JsonObjectDeserializer.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/JsonObjectDeserializer.java new file mode 100644 index 0000000..f89c4a7 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/JsonObjectDeserializer.java @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.rest.util; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import java.io.IOException; + +public class JsonObjectDeserializer extends JsonDeserializer<JsonObject> { + private Gson gson = new Gson(); + + @Override + public JsonObject deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + ObjectCodec oc = jsonParser.getCodec(); + JsonNode node = oc.readTree(jsonParser); + return gson.fromJson(node.toString(), JsonObject.class); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/ResponseBuilder.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/ResponseBuilder.java new file mode 100644 index 0000000..5fca25a --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/ResponseBuilder.java @@ -0,0 +1,62 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.rest.util; + +import java.util.LinkedHashMap; +import java.util.Map; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +public class ResponseBuilder { + + public static final String TIMESTAMP = "timestamp"; + public static final String MESSAGE = "message"; + public static final String SIMULATOR_STATUS = "simulatorStatus"; + public static final String REMAINING_TIME = "remainingTime"; + + private HttpStatus httpStatus; + private Map<String, Object> body = new LinkedHashMap<>(); + + private ResponseBuilder(HttpStatus httpStatus) { + this.httpStatus = httpStatus; + } + + public static ResponseBuilder status(HttpStatus httpStatus) { + + return new ResponseBuilder(httpStatus); + } + + public ResponseBuilder put(String key, Object value) { + + body.put(key, value); + return this; + } + + public ResponseEntity build() { + + if (body.isEmpty()) { + return ResponseEntity.status(httpStatus).build(); + } + + return ResponseEntity.status(httpStatus).body(body); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/DBTemplateReader.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/DBTemplateReader.java new file mode 100644 index 0000000..6c11254 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/DBTemplateReader.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.io.IOException; +import org.onap.pnfsimulator.template.Template; +import org.onap.pnfsimulator.template.TemplateService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DBTemplateReader implements TemplateReader { + private final TemplateService service; + private final Gson gson; + + @Autowired + public DBTemplateReader(TemplateService service, Gson gson) { + this.service = service; + this.gson = gson; + } + + @Override + public JsonObject readTemplate(String templateName) throws IOException { + Template template = service.get(templateName).orElseThrow(() -> new IOException("Template does not exist")); + JsonElement jsonElement = gson.toJsonTree(template.getContent()); + return jsonElement.getAsJsonObject(); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/EventNotFoundException.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/EventNotFoundException.java new file mode 100644 index 0000000..4f43d8c --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/EventNotFoundException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +public class EventNotFoundException extends RuntimeException { + private static final String NOT_FOUND = "Not found an event with id: "; + public EventNotFoundException(String eventId) { + super(NOT_FOUND + eventId); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/FilesystemTemplateReader.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/FilesystemTemplateReader.java new file mode 100644 index 0000000..a405a2e --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/FilesystemTemplateReader.java @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class FilesystemTemplateReader implements TemplateReader { + + private final Path templatesDir; + private final Gson gson; + + @Autowired + FilesystemTemplateReader(@Value("${templates.dir}") String templatesDir, Gson gson) { + this.templatesDir = Paths.get(templatesDir); + this.gson = gson; + } + + public JsonObject readTemplate(String templateFileName) throws IOException { + Path absTemplateFilePath = templatesDir.resolve(templateFileName); + try (Stream<String> lines = Files.lines(absTemplateFilePath)) { + String content = lines.collect(Collectors.joining("\n")); + return gson.fromJson(content, JsonObject.class); + } + } +} + diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProvider.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProvider.java new file mode 100644 index 0000000..ea87ae6 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProvider.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +@FunctionalInterface +public interface IncrementProvider { + int getAndIncrement(String id); +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProviderImpl.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProviderImpl.java new file mode 100644 index 0000000..16c0a0e --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProviderImpl.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class IncrementProviderImpl implements IncrementProvider { + private final EventDataRepository repository; + + @Autowired + public IncrementProviderImpl(EventDataRepository repository) { + this.repository = repository; + } + + @Override + public int getAndIncrement(String id) { + EventData eventData = repository.findById(id) + .orElseThrow(() -> new EventNotFoundException(id)); + int value = eventData.getIncrementValue() + 1; + eventData.setIncrementValue(value); + repository.save(eventData); + return value; + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/JsonTokenProcessor.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/JsonTokenProcessor.java new file mode 100644 index 0000000..da0026a --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/JsonTokenProcessor.java @@ -0,0 +1,134 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.stream.Collectors; + +public enum JsonTokenProcessor { + STRING(JsonToken.STRING) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + String originalString = reader.nextString(); + if (keywordsExtractor.isPrimitive(originalString)) { + writer.value(keywordsExtractor.substitutePrimitiveKeyword(originalString)); + } else { + String possibleSubstitution = Arrays.stream(originalString.split(" ")) + .map(singleWord -> keywordsExtractor.substituteStringKeyword(singleWord, incrementValue)).collect( + Collectors.joining(" ")); + writer.value(originalString.equals(possibleSubstitution) ? originalString : possibleSubstitution); + } + } + }, + BEGIN_ARRAY(JsonToken.BEGIN_ARRAY) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.beginArray(); + writer.beginArray(); + } + }, + END_ARRAY(JsonToken.END_ARRAY) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.endArray(); + writer.endArray(); + } + }, + BEGIN_OBJECT(JsonToken.BEGIN_OBJECT) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.beginObject(); + writer.beginObject(); + } + }, + END_OBJECT(JsonToken.END_OBJECT) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.endObject(); + writer.endObject(); + } + }, + NAME(JsonToken.NAME) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + writer.name(reader.nextName()); + } + }, + NUMBER(JsonToken.NUMBER) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + writer.value(new BigDecimal(reader.nextString())); + } + }, + BOOLEAN(JsonToken.BOOLEAN) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + writer.value(reader.nextBoolean()); + } + }, + NULL(JsonToken.NULL) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.nextNull(); + writer.nullValue(); + } + }, + END_DOCUMENT(JsonToken.END_DOCUMENT) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + // do nothing + } + }; + + private JsonToken jsonToken; + + JsonTokenProcessor(JsonToken jsonToken) { + this.jsonToken = jsonToken; + } + + boolean isProcessorFor(JsonToken jsonToken) { + return this.jsonToken == jsonToken; + } + + abstract void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) throws IOException; + + private static final String INVALID_JSON_BODY_UNSUPPORTED_JSON_TOKEN = "Invalid json body. Unsupported JsonToken."; + + static JsonTokenProcessor getProcessorFor(JsonToken jsonToken) throws IOException { + return Arrays.stream(JsonTokenProcessor.values()).filter(processor -> processor.isProcessorFor(jsonToken)).findFirst() + .orElseThrow(() -> new IOException(INVALID_JSON_BODY_UNSUPPORTED_JSON_TOKEN)); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsExtractor.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsExtractor.java new file mode 100644 index 0000000..23c383f --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsExtractor.java @@ -0,0 +1,118 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import static io.vavr.API.$; +import static io.vavr.API.Case; +import static io.vavr.API.Match; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getEpochSecond; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomLimitedInteger; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomInteger; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomLimitedString; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomString; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomPrimitiveInteger; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getTimestampPrimitive; +import static org.onap.pnfsimulator.simulator.keywords.NonParameterKeywordPatterns.$nonParameterKeyword; +import static org.onap.pnfsimulator.simulator.keywords.SingleParameterKeywordPatterns.$singleParameterKeyword; +import static org.onap.pnfsimulator.simulator.keywords.TwoParameterKeywordPatterns.$twoParameterKeyword; +import io.vavr.API.Match.Pattern1; +import org.onap.pnfsimulator.simulator.keywords.Keyword; +import org.onap.pnfsimulator.simulator.keywords.NonParameterKeyword; +import org.onap.pnfsimulator.simulator.keywords.SingleParameterKeyword; +import org.onap.pnfsimulator.simulator.keywords.TwoParameterKeyword; +import org.springframework.stereotype.Component; + +@Component +public class KeywordsExtractor { + + String substituteStringKeyword(String text, int increment) { + return Match(text).of( + Case(isRandomStringParamKeyword(), + spk -> spk.substituteKeyword(getRandomString().apply(spk.getAdditionalParameter()))), + Case(isRandomStringNonParamKeyword(), + npk -> npk.substituteKeyword(getRandomLimitedString().apply())), + Case(isRandomIntegerParamKeyword(), + tpk -> tpk.substituteKeyword(getRandomInteger().apply(tpk.getAdditionalParameter1(), tpk.getAdditionalParameter2()))), + Case(isRandomIntegerNonParamKeyword(), + npk -> npk.substituteKeyword(getRandomLimitedInteger().apply())), + Case(isIncrementKeyword(), + ik -> ik.substituteKeyword(String.valueOf(increment))), + Case(isTimestampNonParamKeyword(), + npk -> npk.substituteKeyword(getEpochSecond().apply())), + Case( + $(), + () -> text + )); + } + + Long substitutePrimitiveKeyword(String text) { + return Match(text).of( + Case(isRandomPrimitiveIntegerParamKeyword(), + tpk -> + getRandomPrimitiveInteger().apply(tpk.getAdditionalParameter1(), tpk.getAdditionalParameter2())), + Case(isTimestampPrimitiveNonParamKeyword(), + tpk -> + getTimestampPrimitive().apply()), + Case( + $(), + () -> 0L + )); + } + + boolean isPrimitive(String text) { + return Match(text).of( + Case(isRandomPrimitiveIntegerParamKeyword(), () -> true), + Case(isTimestampPrimitiveNonParamKeyword(), () -> true), + Case($(), () -> false)); + } + + private Pattern1<String, SingleParameterKeyword> isRandomStringParamKeyword() { + return $singleParameterKeyword($(spk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(spk, "RandomString"))); + } + + private Pattern1<String, NonParameterKeyword> isRandomStringNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "RandomString"))); + } + + private Pattern1<String, NonParameterKeyword> isIncrementKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "Increment"))); + } + + private Pattern1<String, TwoParameterKeyword> isRandomIntegerParamKeyword() { + return $twoParameterKeyword($(tpk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(tpk, "RandomInteger"))); + } + + private Pattern1<String, TwoParameterKeyword> isRandomPrimitiveIntegerParamKeyword() { + return $twoParameterKeyword($(tpk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(tpk, "RandomPrimitiveInteger"))); + } + + private Pattern1<String, NonParameterKeyword> isTimestampPrimitiveNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "TimestampPrimitive"))); + } + + private Pattern1<String, NonParameterKeyword> isRandomIntegerNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "RandomInteger"))); + } + + private Pattern1<String, NonParameterKeyword> isTimestampNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "Timestamp"))); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsHandler.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsHandler.java new file mode 100644 index 0000000..51e0c1f --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsHandler.java @@ -0,0 +1,72 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import org.springframework.stereotype.Component; + +@Component +public class KeywordsHandler { + + private KeywordsExtractor keywordsExtractor; + private IncrementProvider incrementProvider; + + public KeywordsHandler(KeywordsExtractor keywordsExtractor, IncrementProvider incrementProvider) { + this.keywordsExtractor = keywordsExtractor; + this.incrementProvider = incrementProvider; + } + + public JsonElement substituteKeywords(JsonElement jsonBody, String jobId) { + int counter = incrementProvider.getAndIncrement(jobId); + try ( + JsonReader reader = new JsonReader(new StringReader(jsonBody.toString())); + StringWriter stringWriter = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(stringWriter); + ) { + modify(reader, jsonWriter, counter); + return new Gson().fromJson(stringWriter.getBuffer().toString(), JsonElement.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void modify(JsonReader reader, JsonWriter writer, int incrementValue) throws IOException { + JsonTokenProcessor jsonTokenProcessor; + do { + JsonToken token = reader.peek(); + jsonTokenProcessor = JsonTokenProcessor.getProcessorFor(token); + jsonTokenProcessor.process(reader, writer, incrementValue, keywordsExtractor); + } while (isJsonProcessingFinished(jsonTokenProcessor)); + } + + private boolean isJsonProcessingFinished(JsonTokenProcessor jsonTokenProcessor) { + return !jsonTokenProcessor.isProcessorFor(JsonToken.END_DOCUMENT); + } + +} + + diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsValueProvider.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsValueProvider.java new file mode 100644 index 0000000..3bcfa5b --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsValueProvider.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import io.vavr.Function0; +import io.vavr.Function1; +import io.vavr.Function2; + +import java.time.Instant; +import java.util.Random; + +import org.apache.commons.lang3.RandomStringUtils; + +class KeywordsValueProvider { + + private KeywordsValueProvider() { + } + + static final int DEFAULT_STRING_LENGTH = 20; + public static final int RANDOM_INTEGER_MAX_LIMITATION = 9; + public static final int RANDOM_INTEGER_MIN_LIMITATION = 0; + + private static Function2<Integer, Integer, Integer> bigger = (left, right) -> left >= right ? left : right; + private static Function2<Integer, Integer, Integer> smaller = (left, right) -> left < right ? left : right; + private static Function2<Integer, Integer, Integer> randomPrimitiveIntegerFromSortedRange = (min, max) -> new Random().nextInt(max - min + 1) + min; + private static Function2<Integer, Integer, String> randomIntegerFromSortedRange = (min, max) -> Integer.toString(new Random().nextInt(max - min + 1) + min); + + private static Function1<Integer, String> randomString = RandomStringUtils::randomAscii; + private static Function2<Integer, Integer, String> randomInteger = (left, right) -> randomIntegerFromSortedRange.apply(smaller.apply(left, right), bigger.apply(left, right)); + private static Function0<String> randomLimitedInteger = () -> randomInteger.apply(RANDOM_INTEGER_MIN_LIMITATION, RANDOM_INTEGER_MAX_LIMITATION); + private static Function0<String> randomLimitedString = () -> RandomStringUtils.randomAscii(DEFAULT_STRING_LENGTH); + private static Function0<String> epochSecond = () -> Long.toString(Instant.now().getEpochSecond()); + private static Function2<Integer, Integer, Long> randomPrimitiveInteger = (left, right) -> randomPrimitiveIntegerFromSortedRange.apply(smaller.apply(left, right), bigger.apply(left, right)).longValue(); + private static Function0<Long> timestampPrimitive = () -> Instant.now().getEpochSecond(); + + public static Function1<Integer, String> getRandomString() { + return randomString; + } + + public static Function2<Integer, Integer, String> getRandomInteger() { + return randomInteger; + } + + public static Function0<String> getRandomLimitedInteger() { + return randomLimitedInteger; + } + + public static Function0<String> getRandomLimitedString() { + return randomLimitedString; + } + + public static Function0<String> getEpochSecond() { + return epochSecond; + } + + public static Function2<Integer, Integer, Long> getRandomPrimitiveInteger() { + return randomPrimitiveInteger; + } + + public static Function0<Long> getTimestampPrimitive() { + return timestampPrimitive; + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java new file mode 100644 index 0000000..155c0ff --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java @@ -0,0 +1,121 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import com.google.common.base.Strings; +import com.google.gson.JsonObject; +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.GeneralSecurityException; +import java.util.Optional; +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataService; +import org.onap.pnfsimulator.rest.model.FullEvent; +import org.onap.pnfsimulator.rest.model.SimulatorParams; +import org.onap.pnfsimulator.rest.model.SimulatorRequest; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; +import org.onap.pnfsimulator.simulator.scheduler.EventScheduler; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfigService; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SimulatorService { + + private final TemplatePatcher templatePatcher; + private final TemplateReader templateReader; + private final EventDataService eventDataService; + private final EventScheduler eventScheduler; + private final SSLAuthenticationHelper sslAuthenticationHelper; + private SimulatorConfigService simulatorConfigService; + private static final JsonObject EMPTY_JSON_OBJECT = new JsonObject(); + + @Autowired + public SimulatorService(TemplatePatcher templatePatcher, TemplateReader templateReader, + EventScheduler eventScheduler, EventDataService eventDataService, + SimulatorConfigService simulatorConfigService, SSLAuthenticationHelper sslAuthenticationHelper) { + this.templatePatcher = templatePatcher; + this.templateReader = templateReader; + this.eventDataService = eventDataService; + this.eventScheduler = eventScheduler; + this.simulatorConfigService = simulatorConfigService; + this.sslAuthenticationHelper = sslAuthenticationHelper; + } + + public String triggerEvent(SimulatorRequest simulatorRequest) throws IOException, SchedulerException, GeneralSecurityException { + String templateName = simulatorRequest.getTemplateName(); + SimulatorParams simulatorParams = simulatorRequest.getSimulatorParams(); + JsonObject template = templateReader.readTemplate(templateName); + JsonObject input = Optional.ofNullable(simulatorRequest.getPatch()).orElse(new JsonObject()); + JsonObject patchedJson = templatePatcher + .mergeTemplateWithPatch(template, input); + JsonObject keywords = new JsonObject(); + + EventData eventData = eventDataService.persistEventData(template, patchedJson, input, keywords); + + String targetVesUrl = getDefaultUrlIfNotProvided(simulatorParams.getVesServerUrl()); + return eventScheduler + .scheduleEvent(targetVesUrl, Optional.ofNullable(simulatorParams.getRepeatInterval()).orElse(1), + Optional.ofNullable(simulatorParams.getRepeatCount()).orElse(1), simulatorRequest.getTemplateName(), + eventData.getId(), + patchedJson); + } + + public void triggerOneTimeEvent(FullEvent event) throws IOException, GeneralSecurityException { + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), id -> 1); + JsonObject withKeywordsSubstituted = keywordsHandler.substituteKeywords(event.getEvent(), "").getAsJsonObject(); + + HttpClientAdapter client = createHttpClientAdapter(event.getVesServerUrl()); + eventDataService.persistEventData(EMPTY_JSON_OBJECT, withKeywordsSubstituted, event.getEvent(), EMPTY_JSON_OBJECT); + + client.send(withKeywordsSubstituted.toString()); + } + + public SimulatorConfig getConfiguration() { + return simulatorConfigService.getConfiguration(); + } + + public SimulatorConfig updateConfiguration(SimulatorConfig newConfig) { + return simulatorConfigService.updateConfiguration(newConfig); + } + + public boolean cancelAllEvents() throws SchedulerException { + return eventScheduler.cancelAllEvents(); + } + + public boolean cancelEvent(String jobName) throws SchedulerException { + return eventScheduler.cancelEvent(jobName); + } + + HttpClientAdapter createHttpClientAdapter(String vesServerUrl) throws IOException, GeneralSecurityException { + String targetVesUrl = getDefaultUrlIfNotProvided(vesServerUrl); + return new HttpClientAdapterImpl(targetVesUrl, sslAuthenticationHelper); + } + + private String getDefaultUrlIfNotProvided(String vesUrlSimulatorParam) { + return Strings.isNullOrEmpty(vesUrlSimulatorParam) + ? simulatorConfigService.getConfiguration().getVesServerUrl().toString() : vesUrlSimulatorParam; + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplatePatcher.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplatePatcher.java new file mode 100644 index 0000000..1114d3c --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplatePatcher.java @@ -0,0 +1,53 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +class TemplatePatcher { + + JsonObject mergeTemplateWithPatch(JsonObject templateJson, JsonObject patchJson) { + JsonObject template = templateJson.deepCopy(); + patchTemplateNode(template, patchJson); + return template; + } + + private void patchTemplateNode(JsonObject templateJson, JsonObject patchJson) { + for (Map.Entry<String, JsonElement> stringJsonElementEntry : patchJson.entrySet()) { + String patchKey = stringJsonElementEntry.getKey(); + JsonElement patchValue = stringJsonElementEntry.getValue(); + JsonElement templateElement = templateJson.get(patchKey); + + if (!patchValue.isJsonObject() || templateElement == null || !templateElement.isJsonObject()) { + templateJson.remove(patchKey); + templateJson.add(patchKey, patchValue); + } else { + patchTemplateNode(templateElement.getAsJsonObject(), patchValue.getAsJsonObject()); + } + + } + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateReader.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateReader.java new file mode 100644 index 0000000..bf06381 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateReader.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator; + +import com.google.gson.JsonObject; +import java.io.IOException; + +public interface TemplateReader { + JsonObject readTemplate(String templateName) throws IOException; +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapter.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapter.java new file mode 100644 index 0000000..e7d113d --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapter.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.client; + +public interface HttpClientAdapter { + + void send(String content); +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java new file mode 100644 index 0000000..6ea1157 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java @@ -0,0 +1,104 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.client; + +import static org.onap.pnfsimulator.logging.MDCVariables.REQUEST_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.X_INVOCATION_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.X_ONAP_REQUEST_ID; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.GeneralSecurityException; +import java.util.UUID; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.util.EntityUtils; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SslSupportLevel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +public class HttpClientAdapterImpl implements HttpClientAdapter { + + private static final int CONNECTION_TIMEOUT = 1000; + private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientAdapterImpl.class); + private static final String CONTENT_TYPE = "Content-Type"; + private static final String APPLICATION_JSON = "application/json"; + private static final RequestConfig CONFIG = RequestConfig.custom() + .setConnectTimeout(CONNECTION_TIMEOUT) + .setConnectionRequestTimeout(CONNECTION_TIMEOUT) + .setSocketTimeout(CONNECTION_TIMEOUT) + .build(); + private static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); + private SslSupportLevel sslSupportLevel; + private HttpClient client; + private final String targetUrl; + + public HttpClientAdapterImpl(String targetUrl, SSLAuthenticationHelper sslAuthenticationHelper) + throws IOException, GeneralSecurityException { + this.sslSupportLevel = sslAuthenticationHelper.isClientCertificateEnabled() ? + SslSupportLevel.CLIENT_CERT_AUTH : SslSupportLevel.getSupportLevelBasedOnProtocol(targetUrl); + this.client = sslSupportLevel.getClient(CONFIG, sslAuthenticationHelper); + this.targetUrl = targetUrl; + } + + HttpClientAdapterImpl(HttpClient client, String targetUrl) { + this.client = client; + this.targetUrl = targetUrl; + } + + @Override + public void send(String content) { + try { + HttpPost request = createRequest(content); + HttpResponse response = client.execute(request); + + //response has to be fully consumed otherwise apache won't release connection + EntityUtils.consumeQuietly(response.getEntity()); + LOGGER.info(INVOKE, "Message sent, ves response code: {}", response.getStatusLine()); + } catch (IOException e) { + LOGGER.warn("Error sending message to ves: " + e.getMessage(), e.getCause()); + } + } + + public SslSupportLevel getSslSupportLevel(){ + return sslSupportLevel; + } + + private HttpPost createRequest(String content) throws UnsupportedEncodingException { + HttpPost request = new HttpPost(this.targetUrl); + StringEntity stringEntity = new StringEntity(content); + request.addHeader(CONTENT_TYPE, APPLICATION_JSON); + request.addHeader(X_ONAP_REQUEST_ID, MDC.get(REQUEST_ID)); + request.addHeader(X_INVOCATION_ID, UUID.randomUUID().toString()); + request.setEntity(stringEntity); + return request; + } + + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLAuthenticationHelper.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLAuthenticationHelper.java new file mode 100644 index 0000000..eda17ef --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SSLAuthenticationHelper.java @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.simulator.client.utils.ssl; + +import java.io.Serializable; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "ssl") +@RefreshScope +@Primary +public class SSLAuthenticationHelper implements Serializable { + + private boolean clientCertificateEnabled; + private String clientCertificateDir; + private String clientCertificatePassword; + private String trustStoreDir; + private String trustStorePassword; + + public boolean isClientCertificateEnabled() { + return clientCertificateEnabled; + } + + public void setClientCertificateEnabled(boolean clientCertificateEnabled) { + this.clientCertificateEnabled = clientCertificateEnabled; + } + + public String getClientCertificateDir() { + return clientCertificateDir; + } + + public void setClientCertificateDir(String clientCertificateDir) { + this.clientCertificateDir = clientCertificateDir; + } + + public String getClientCertificatePassword() { + return clientCertificatePassword; + } + + public void setClientCertificatePassword(String clientCertificatePassword) { + this.clientCertificatePassword = clientCertificatePassword; + } + + public String getTrustStoreDir() { + return trustStoreDir; + } + + public void setTrustStoreDir(String trustStoreDir) { + this.trustStoreDir = trustStoreDir; + } + + public String getTrustStorePassword() { + return trustStorePassword; + } + + public void setTrustStorePassword(String trustStorePassword) { + this.trustStorePassword = trustStorePassword; + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java new file mode 100644 index 0000000..264a7d1 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java @@ -0,0 +1,120 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.client.utils.ssl; + +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.TrustAllStrategy; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLContext; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.Optional; + +public enum SslSupportLevel { + + NONE { + public HttpClient getClient(RequestConfig requestConfig, SSLAuthenticationHelper sslAuthenticationHelper) { + LOGGER.info("<!-----IN SslSupportLevel.NONE, Creating BasicHttpClient for http protocol----!>"); + return HttpClientBuilder + .create() + .setDefaultRequestConfig(requestConfig) + .build(); + } + }, + ALWAYS_TRUST { + public HttpClient getClient(RequestConfig requestConfig, SSLAuthenticationHelper sslAuthenticationHelper) + throws GeneralSecurityException, IOException { + LoggerFactory.getLogger(SslSupportLevel.class).info("<!-----IN SslSupportLevel.ALWAYS_TRUST, Creating client with SSL support for https protocol----!>"); + HttpClient client; + try { + SSLContext alwaysTrustSslContext = SSLContextBuilder.create().loadTrustMaterial(TRUST_STRATEGY_ALWAYS).build(); + client = HttpClients.custom() + .setSSLContext(alwaysTrustSslContext) + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .setDefaultRequestConfig(requestConfig) + .build(); + + } catch (GeneralSecurityException e) { + LOGGER.error("Could not initialize client due to SSL exception: {}. Default client without SSL support will be used instead.\nCause: {}", e.getMessage(), e.getCause()); + client = NONE.getClient(requestConfig, sslAuthenticationHelper); + } + return client; + } + }, + CLIENT_CERT_AUTH { + @Override + public HttpClient getClient(RequestConfig requestConfig, SSLAuthenticationHelper sslAuthenticationHelper) + throws GeneralSecurityException, IOException { + + SSLContext sslContext = SSLContexts.custom() + .loadKeyMaterial(readCertificate(sslAuthenticationHelper.getClientCertificateDir(), sslAuthenticationHelper.getClientCertificatePassword(), "PKCS12"), getPasswordAsCharArray(sslAuthenticationHelper.getClientCertificatePassword())) + .loadTrustMaterial(readCertificate(sslAuthenticationHelper.getTrustStoreDir(), sslAuthenticationHelper.getTrustStorePassword(), "JKS"), new TrustSelfSignedStrategy()) + .build(); + + return HttpClients.custom() + .setSSLContext(sslContext) + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .setDefaultRequestConfig(requestConfig) + .build(); + } + + private KeyStore readCertificate(String certificate, String password, String type) throws GeneralSecurityException, IOException { + try (InputStream keyStoreStream = new FileInputStream(certificate)) { + KeyStore keyStore = KeyStore.getInstance(type); + keyStore.load(keyStoreStream, getPasswordAsCharArray(password)); + return keyStore; + } + } + + private char[] getPasswordAsCharArray(String clientCertificatePassword) { + return Optional.ofNullable(clientCertificatePassword).map(String::toCharArray).orElse(null); + } + }; + + private static final Logger LOGGER = LoggerFactory.getLogger(SslSupportLevel.class); + private static final TrustStrategy TRUST_STRATEGY_ALWAYS = new TrustAllStrategy(); + + public static SslSupportLevel getSupportLevelBasedOnProtocol(String url) throws MalformedURLException { + return "https".equals(new URL(url).getProtocol()) ? SslSupportLevel.ALWAYS_TRUST : SslSupportLevel.NONE; + } + + public abstract HttpClient getClient(RequestConfig config, SSLAuthenticationHelper sslAuthenticationHelper) + throws GeneralSecurityException, IOException; + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/Keyword.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/Keyword.java new file mode 100644 index 0000000..edafe8f --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/Keyword.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.keywords; + +import io.vavr.Function1; +import io.vavr.Function2; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.stream.Collectors; +import lombok.Getter; + +@Getter +public class Keyword { + + protected static final String LETTERS_REGEX = "([a-zA-Z]+)"; + protected static final String NONLETTERS_REGEX = "([^a-zA-Z]+)"; + + protected static final Function1<String, String> OPTIONAL = + (regex) -> regex + "?"; + + private final String name; + private final List<String> meaningfulParts; + + public static final Function2<Keyword, String, Boolean> IS_MATCHING_KEYWORD_NAME = (keyword, key) -> + keyword != null && keyword.getName() != null && keyword.getName().equals(key); + + /** + * Returns list of independent parts inside the keyword. Current implementation assumes that customer can join keywords with integer values, so + * keyword is decomposed to parts then some parts of the keyword is skipped because of replacement process. + * + * @param matcher - Matcher to check find independent groups inside the keyword + * @param skipGroups Informs this method about which groups should be consider as part of the replacement process + * @return list of independent parts inside the keywords + */ + static List<String> extractPartsFrom(Matcher matcher, List skipGroups) { + List<String> parts = new ArrayList<String>(); + for (int i = 1; i <= matcher.groupCount(); i++) { + if (matcher.group(i) != null && !skipGroups.contains(i)) { + parts.add(matcher.group(i)); + } + } + return parts; + } + + Keyword(String name, List<String> meaningfulParts) { + this.name = name; + this.meaningfulParts = meaningfulParts; + } + + public String substituteKeyword(String substitution) { + return meaningfulParts.stream() + .map(part -> part.equals(name) ? substitution : part) + .collect(Collectors.joining()); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/NonParameterKeyword.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/NonParameterKeyword.java new file mode 100644 index 0000000..5e44550 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/NonParameterKeyword.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.keywords; + +import io.vavr.Tuple; +import io.vavr.Tuple1; +import io.vavr.match.annotation.Patterns; +import io.vavr.match.annotation.Unapply; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.Setter; +import lombok.val; + +@Patterns +@Getter +@Setter +public class NonParameterKeyword extends Keyword { + + public static final int KEYWORD_NAME_GROUP = 2; + + private static final String KEYWORD_REGEX = new StringBuilder() + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .append("#") + .append(LETTERS_REGEX) + .append("(?!\\()") + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .toString(); + + private NonParameterKeyword(String name, List<String> meaningfulParts) { + super(name, meaningfulParts); + } + + @Unapply + static Tuple1<NonParameterKeyword> nonParameterKeyword(String keyword) { + val matcher = Pattern.compile(KEYWORD_REGEX).matcher(keyword); + NonParameterKeyword npk = null; + if (matcher.find()) { + npk = new NonParameterKeyword( + matcher.group(KEYWORD_NAME_GROUP), + extractPartsFrom(matcher, Collections.emptyList()) + ); + } + return Tuple.of(npk); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/SingleParameterKeyword.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/SingleParameterKeyword.java new file mode 100644 index 0000000..b1c38c8 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/SingleParameterKeyword.java @@ -0,0 +1,73 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.keywords; + +import io.vavr.Tuple; +import io.vavr.Tuple1; +import io.vavr.match.annotation.Patterns; +import io.vavr.match.annotation.Unapply; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.Setter; +import lombok.val; + +@Patterns +@Getter +@Setter +public class SingleParameterKeyword extends Keyword { + + public static final int KEYWORD_NAME_GROUP = 2; + public static final int ADDITIONAL_PARAMETER_GROUP = 3; + + private static final String KEYWORD_REGEX = new StringBuilder() + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .append("#") + .append(LETTERS_REGEX) + .append("\\((\\d+)\\)") + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .toString(); + public static final int SKIPPED_GROUP_NUMBER = 3; + + private Integer additionalParameter; + + private SingleParameterKeyword(String name, List<String> meaningfulParts, + Integer additionalParameter) { + super(name, meaningfulParts); + this.additionalParameter = additionalParameter; + } + + @Unapply + static Tuple1<SingleParameterKeyword> singleParameterKeyword(String keyword) { + val matcher = Pattern.compile(KEYWORD_REGEX).matcher(keyword); + SingleParameterKeyword spk = null; + if (matcher.find()) { + spk = new SingleParameterKeyword( + matcher.group(KEYWORD_NAME_GROUP), + extractPartsFrom(matcher, Collections.singletonList(SKIPPED_GROUP_NUMBER)), + Integer.parseInt(matcher.group(ADDITIONAL_PARAMETER_GROUP)) + ); + } + return Tuple.of(spk); + } +} + + diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/TwoParameterKeyword.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/TwoParameterKeyword.java new file mode 100644 index 0000000..6fecfa6 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/TwoParameterKeyword.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.keywords; + +import io.vavr.Tuple; +import io.vavr.Tuple1; +import io.vavr.match.annotation.Patterns; +import io.vavr.match.annotation.Unapply; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.Setter; +import lombok.val; + +@Patterns +@Getter +@Setter +public class TwoParameterKeyword extends Keyword { + + public static final int ADDITIONAL_PARAMETER_1_GROUP = 3; + public static final int ADDITIONAL_PARAMETER_2_GROUP = 4; + public static final int KEYWORD_NAME_GROUP = 2; + protected static final List<Integer> ADDITIONAL_PARAMETERS_GROUPS = Arrays.asList(ADDITIONAL_PARAMETER_1_GROUP, ADDITIONAL_PARAMETER_2_GROUP); + + private static final String NON_LIMITED_NUMBER_REGEX = "\\((\\d+)"; + private static final String COLON_REGEX = "\\s?,\\s?"; + private static final String OPTIONAL_NUMBER_PARAM_REGEX = "(\\d+)\\)"; + + private static final String KEYWORD_REGEX = OPTIONAL.apply(NONLETTERS_REGEX) + + "#" + + LETTERS_REGEX + + NON_LIMITED_NUMBER_REGEX + + COLON_REGEX + + OPTIONAL_NUMBER_PARAM_REGEX + + OPTIONAL.apply(NONLETTERS_REGEX); + + private Integer additionalParameter1; + private Integer additionalParameter2; + + private TwoParameterKeyword(String name, List<String> meaningfulParts, Integer additionalParameter1, + Integer additionalParameter2) { + super(name, meaningfulParts); + this.additionalParameter1 = additionalParameter1; + this.additionalParameter2 = additionalParameter2; + } + + @Unapply + static Tuple1<TwoParameterKeyword> twoParameterKeyword(String keyword) { + val matcher = Pattern.compile(KEYWORD_REGEX).matcher(keyword); + TwoParameterKeyword tpk = null; + if (matcher.find()) { + tpk = new TwoParameterKeyword( + matcher.group(KEYWORD_NAME_GROUP), + extractPartsFrom(matcher, ADDITIONAL_PARAMETERS_GROUPS), + Integer.parseInt(matcher.group(ADDITIONAL_PARAMETER_1_GROUP)), + Integer.parseInt(matcher.group(ADDITIONAL_PARAMETER_2_GROUP)) + ); + } + return Tuple.of(tpk); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java new file mode 100644 index 0000000..c4b40fc --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java @@ -0,0 +1,93 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.scheduler; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.onap.pnfsimulator.simulator.KeywordsHandler; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.GeneralSecurityException; +import java.util.Optional; + +public class EventJob implements Job { + + private static final Logger LOGGER = LoggerFactory.getLogger(EventJob.class); + + static final String TEMPLATE_NAME = "TEMPLATE_NAME"; + static final String VES_URL = "VES_URL"; + static final String BODY = "BODY"; + static final String CLIENT_ADAPTER = "CLIENT_ADAPTER"; + static final String KEYWORDS_HANDLER = "KEYWORDS_HANDLER"; + static final String EVENT_ID = "EVENT_ID"; + + @Override + public void execute(JobExecutionContext jobExecutionContext) { + JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); + String templateName = jobDataMap.getString(TEMPLATE_NAME); + String vesUrl = jobDataMap.getString(VES_URL); + JsonObject body = (JsonObject) jobDataMap.get(BODY); + String id = jobDataMap.getString(EVENT_ID); + Optional<HttpClientAdapter> httpClientAdapter = getHttpClientAdapter(jobDataMap, vesUrl); + + if (httpClientAdapter.isPresent()) { + KeywordsHandler keywordsHandler = (KeywordsHandler) jobDataMap.get(KEYWORDS_HANDLER); + JsonElement processedBody = keywordsHandler.substituteKeywords(body, id); + String processedBodyString = processedBody.toString(); + String jobKey = jobExecutionContext.getJobDetail().getKey().toString(); + + logEventDetails(templateName, vesUrl, body.toString(), jobKey); + httpClientAdapter.get().send(processedBodyString); + } else { + LOGGER.error("Could not send event as client is not available"); + } + } + private Optional<HttpClientAdapter> getHttpClientAdapter(JobDataMap jobDataMap, String vesUrl) { + HttpClientAdapter adapter = null; + try { + adapter = (HttpClientAdapter) (jobDataMap.containsKey(CLIENT_ADAPTER) ? jobDataMap.get(CLIENT_ADAPTER) : + new HttpClientAdapterImpl(vesUrl, new SSLAuthenticationHelper())); + } catch (MalformedURLException e) { + LOGGER.error("Invalid format of vesServerUr: {}", vesUrl); + } catch (IOException | GeneralSecurityException e){ + LOGGER.error("Invalid configuration of client certificate"); + } + return Optional.ofNullable(adapter); + } + + private void logEventDetails(String templateName, String vesUrl, String body, String jobKey) { + LOGGER.info(String.format("Job %s:Sending event to %s from template %s", + jobKey, vesUrl, templateName)); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(String.format("Job %s: Request body %s", jobKey, body)); + } + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java new file mode 100644 index 0000000..08e24f8 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java @@ -0,0 +1,121 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.scheduler; + + +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.BODY; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.CLIENT_ADAPTER; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.EVENT_ID; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.KEYWORDS_HANDLER; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.TEMPLATE_NAME; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.VES_URL; +import static org.quartz.SimpleScheduleBuilder.simpleSchedule; + +import com.google.gson.JsonObject; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.GeneralSecurityException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.onap.pnfsimulator.simulator.KeywordsHandler; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SSLAuthenticationHelper; +import org.quartz.JobBuilder; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SimpleTrigger; +import org.quartz.TriggerBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class EventScheduler { + + + private final Scheduler scheduler; + private final KeywordsHandler keywordsHandler; + private final SSLAuthenticationHelper SSLAuthenticationHelper; + + @Autowired + public EventScheduler(Scheduler scheduler, KeywordsHandler keywordsHandler, SSLAuthenticationHelper SSLAuthenticationHelper) { + this.scheduler = scheduler; + this.keywordsHandler = keywordsHandler; + this.SSLAuthenticationHelper = SSLAuthenticationHelper; + } + + public String scheduleEvent(String vesUrl, Integer repeatInterval, Integer repeatCount, + String templateName, String eventId, JsonObject body) + throws SchedulerException, IOException, GeneralSecurityException { + + JobDetail jobDetail = createJobDetail(vesUrl, templateName, eventId, body); + SimpleTrigger trigger = createTrigger(repeatInterval, repeatCount); + + scheduler.scheduleJob(jobDetail, trigger); + return jobDetail.getKey().getName(); + } + + public boolean cancelAllEvents() throws SchedulerException { + List<JobKey> jobKeys = getActiveJobsKeys(); + return scheduler.deleteJobs(jobKeys); + } + + public boolean cancelEvent(String jobName) throws SchedulerException { + Optional<JobKey> activeJobKey = getActiveJobsKeys().stream().filter(e -> e.getName().equals(jobName)).findFirst(); + return activeJobKey.isPresent() && scheduler.deleteJob(activeJobKey.get()); + } + + private SimpleTrigger createTrigger(int interval, int repeatCount) { + return TriggerBuilder.newTrigger() + .withSchedule(simpleSchedule() + .withIntervalInSeconds(interval) + .withRepeatCount(repeatCount - 1)) + .build(); + } + + private JobDetail createJobDetail(String vesUrl, String templateName, String eventId, JsonObject body) throws IOException, GeneralSecurityException { + JobDataMap jobDataMap = new JobDataMap(); + jobDataMap.put(TEMPLATE_NAME, templateName); + jobDataMap.put(VES_URL, vesUrl); + jobDataMap.put(EVENT_ID, eventId); + jobDataMap.put(KEYWORDS_HANDLER, keywordsHandler); + jobDataMap.put(BODY, body); + jobDataMap.put(CLIENT_ADAPTER, new HttpClientAdapterImpl(vesUrl, SSLAuthenticationHelper)); + + return JobBuilder + .newJob(EventJob.class) + .withDescription(templateName) + .usingJobData(jobDataMap) + .build(); + } + + private List<JobKey> getActiveJobsKeys() throws SchedulerException { + return scheduler.getCurrentlyExecutingJobs() + .stream() + .map(JobExecutionContext::getJobDetail) + .map(JobDetail::getKey) + .collect(Collectors.toList()); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/QuartzConfiguration.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/QuartzConfiguration.java new file mode 100644 index 0000000..2beb9dc --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/QuartzConfiguration.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulator.scheduler; + +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.impl.StdSchedulerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class QuartzConfiguration { + + @Bean + Scheduler provideScheduler() throws SchedulerException { + StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); + Scheduler scheduler = stdSchedulerFactory.getScheduler(); + scheduler.start(); + return scheduler; + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfig.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfig.java new file mode 100644 index 0000000..0baa477 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfig.java @@ -0,0 +1,49 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulatorconfig; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Field; + +import javax.validation.constraints.NotNull; +import java.net.URL; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class SimulatorConfig { + + @JsonIgnore + @Id + private String id; + + @NotNull + @Field("vesServerUrl") + private URL vesServerUrl; +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigRepository.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigRepository.java new file mode 100644 index 0000000..5e63ee4 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigRepository.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulatorconfig; + +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface SimulatorConfigRepository extends MongoRepository<SimulatorConfig, String> { +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigService.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigService.java new file mode 100644 index 0000000..2063351 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigService.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. 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.pnfsimulator.simulatorconfig; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class SimulatorConfigService { + + private final SimulatorConfigRepository repository; + + @Autowired + public SimulatorConfigService(SimulatorConfigRepository repository) { + this.repository = repository; + } + + + public SimulatorConfig getConfiguration() { + List<SimulatorConfig> configs = repository.findAll(); + if (configs.isEmpty()) { + throw new IllegalStateException("No configuration found in db"); + } + return configs.get(0); + } + + public SimulatorConfig updateConfiguration(SimulatorConfig configuration) { + SimulatorConfig currentConfig = getConfiguration(); + currentConfig.setVesServerUrl(configuration.getVesServerUrl()); + return repository.save(currentConfig); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/FsToDbTemplateSynchronizer.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/FsToDbTemplateSynchronizer.java new file mode 100644 index 0000000..881585b --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/FsToDbTemplateSynchronizer.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Stream; + +import org.bson.json.JsonParseException; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.filesystem.WatcherEventProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class FsToDbTemplateSynchronizer { + + private static final String CANNOT_SYNC = "Cannot synchronize templates. Check whether the proper folder exists."; + private static final Logger LOGGER = LoggerFactory.getLogger(FsToDbTemplateSynchronizer.class); + + private final String templatesDir; + private final Storage<Template> storage; + + @Autowired + public FsToDbTemplateSynchronizer(@Value("${templates.dir}") String templatesDir, + Storage<Template> storage) { + this.templatesDir = templatesDir; + this.storage = storage; + } + + public void synchronize() { + try { + processTemplatesFolder(); + } catch (IOException e) { + LOGGER.error(CANNOT_SYNC, e); + } + } + + private void processTemplatesFolder() throws IOException { + try (Stream<Path> walk = Files.walk(Paths.get(templatesDir))) { + walk.filter(Files::isRegularFile).forEach(path -> { + try { + WatcherEventProcessor.MODIFIED.processEvent(path, storage); + } catch (IOException | JsonParseException e) { + LOGGER + .error("Cannot synchronize template: " + path.getFileName().toString(), e); + } + }); + } + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/Template.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/Template.java new file mode 100644 index 0000000..c84b8d0 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/Template.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.db.Row; +import org.bson.Document; +import org.onap.pnfsimulator.template.search.JsonUtils; +import org.springframework.data.mongodb.core.mapping.Field; + +@NoArgsConstructor +@ToString +public class Template extends Row { + + @Field("content") + private Document content; + + @Field("flatContent") + private Document flatContent; + + @Field("lmod") + private long lmod; + + public Template(String name, Document content, long lmod) { + this.id = name; + this.content = content; + this.lmod = lmod; + this.flatContent = new JsonUtils().flatten(content); + } + + public Template(String name, String template, long lmod) { + this.id = name; + this.content = Document.parse(template); + this.lmod = lmod; + this.flatContent = new JsonUtils().flatten(this.content); + } + + public void setContent(Document content) { + this.content = content; + this.flatContent = new JsonUtils().flatten(content); + } + + public Document getContent() { + return new Document(this.content); + } + + @JsonIgnore + public Document getFlatContent() { + return new Document(this.flatContent); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Template template = (Template) o; + return Objects.equals(content, template.content) + && Objects.equals(id, template.id) + && Objects.equals(lmod, template.lmod); + } + + @Override + public int hashCode() { + return Objects.hash(content, id); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateRepository.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateRepository.java new file mode 100644 index 0000000..78c9c77 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateRepository.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template; + +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface TemplateRepository extends MongoRepository<Template, String> { +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateService.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateService.java new file mode 100644 index 0000000..3e245e1 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateService.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template; + +import java.util.List; +import java.util.Optional; + +import com.google.gson.JsonObject; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.search.TemplateSearchHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; + +@Primary +@Service +public class TemplateService implements Storage<Template> { + + private final TemplateRepository templateRepository; + private TemplateSearchHelper searchHelper; + + + @Autowired + public TemplateService(TemplateRepository templateRepository, TemplateSearchHelper searchHelper) { + this.templateRepository = templateRepository; + this.searchHelper = searchHelper; + } + + @Override + public List<Template> getAll() { + return templateRepository.findAll(); + } + + @Override + public Optional<Template> get(String name) { + return templateRepository.findById(name); + } + + @Override + public void persist(Template template) { + templateRepository.save(template); + } + + @Override + public boolean tryPersistOrOverwrite(Template template, boolean overwrite) { + if (templateRepository.existsById(template.getId()) && !overwrite) { + return false; + } + templateRepository.save(template); + return true; + } + + @Override + public void delete(String templateName) { + templateRepository.deleteById(templateName); + } + + @Override + public List<String> getIdsByContentCriteria(JsonObject stringQueryJson) { + return searchHelper.getIdsOfDocumentMatchingCriteria(stringQueryJson); + } + +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/IllegalJsonValueException.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/IllegalJsonValueException.java new file mode 100644 index 0000000..6890382 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/IllegalJsonValueException.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template.search; + +public class IllegalJsonValueException extends IllegalArgumentException { + + IllegalJsonValueException(String s) { + super(s); + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/JsonUtils.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/JsonUtils.java new file mode 100644 index 0000000..b595b4f --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/JsonUtils.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template.search; + +import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.bson.Document; + +/** + * This util flattens nested json and produces json with keys transformed to form of json path + * where default separator between parent object key and object key is ':' + * For easing searching of boolean values, they are converted to its string representation + */ +public class JsonUtils { + + private static final String DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR = ":"; + private static final String SEED_PREFIX = ""; + private static final Gson GSON = new Gson(); + + public JsonObject flatten(JsonObject original) { + return flattenWithPrefixedKeys(DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR, original.deepCopy(), SEED_PREFIX, new JsonObject()); + } + + public JsonObject flatten(String parentKeyToKeySeparator, JsonObject original) { + return flattenWithPrefixedKeys(parentKeyToKeySeparator, original.deepCopy(), SEED_PREFIX, new JsonObject()); + } + + public Document flatten(Document original) { + return flatten(DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR, original); + } + + public Document flatten(String parentKeyToKeySeparator, Document original) { + JsonObject originalJsonObject = GSON.fromJson(original.toJson(), JsonObject.class); + JsonObject flattenedJson = flatten(parentKeyToKeySeparator, originalJsonObject); + return Document.parse(flattenedJson.toString()); + } + + private JsonObject flattenWithPrefixedKeys(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) { + if (topLevelElem.isJsonPrimitive()) { + handleJsonPrimitive(topLevelElem, prefix, acc); + } else if (topLevelElem.isJsonArray()) { + handleJsonArray(parentKeyToKeySeparator, topLevelElem, prefix, acc); + } else if (topLevelElem.isJsonObject()) { + handleJsonObject(parentKeyToKeySeparator, topLevelElem, prefix, acc); + } else { + acc.add(prefix, topLevelElem.getAsJsonNull()); + } + return acc.deepCopy(); + } + + private void handleJsonObject(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) { + boolean isEmpty = true; + JsonObject thisToplevelObj = topLevelElem.getAsJsonObject(); + for (String key : thisToplevelObj.keySet()) { + isEmpty = false; + String keyPrefix = String.format("%s%s%s", prefix, parentKeyToKeySeparator, key); + flattenWithPrefixedKeys(parentKeyToKeySeparator, thisToplevelObj.get(key), keyPrefix, acc); + } + if (isEmpty && !Strings.isNullOrEmpty(prefix)) { + acc.add(prefix, new JsonObject()); + } + } + + private void handleJsonArray(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) { + JsonArray asJsonArray = topLevelElem.getAsJsonArray(); + if (asJsonArray.size() == 0) { + acc.add(prefix, new JsonArray()); + } + for (int i = 0; i < asJsonArray.size(); i++) { + flattenWithPrefixedKeys(parentKeyToKeySeparator, asJsonArray.get(i), String.format("%s[%s]", prefix, i), acc); + } + } + + private void handleJsonPrimitive(JsonElement topLevelElem, String prefix, JsonObject acc) { + JsonPrimitive jsonPrimitive = topLevelElem.getAsJsonPrimitive(); + if (jsonPrimitive.isBoolean()) { + acc.add(prefix, new JsonPrimitive(jsonPrimitive.getAsString())); + } else { + acc.add(prefix, topLevelElem.getAsJsonPrimitive()); + } + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/TemplateSearchHelper.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/TemplateSearchHelper.java new file mode 100644 index 0000000..3f22b1a --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/TemplateSearchHelper.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template.search; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.onap.pnfsimulator.template.search.handler.PrimitiveValueCriteriaBuilder; +import org.onap.pnfsimulator.template.search.viewmodel.FlatTemplateContent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Component +public class TemplateSearchHelper { + private static final String PARENT_TO_CHILD_KEY_SEPARATOR = ":"; //compliant with flat json stored in db + private static final String FLATTENED_JSON_KEY_REGEX = PARENT_TO_CHILD_KEY_SEPARATOR + "%s(?:(\\[[\\d]+\\]))?$"; + private static final String FLATTENED_TEMPLATES_VIEW = "flatTemplatesView"; + + private MongoTemplate mongoTemplate; + private PrimitiveValueCriteriaBuilder criteriaBuilder; + + @Autowired + public TemplateSearchHelper(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + this.criteriaBuilder = new PrimitiveValueCriteriaBuilder(); + } + + public List<String> getIdsOfDocumentMatchingCriteria(JsonObject jsonCriteria) { + if (isNullValuePresentInCriteria(jsonCriteria)) { + throw new IllegalJsonValueException("Null values in search criteria are not supported."); + } + Criteria mongoDialectCriteria = composeCriteria(jsonCriteria); + Query query = new Query(mongoDialectCriteria); + List<FlatTemplateContent> flatTemplateContents = mongoTemplate.find(query, FlatTemplateContent.class, FLATTENED_TEMPLATES_VIEW); + return flatTemplateContents + .stream() + .map(FlatTemplateContent::getId) + .collect(Collectors.toList()); + } + + + private Criteria composeCriteria(JsonObject criteria) { + Criteria[] criteriaArr = criteria.entrySet() + .stream() + .map(this::mapEntryCriteriaWithRegex) + .toArray(Criteria[]::new); + return criteriaArr.length > 0 ? new Criteria().andOperator(criteriaArr) : new Criteria(); + } + + private Criteria mapEntryCriteriaWithRegex(Map.Entry<String, JsonElement> entry) { + Pattern primitiveOrArrayElemKeyRegex = getCaseInsensitive(String.format(FLATTENED_JSON_KEY_REGEX, entry.getKey())); + Criteria criteriaForJsonKey = Criteria.where("k").regex(primitiveOrArrayElemKeyRegex); + Criteria criteriaWithValue = criteriaBuilder.applyValueCriteriaBasedOnPrimitiveType(criteriaForJsonKey.and("v"), entry.getValue().getAsJsonPrimitive()); + return Criteria.where("keyValues").elemMatch(criteriaWithValue); + + } + + private boolean isNullValuePresentInCriteria(JsonObject jsonObject) { + return jsonObject.entrySet() + .stream() + .map(Map.Entry::getValue) + .anyMatch(JsonElement::isJsonNull); + } + + static Pattern getCaseInsensitive(String base) { + return Pattern.compile(base, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + } +} + + diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilder.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilder.java new file mode 100644 index 0000000..79d64b7 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilder.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template.search.handler; + +import com.google.common.collect.Lists; +import com.google.gson.JsonPrimitive; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; +import java.util.regex.Pattern; + +/** + * This class is a helper class for constructing apropriate criteria for query send to mongodb based on type of value. + * Query is build to search mongodb for templates that contains key-value pairs that satisfy given criteria. + * Value is oftype JsonPrimitive, based on its primitive java type following criteria are build to get proper document: + * -for string - there is a regex expression that ignores every meta character inside passed argument and searches for exact literal match ignoring case; + * -for number - all numbers are treated as double (mongodb number type equivalent) + * -for boolean - exact match, used string representation of boolean in search + **/ + +public class PrimitiveValueCriteriaBuilder { + + private final List<ValueTypeHandler> typeHandlers; + + public PrimitiveValueCriteriaBuilder() { + typeHandlers = Lists.newArrayList(new StringValueHandler(), new NumberValueHandler(), new BoolValueHandler()); + } + + public Criteria applyValueCriteriaBasedOnPrimitiveType(Criteria baseCriteria, JsonPrimitive jsonPrimitive) { + ValueTypeHandler typeHandler = typeHandlers.stream() + .filter(el -> el.isProperTypeHandler(jsonPrimitive)) + .findFirst() + .orElseThrow(() -> + new IllegalArgumentException(String.format( + "Expected json primitive, but given value: %s is of type: %s and could not be decoded", + jsonPrimitive, jsonPrimitive.getClass().toString()))); + return typeHandler.chainCriteriaForValue(baseCriteria, jsonPrimitive); + } + + private interface ValueTypeHandler { + boolean isProperTypeHandler(JsonPrimitive value); + + Criteria chainCriteriaForValue(Criteria criteria, JsonPrimitive value); + } + + private class BoolValueHandler implements ValueTypeHandler { + public boolean isProperTypeHandler(JsonPrimitive value) { + return value.isBoolean(); + } + + public Criteria chainCriteriaForValue(Criteria criteria, JsonPrimitive value) { + return criteria.is(value.getAsString()); + } + + } + + private class NumberValueHandler implements ValueTypeHandler { + public boolean isProperTypeHandler(JsonPrimitive value) { + return value.isNumber(); + } + + public Criteria chainCriteriaForValue(Criteria baseCriteria, JsonPrimitive value) { + return baseCriteria.is(value.getAsDouble()); + } + } + + private class StringValueHandler implements ValueTypeHandler { + public boolean isProperTypeHandler(JsonPrimitive value) { + return value.isString(); + } + + public Criteria chainCriteriaForValue(Criteria baseCriteria, JsonPrimitive value) { + return baseCriteria.regex(makeRegexCaseInsensitive(value.getAsString())); + } + + private Pattern makeRegexCaseInsensitive(String base) { + String metaCharEscaped = convertToIgnoreMetaChars(base); + return Pattern.compile("^" + metaCharEscaped + "$", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + } + + private String convertToIgnoreMetaChars(String valueWithMetaChars) { + return Pattern.quote(valueWithMetaChars); + } + } +} diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/FlatTemplateContent.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/FlatTemplateContent.java new file mode 100644 index 0000000..84235f7 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/FlatTemplateContent.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template.search.viewmodel; + + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.db.Row; + +import java.util.List; + +@Getter +@NoArgsConstructor +@ToString +public class FlatTemplateContent extends Row { + + private List<KeyValuePair> keyValues; + + + public FlatTemplateContent(String name, List<KeyValuePair> keyValues) { + this.id = name; + this.keyValues = keyValues; + } +} + + diff --git a/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/KeyValuePair.java b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/KeyValuePair.java new file mode 100644 index 0000000..5e44452 --- /dev/null +++ b/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/KeyValuePair.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. 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.pnfsimulator.template.search.viewmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@NoArgsConstructor +@AllArgsConstructor +/** + * POJO for mongo structure after $objectToArray mapping where object consists of fields: k and v + */ +public class KeyValuePair { + + private String k; + private String v; + +} diff --git a/pnfsimulator/src/main/resources/application.properties b/pnfsimulator/src/main/resources/application.properties new file mode 100644 index 0000000..e2c7639 --- /dev/null +++ b/pnfsimulator/src/main/resources/application.properties @@ -0,0 +1,18 @@ +server.port=5000 +templates.dir=/app/templates +spring.data.mongodb.host=mongo +spring.data.mongodb.port=27017 +spring.data.mongodb.username=pnf_simulator_user +spring.data.mongodb.password=zXcVbN123! +spring.data.mongodb.database=pnf_simulator +management.endpoints.enabled-by-default=true +management.endpoint.configprops.enabled=true +management.endpoints.web.base-path=/ +management.server.port=5001 +management.endpoints.web.exposure.include=refresh + +ssl.clientCertificateEnabled=true +ssl.clientCertificateDir=/app/store/client.p12 +ssl.clientCertificatePassword=collector +ssl.trustStoreDir=/app/store/trustStore +ssl.trustStorePassword=collector diff --git a/pnfsimulator/src/main/resources/logback.xml b/pnfsimulator/src/main/resources/logback.xml new file mode 100644 index 0000000..8569b56 --- /dev/null +++ b/pnfsimulator/src/main/resources/logback.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. 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========================================================= + --> + +<Configuration complete="true" compact="true"> + + <Property name="outputFilename" value="pnfsimulator_output"/> + <Property name="log-path" value="/var/log/ONAP/pnfsimulator"/> + <Property name="archive" value="/var/log/ONAP/pnfsimulator/archive"/> + <property name="maxFileSize" value="50MB"/> + <property name="maxHistory" value="30"/> + <property name="totalSizeCap" value="10GB"/> + + <appender name="Console" target="SYSTEM_OUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <Pattern>%nopexception%logger + |%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} + |%level + |%replace(%replace(%message){'\t','\\\\t'}){'\n','\\\\n'} + |%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} + |%replace(%replace(%rootException){'\t','\\\\t'}){'\n','\\\\n'} + |%replace(%replace(%marker){'\t','\\\\t'}){'\n','\\\\n'} + |%thread + |%n</Pattern> + </encoder> + </appender> + + <appender name="ROLLING-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <encoder> + <pattern>%nopexception%logger + |%date{yyyy-MM-dd'T'HH:mm:ss.SSSXXX,UTC} + |%level + |%replace(%replace(%message){'\t','\\\\t'}){'\n','\\\\n'} + |%replace(%replace(%mdc){'\t','\\\\t'}){'\n','\\\\n'} + |%replace(%replace(%rootException){'\t','\\\\t'}){'\n','\\\\n'} + |%replace(%replace(%marker){'\t','\\\\t'}){'\n','\\\\n'} + |%thread + |%n</pattern> + </encoder> + <File>${log-path}/${outputFilename}.log</File> + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> + <FileNamePattern>${archive}/${outputFilename}.%d{yyyy-MM-dd}.%i.log.zip</FileNamePattern> + <MaxFileSize>${maxFileSize}</MaxFileSize> + <MaxHistory>${maxHistory}</MaxHistory> + <TotalSizeCap>${totalSizeCap}</TotalSizeCap> + </rollingPolicy> + </appender> + + <root level="info"> + <appender-ref ref="Console" /> + <appender-ref ref="ROLLING-FILE" /> + </root> +</Configuration> |