Cleanup eclipse warnings
[bgpcep.git] / bgp / config-loader-impl / src / main / java / org / opendaylight / protocol / bgp / config / loader / impl / ConfigLoaderImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.protocol.bgp.config.loader.impl;
10
11 import com.google.common.base.Preconditions;
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.net.URISyntaxException;
17 import java.nio.file.WatchEvent;
18 import java.nio.file.WatchKey;
19 import java.nio.file.WatchService;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.regex.Pattern;
23 import javax.annotation.concurrent.GuardedBy;
24 import javax.xml.parsers.ParserConfigurationException;
25 import javax.xml.stream.XMLInputFactory;
26 import javax.xml.stream.XMLStreamException;
27 import javax.xml.stream.XMLStreamReader;
28 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
29 import org.opendaylight.protocol.bgp.config.loader.spi.ConfigFileProcessor;
30 import org.opendaylight.protocol.bgp.config.loader.spi.ConfigLoader;
31 import org.opendaylight.yangtools.concepts.AbstractRegistration;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
34 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
35 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
36 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
38 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
39 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.xml.sax.SAXException;
43
44 public final class ConfigLoaderImpl implements ConfigLoader, AutoCloseable {
45     private static final Logger LOG = LoggerFactory.getLogger(ConfigLoaderImpl.class);
46     private static final String INTERRUPTED = "InterruptedException";
47     private static final String EXTENSION = "-.*\\.xml";
48     private static final String INITIAL = "^";
49     @GuardedBy("this")
50     private final Map<String, ConfigFileProcessor> configServices = new HashMap<>();
51     private final SchemaContext schemaContext;
52     private final BindingNormalizedNodeSerializer bindingSerializer;
53     private final String path;
54     private final Thread watcherThread;
55
56     public ConfigLoaderImpl(final SchemaContext schemaContext, final BindingNormalizedNodeSerializer bindingSerializer,
57         final String path, final WatchService watchService) {
58         this.schemaContext = Preconditions.checkNotNull(schemaContext);
59         this.bindingSerializer = Preconditions.checkNotNull(bindingSerializer);
60         this.path = Preconditions.checkNotNull(path);
61         Preconditions.checkNotNull(watchService);
62         this.watcherThread = new Thread(new ConfigLoaderImplRunnable(watchService));
63         this.watcherThread.start();
64         LOG.info("Config Loader service initiated");
65     }
66
67     private void handleConfigFile(final ConfigFileProcessor config, final String filename) {
68         final NormalizedNode<?, ?> dto;
69         try {
70             dto = parseDefaultConfigFile(config, filename);
71         } catch (final Exception e) {
72             LOG.warn("Failed to parse config file {}", filename, e);
73             return;
74         }
75         LOG.info("Loading initial config {}", filename);
76         config.loadConfiguration(dto);
77     }
78
79     private NormalizedNode<?, ?> parseDefaultConfigFile(final ConfigFileProcessor config, final String filename)
80         throws IOException, XMLStreamException, ParserConfigurationException, SAXException, URISyntaxException {
81         final NormalizedNodeResult result = new NormalizedNodeResult();
82         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
83
84         final InputStream resourceAsStream = new FileInputStream(new File(this.path, filename));
85         final XMLInputFactory factory = XMLInputFactory.newInstance();
86         final XMLStreamReader reader = factory.createXMLStreamReader(resourceAsStream);
87
88         final SchemaNode schemaNode = SchemaContextUtil.findDataSchemaNode(this.schemaContext, config.getSchemaPath());
89         final XmlParserStream xmlParser = XmlParserStream.create(streamWriter, this.schemaContext, schemaNode);
90         xmlParser.parse(reader);
91
92         return result.getResult();
93     }
94
95     @Override
96     public synchronized AbstractRegistration registerConfigFile(final ConfigFileProcessor config) {
97         final String pattern = INITIAL + config.getSchemaPath().getLastComponent().getLocalName() + EXTENSION;
98         this.configServices.put(pattern, config);
99
100         final File[] fList = new File(this.path).listFiles();
101         if (fList != null) {
102             for (final File file : fList) {
103                 if (file.isFile()) {
104                     final String filename = file.getName();
105                     if (Pattern.matches(pattern, filename)) {
106                         handleConfigFile(config, filename);
107                     }
108                 }
109             }
110         }
111
112         return new AbstractRegistration() {
113             @Override
114             protected void removeRegistration() {
115                 synchronized (ConfigLoaderImpl.this) {
116                     ConfigLoaderImpl.this.configServices.remove(pattern);
117                 }
118             }
119         };
120     }
121
122     @Override
123     public BindingNormalizedNodeSerializer getBindingNormalizedNodeSerializer() {
124         return this.bindingSerializer;
125     }
126
127
128     @Override
129     public void close() throws Exception {
130         this.watcherThread.interrupt();
131     }
132
133     private class ConfigLoaderImplRunnable implements Runnable {
134         private final WatchService watchService;
135
136         ConfigLoaderImplRunnable(final WatchService watchService) {
137             this.watchService = watchService;
138         }
139
140         @Override
141         public void run() {
142             try {
143                 while (!Thread.currentThread().isInterrupted()) {
144                     handleChanges(this.watchService);
145                 }
146             } catch (final Exception e) {
147                 LOG.warn(INTERRUPTED, e);
148             }
149         }
150
151         private synchronized void handleChanges(final WatchService watchService) {
152             try {
153                 final WatchKey key = watchService.take();
154                 if (key != null) {
155                     for (final WatchEvent<?> event : key.pollEvents()) {
156                         handleEvent(event.context().toString());
157                     }
158                     final boolean reset = key.reset();
159                     if (!reset) {
160                         LOG.warn("Could not reset the watch key.");
161                     }
162                 }
163             } catch (final InterruptedException e) {
164                 LOG.warn(INTERRUPTED, e);
165             }
166         }
167
168         private synchronized void handleEvent(final String filename) {
169             ConfigLoaderImpl.this.configServices.entrySet().stream()
170                 .filter(entry -> Pattern.matches(entry.getKey(), filename)).
171                 forEach(entry -> handleConfigFile(entry.getValue(), filename));
172         }
173     }
174 }