--- /dev/null
+/*\r
+ * ============LICENSE_START========================================================================\r
+ * ONAP : tr-069-adapter\r
+ * =================================================================================================\r
+ * Copyright (C) 2020 CommScope Inc Intellectual Property.\r
+ * =================================================================================================\r
+ * This tr-069-adapter software file is distributed by CommScope Inc under the Apache License,\r
+ * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You\r
+ * may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\r
+ * either express or implied. See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ===============LICENSE_END=======================================================================\r
+ */\r
+\r
+package org.commscope.tr069adapter.netconf.server;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileReader;\r
+import java.io.IOException;\r
+import java.util.Arrays;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import java.util.concurrent.TimeUnit;\r
+import java.util.regex.Matcher;\r
+import java.util.regex.Pattern;\r
+import org.commscope.tr069adapter.netconf.config.NetConfServerProperties;\r
+import org.commscope.tr069adapter.netconf.operations.CustomOperationsCreator;\r
+import org.opendaylight.netconf.test.tool.NetconfDeviceSimulator;\r
+import org.opendaylight.netconf.test.tool.config.Configuration;\r
+import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder;\r
+import org.opendaylight.netconf.test.tool.operations.OperationsCreator;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+import org.springframework.beans.factory.annotation.Autowired;\r
+import org.springframework.context.annotation.Scope;\r
+import org.springframework.stereotype.Component;\r
+import com.google.common.base.Preconditions;\r
+\r
+@Component\r
+@Scope("singleton")\r
+public class NetconfServerStarter {\r
+\r
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfServerStarter.class);\r
+\r
+ @Autowired\r
+ NetConfServerProperties config;\r
+\r
+ public boolean startServer(String netConfPort, String macID) {\r
+\r
+ if (netConfPort == null) {\r
+ LOG.error("Invalid NETCONF port for deviceID: {}, port is null.", macID);\r
+ return false;\r
+ }\r
+\r
+ LOG.debug("Starting Netconf server for MACID :{}, on port :{}", macID, netConfPort);\r
+ boolean result = startServer(netConfPort, config.getSchemaDirPath(), macID);\r
+ LOG.debug("Completed starting Netconf server for MACID :{} , on port :{}, server status={}",\r
+ macID, netConfPort, result);\r
+\r
+ return result;\r
+ }\r
+\r
+ @SuppressWarnings({"resource", "deprecation"})\r
+ private boolean startServer(String portStr, String schemaDirPath, String macID) {\r
+\r
+ // creating configuration for the netconf instance\r
+ final Configuration configuration = new ConfigurationBuilder().build();\r
+ OperationsCreator operationsCreator = new CustomOperationsCreator(macID);\r
+ configuration.setOperationsCreator(operationsCreator);\r
+ configuration.setGenerateConfigsTimeout((int) TimeUnit.MINUTES.toMillis(30));\r
+ if (portStr != null) {\r
+ try {\r
+ int port = Integer.parseInt(portStr);\r
+ configuration.setStartingPort(port);\r
+ } catch (Exception e) {\r
+ LOG.error("Failed to get netconf service instance port for parameters {}", e.toString());\r
+ return false;\r
+ }\r
+ }\r
+ configuration.setDeviceCount(1);\r
+ configuration.setSsh(Boolean.TRUE);\r
+ File schemaDir = new File(schemaDirPath);\r
+ configuration.setSchemasDir(schemaDir);\r
+ configuration.setCapabilities(Configuration.DEFAULT_BASE_CAPABILITIES_EXI);\r
+ configuration.setIp("0.0.0.0");\r
+\r
+ boolean isSchemaLoaded = loadSchemas(schemaDir);\r
+ if (!isSchemaLoaded) {\r
+ LOG.debug("Failed to load schema for netconf server instance {}", macID);\r
+ return false;\r
+ }\r
+\r
+ try(final NetconfDevice netconfDevice = new NetconfDevice(configuration)){\r
+ final List<Integer> openDevices = netconfDevice.start();\r
+ if (openDevices.isEmpty()) {\r
+ LOG.debug("Failed to start netconf server instance {}", macID);\r
+ return false;\r
+ }\r
+ netconfDevice.setAutoClose(false);\r
+ } catch (RuntimeException e) {\r
+ LOG.error("Unhandled exception. Failed to start the server", e);\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ private boolean loadSchemas(File schemasDir) {\r
+ if (schemasDir != null) {\r
+ if (!schemasDir.exists() || !schemasDir.isDirectory() || !schemasDir.canRead()) {\r
+ LOG.error("Failed to load schema. schema location is not valid.");\r
+ return false;\r
+ }\r
+\r
+ Pattern yangregex = Pattern.compile("(?<name>.*)@(?<revision>\\d{4}-\\d{2}-\\d{2})\\.yang");\r
+ Pattern revisionregex = Pattern.compile("revision\\s+\"?(\\d{4}-\\d{2}-\\d{2})\"?");\r
+\r
+ final File[] filesArray = schemasDir.listFiles();\r
+ final List<File> files =\r
+ filesArray != null ? Arrays.asList(filesArray) : Collections.emptyList();\r
+ for (final File file : files) {\r
+ final Matcher yangMatcher = yangregex.matcher(file.getName());\r
+ if (!yangMatcher.matches()) {\r
+ try (BufferedReader reader = new BufferedReader(new FileReader(file))) {\r
+ String line = reader.readLine();\r
+ while (line != null && !revisionregex.matcher(line).find()) {\r
+ line = reader.readLine();\r
+ }\r
+ loadSchemaPattren(line, file, revisionregex);\r
+ } catch (final IOException e) {\r
+ LOG.error("Unhandled exception. Failed to load the schema.{}", e.toString());\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+\r
+ private void loadSchemaPattren(String line, File file, Pattern revisionregex) {\r
+ if (line != null) {\r
+ final Matcher m = revisionregex.matcher(line);\r
+ Preconditions.checkState(m.find());\r
+ String moduleName = file.getAbsolutePath();\r
+ if (file.getName().endsWith(".yang")) {\r
+ moduleName = moduleName.substring(0, moduleName.length() - 5);\r
+ }\r
+ final String revision = m.group(1);\r
+ final String correctName = moduleName + "@" + revision + ".yang";\r
+ final File correctNameFile = new File(correctName);\r
+ if (!file.renameTo(correctNameFile)) {\r
+ throw new IllegalStateException("Failed to rename '%s'." + file);\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
+\r
+\r
+class NetconfDevice extends NetconfDeviceSimulator {\r
+ boolean autoClose = true;\r
+\r
+ public NetconfDevice(Configuration configuration) {\r
+ super(configuration);\r
+ }\r
+\r
+ @Override\r
+ public void close() {\r
+ if (autoClose)\r
+ super.close();\r
+ }\r
+\r
+ public void setAutoClose(boolean autoClose) {\r
+ this.autoClose = autoClose;\r
+ }\r
+\r
+}\r