Andrea Campanella
Committed by Gerrit Code Review

ONOS-3605 Create thread Session input stream mechanism, adding listener for events from the device

Change-Id: Ib323487f61d9e595f7ccdc1957a92e58b7002d2a
...@@ -19,7 +19,6 @@ package org.onosproject.netconf; ...@@ -19,7 +19,6 @@ package org.onosproject.netconf;
19 import org.onlab.packet.IpAddress; 19 import org.onlab.packet.IpAddress;
20 import org.onosproject.net.DeviceId; 20 import org.onosproject.net.DeviceId;
21 21
22 -import java.io.IOException;
23 import java.util.Map; 22 import java.util.Map;
24 23
25 /** 24 /**
...@@ -48,8 +47,9 @@ public interface NetconfController { ...@@ -48,8 +47,9 @@ public interface NetconfController {
48 * 47 *
49 * @param deviceInfo info about the device to add 48 * @param deviceInfo info about the device to add
50 * @return NetconfDevice Netconf device 49 * @return NetconfDevice Netconf device
50 + * @throws NetconfException when device is not available
51 */ 51 */
52 - NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) throws IOException; 52 + NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) throws NetconfException;
53 53
54 /** 54 /**
55 * Removes a Netconf device. 55 * Removes a Netconf device.
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.netconf;
18 +
19 +import org.onosproject.event.AbstractEvent;
20 +
21 +/**
22 + * Describes network configuration event.
23 + */
24 +public final class NetconfDeviceOutputEvent extends
25 + AbstractEvent<NetconfDeviceOutputEvent.Type, Object> {
26 +
27 + private final String messagePayload;
28 + private final int messageID;
29 + private final NetconfDeviceInfo deviceInfo;
30 +
31 + /**
32 + * Type of network configuration events.
33 + */
34 + public enum Type {
35 + /**
36 + * Signifies that sent a reply to a request.
37 + */
38 + DEVICE_REPLY,
39 +
40 + /**
41 + * Signifies that the device sent a notification.
42 + */
43 + DEVICE_NOTIFICATION,
44 +
45 + /**
46 + * Signifies that the device is not reachable.
47 + */
48 + DEVICE_UNREGISTERED,
49 +
50 + /**
51 + * Signifies that the device has encountered an error.
52 + */
53 + DEVICE_ERROR,
54 +
55 + }
56 +
57 + /**
58 + * Creates an event of a given type and for the specified subject and the
59 + * current time.
60 + *
61 + * @param type event type
62 + * @param subject event subject
63 + * @param payload message from the device
64 + * @param msgID id of the message related to the event
65 + * @param netconfDeviceInfo device of event
66 + */
67 + public NetconfDeviceOutputEvent(Type type, Object subject, String payload, int msgID,
68 + NetconfDeviceInfo netconfDeviceInfo) {
69 + super(type, subject);
70 + messagePayload = payload;
71 + this.messageID = msgID;
72 + deviceInfo = netconfDeviceInfo;
73 + }
74 +
75 + /**
76 + * Creates an event of a given type and for the specified subject and time.
77 + *
78 + * @param type event type
79 + * @param subject event subject
80 + * @param payload message from the device
81 + * @param msgID id of the message related to the event
82 + * @param netconfDeviceInfo device of event
83 + * @param msgID id of the message related to the event
84 + * @param time occurrence time
85 + */
86 + public NetconfDeviceOutputEvent(Type type, Object subject, String payload, int msgID,
87 + NetconfDeviceInfo netconfDeviceInfo, long time) {
88 + super(type, subject, time);
89 + messagePayload = payload;
90 + deviceInfo = netconfDeviceInfo;
91 + this.messageID = msgID;
92 + }
93 +
94 + public String getMessagePayload() {
95 + return messagePayload;
96 + }
97 +
98 + public NetconfDeviceInfo getDeviceInfo() {
99 + return deviceInfo;
100 + }
101 +
102 + public Integer getMessageID() {
103 + return messageID;
104 + }
105 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.netconf;
18 +
19 +import org.onosproject.event.EventListener;
20 +
21 +/**
22 + * Interface for Netconf device output Listeners.
23 + */
24 +public interface NetconfDeviceOutputEventListener extends EventListener<NetconfDeviceOutputEvent> {
25 +}
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.netconf;
17 +
18 +import java.io.IOException;
19 +
20 +/**
21 + * Represents class of errors related to NETCONF SB protocol.
22 + */
23 +public class NetconfException extends IOException {
24 + /**
25 + * Constructs an exception with the specified message.
26 + *
27 + * @param message the message describing the specific nature of the error
28 + */
29 + public NetconfException(String message) {
30 + super(message);
31 + }
32 +
33 + /**
34 + * Constructs an exception with the specified message and the underlying cause.
35 + *
36 + * @param message the message describing the specific nature of the error
37 + * @param cause the underlying cause of this error
38 + */
39 + public NetconfException(String message, Throwable cause) {
40 + super(message, cause);
41 + }
42 +}
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
16 16
17 package org.onosproject.netconf; 17 package org.onosproject.netconf;
18 18
19 -import java.io.IOException;
20 import java.util.List; 19 import java.util.List;
20 +import java.util.concurrent.CompletableFuture;
21 21
22 /** 22 /**
23 * NETCONF session object that allows NETCONF operations on top with the physical 23 * NETCONF session object that allows NETCONF operations on top with the physical
...@@ -27,28 +27,45 @@ import java.util.List; ...@@ -27,28 +27,45 @@ import java.util.List;
27 public interface NetconfSession { 27 public interface NetconfSession {
28 28
29 /** 29 /**
30 + * Executes an asynchronous RPC to the server and obtains a future to be completed.
31 + *
32 + * @param request the XML containing the RPC for the server.
33 + * @return Server response or ERROR
34 + * @throws NetconfException when there is a problem in the communication process on
35 + * the underlying connection
36 + */
37 + CompletableFuture<String> request(String request) throws NetconfException;
38 +
39 +
40 + /**
30 * Retrives the requested configuration, different from get-config. 41 * Retrives the requested configuration, different from get-config.
31 * 42 *
32 * @param request the XML containing the request to the server. 43 * @param request the XML containing the request to the server.
33 * @return device running configuration 44 * @return device running configuration
45 + * @throws NetconfException when there is a problem in the communication process on
46 + * the underlying connection
34 */ 47 */
35 - String get(String request) throws IOException; 48 + String get(String request) throws NetconfException;
36 49
37 /** 50 /**
38 - * Executes an RPC to the server. 51 + * Executes an synchronous RPC to the server.
39 * 52 *
40 * @param request the XML containing the RPC for the server. 53 * @param request the XML containing the RPC for the server.
41 * @return Server response or ERROR 54 * @return Server response or ERROR
55 + * @throws NetconfException when there is a problem in the communication process on
56 + * the underlying connection
42 */ 57 */
43 - String doRPC(String request) throws IOException; 58 + String requestSync(String request) throws NetconfException;
44 59
45 /** 60 /**
46 * Retrives the specified configuration. 61 * Retrives the specified configuration.
47 * 62 *
48 * @param targetConfiguration the type of configuration to retrieve. 63 * @param targetConfiguration the type of configuration to retrieve.
49 * @return specified configuration. 64 * @return specified configuration.
65 + * @throws NetconfException when there is a problem in the communication process on
66 + * the underlying connection
50 */ 67 */
51 - String getConfig(String targetConfiguration) throws IOException; 68 + String getConfig(String targetConfiguration) throws NetconfException;
52 69
53 /** 70 /**
54 * Retrives part of the specivied configuration based on the filterSchema. 71 * Retrives part of the specivied configuration based on the filterSchema.
...@@ -57,28 +74,35 @@ public interface NetconfSession { ...@@ -57,28 +74,35 @@ public interface NetconfSession {
57 * @param configurationFilterSchema XML schema to filter the configuration 74 * @param configurationFilterSchema XML schema to filter the configuration
58 * elements we are interested in 75 * elements we are interested in
59 * @return device running configuration. 76 * @return device running configuration.
77 + * @throws NetconfException when there is a problem in the communication process on
78 + * the underlying connection
60 */ 79 */
61 String getConfig(String targetConfiguration, String configurationFilterSchema) 80 String getConfig(String targetConfiguration, String configurationFilterSchema)
62 - throws IOException; 81 + throws NetconfException;
63 82
64 /** 83 /**
65 * Retrives part of the specified configuration based on the filterSchema. 84 * Retrives part of the specified configuration based on the filterSchema.
66 * 85 *
67 * @param newConfiguration configuration to set 86 * @param newConfiguration configuration to set
68 * @return true if the configuration was edited correctly 87 * @return true if the configuration was edited correctly
88 + * @throws NetconfException when there is a problem in the communication process on
89 + * the underlying connection
69 */ 90 */
70 91
71 - boolean editConfig(String newConfiguration) throws IOException; 92 + boolean editConfig(String newConfiguration) throws NetconfException;
72 93
73 /** 94 /**
74 * Retrives part of the specified configuration based on the filterSchema. 95 * Retrives part of the specified configuration based on the filterSchema.
96 + *
75 * @param targetConfiguration the targetConfiguration to change 97 * @param targetConfiguration the targetConfiguration to change
76 - * @param mode selected mode to change the configuration 98 + * @param mode selected mode to change the configuration
77 - * @param newConfiguration configuration to set 99 + * @param newConfiguration configuration to set
78 * @return true if the configuration was edited correctly 100 * @return true if the configuration was edited correctly
101 + * @throws NetconfException when there is a problem in the communication process on
102 + * the underlying connection
79 */ 103 */
80 boolean editConfig(String targetConfiguration, String mode, String newConfiguration) 104 boolean editConfig(String targetConfiguration, String mode, String newConfiguration)
81 - throws IOException; 105 + throws NetconfException;
82 106
83 /** 107 /**
84 * Copies the new configuration, an Url or a complete configuration xml tree 108 * Copies the new configuration, an Url or a complete configuration xml tree
...@@ -88,39 +112,49 @@ public interface NetconfSession { ...@@ -88,39 +112,49 @@ public interface NetconfSession {
88 * @param targetConfiguration the type of configuration to retrieve. 112 * @param targetConfiguration the type of configuration to retrieve.
89 * @param newConfiguration configuration to set 113 * @param newConfiguration configuration to set
90 * @return true if the configuration was copied correctly 114 * @return true if the configuration was copied correctly
115 + * @throws NetconfException when there is a problem in the communication process on
116 + * the underlying connection
91 */ 117 */
92 boolean copyConfig(String targetConfiguration, String newConfiguration) 118 boolean copyConfig(String targetConfiguration, String newConfiguration)
93 - throws IOException; 119 + throws NetconfException;
94 120
95 /** 121 /**
96 * Deletes part of the specified configuration based on the filterSchema. 122 * Deletes part of the specified configuration based on the filterSchema.
97 * 123 *
98 * @param targetConfiguration the name of the configuration to delete 124 * @param targetConfiguration the name of the configuration to delete
99 * @return true if the configuration was copied correctly 125 * @return true if the configuration was copied correctly
126 + * @throws NetconfException when there is a problem in the communication process on
127 + * the underlying connection
100 */ 128 */
101 - boolean deleteConfig(String targetConfiguration) throws IOException; 129 + boolean deleteConfig(String targetConfiguration) throws NetconfException;
102 130
103 /** 131 /**
104 * Locks the candidate configuration. 132 * Locks the candidate configuration.
105 * 133 *
106 * @return true if successful. 134 * @return true if successful.
135 + * @throws NetconfException when there is a problem in the communication process on
136 + * the underlying connection
107 */ 137 */
108 - boolean lock() throws IOException; 138 + boolean lock() throws NetconfException;
109 139
110 /** 140 /**
111 * Unlocks the candidate configuration. 141 * Unlocks the candidate configuration.
112 * 142 *
113 * @return true if successful. 143 * @return true if successful.
144 + * @throws NetconfException when there is a problem in the communication process on
145 + * the underlying connection
114 */ 146 */
115 - boolean unlock() throws IOException; 147 + boolean unlock() throws NetconfException;
116 148
117 /** 149 /**
118 * Closes the Netconf session with the device. 150 * Closes the Netconf session with the device.
119 * the first time it tries gracefully, then kills it forcefully 151 * the first time it tries gracefully, then kills it forcefully
120 * 152 *
121 * @return true if closed 153 * @return true if closed
154 + * @throws NetconfException when there is a problem in the communication process on
155 + * the underlying connection
122 */ 156 */
123 - boolean close() throws IOException; 157 + boolean close() throws NetconfException;
124 158
125 /** 159 /**
126 * Gets the session ID of the Netconf session. 160 * Gets the session ID of the Netconf session.
...@@ -137,10 +171,24 @@ public interface NetconfSession { ...@@ -137,10 +171,24 @@ public interface NetconfSession {
137 String getServerCapabilities(); 171 String getServerCapabilities();
138 172
139 /** 173 /**
140 - * Sets the device capabilities. 174 + * Sets the ONOS side capabilities.
141 * 175 *
142 * @param capabilities list of capabilities the device has. 176 * @param capabilities list of capabilities the device has.
143 */ 177 */
144 void setDeviceCapabilities(List<String> capabilities); 178 void setDeviceCapabilities(List<String> capabilities);
145 179
180 + /**
181 + * Remove a listener from the underlying stream handler implementation.
182 + *
183 + * @param listener event listener.
184 + */
185 + void addDeviceOutputListener(NetconfDeviceOutputEventListener listener);
186 +
187 + /**
188 + * Remove a listener from the underlying stream handler implementation.
189 + *
190 + * @param listener event listener.
191 + */
192 + void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener);
193 +
146 } 194 }
......
...@@ -26,11 +26,11 @@ import org.onosproject.netconf.NetconfController; ...@@ -26,11 +26,11 @@ import org.onosproject.netconf.NetconfController;
26 import org.onosproject.netconf.NetconfDevice; 26 import org.onosproject.netconf.NetconfDevice;
27 import org.onosproject.netconf.NetconfDeviceInfo; 27 import org.onosproject.netconf.NetconfDeviceInfo;
28 import org.onosproject.netconf.NetconfDeviceListener; 28 import org.onosproject.netconf.NetconfDeviceListener;
29 +import org.onosproject.netconf.NetconfException;
29 import org.osgi.service.component.ComponentContext; 30 import org.osgi.service.component.ComponentContext;
30 import org.slf4j.Logger; 31 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory; 32 import org.slf4j.LoggerFactory;
32 33
33 -import java.io.IOException;
34 import java.util.Map; 34 import java.util.Map;
35 import java.util.Set; 35 import java.util.Set;
36 import java.util.concurrent.ConcurrentHashMap; 36 import java.util.concurrent.ConcurrentHashMap;
...@@ -90,9 +90,9 @@ public class NetconfControllerImpl implements NetconfController { ...@@ -90,9 +90,9 @@ public class NetconfControllerImpl implements NetconfController {
90 } 90 }
91 91
92 @Override 92 @Override
93 - public NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) throws IOException { 93 + public NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
94 if (netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) { 94 if (netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) {
95 - log.warn("Device {} is already present", deviceInfo); 95 + log.info("Device {} is already present", deviceInfo);
96 return netconfDeviceMap.get(deviceInfo.getDeviceId()); 96 return netconfDeviceMap.get(deviceInfo.getDeviceId());
97 } else { 97 } else {
98 log.info("Creating NETCONF device {}", deviceInfo); 98 log.info("Creating NETCONF device {}", deviceInfo);
...@@ -109,9 +109,8 @@ public class NetconfControllerImpl implements NetconfController { ...@@ -109,9 +109,8 @@ public class NetconfControllerImpl implements NetconfController {
109 } 109 }
110 } 110 }
111 111
112 - private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) throws IOException { 112 + private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
113 - NetconfDevice netconfDevice = null; 113 + NetconfDevice netconfDevice = new NetconfDeviceImpl(deviceInfo);
114 - netconfDevice = new NetconfDeviceImpl(deviceInfo);
115 for (NetconfDeviceListener l : netconfDeviceListeners) { 114 for (NetconfDeviceListener l : netconfDeviceListeners) {
116 l.deviceAdded(deviceInfo); 115 l.deviceAdded(deviceInfo);
117 } 116 }
......
...@@ -18,6 +18,7 @@ package org.onosproject.netconf.ctl; ...@@ -18,6 +18,7 @@ package org.onosproject.netconf.ctl;
18 18
19 import org.onosproject.netconf.NetconfDevice; 19 import org.onosproject.netconf.NetconfDevice;
20 import org.onosproject.netconf.NetconfDeviceInfo; 20 import org.onosproject.netconf.NetconfDeviceInfo;
21 +import org.onosproject.netconf.NetconfException;
21 import org.onosproject.netconf.NetconfSession; 22 import org.onosproject.netconf.NetconfSession;
22 import org.slf4j.Logger; 23 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory; 24 import org.slf4j.LoggerFactory;
...@@ -36,12 +37,13 @@ public class NetconfDeviceImpl implements NetconfDevice { ...@@ -36,12 +37,13 @@ public class NetconfDeviceImpl implements NetconfDevice {
36 private boolean deviceState = false; 37 private boolean deviceState = false;
37 private NetconfSession netconfSession; 38 private NetconfSession netconfSession;
38 39
39 - public NetconfDeviceImpl(NetconfDeviceInfo deviceInfo) throws IOException { 40 + public NetconfDeviceImpl(NetconfDeviceInfo deviceInfo) throws NetconfException {
40 netconfDeviceInfo = deviceInfo; 41 netconfDeviceInfo = deviceInfo;
41 try { 42 try {
42 netconfSession = new NetconfSessionImpl(netconfDeviceInfo); 43 netconfSession = new NetconfSessionImpl(netconfDeviceInfo);
43 } catch (IOException e) { 44 } catch (IOException e) {
44 - throw new IOException("Cannot create connection and session", e); 45 + throw new NetconfException("Cannot create connection and session for device " +
46 + deviceInfo, e);
45 } 47 }
46 deviceState = true; 48 deviceState = true;
47 } 49 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.netconf.ctl;
18 +
19 +import org.onosproject.netconf.NetconfDeviceInfo;
20 +import org.onosproject.netconf.NetconfDeviceOutputEvent;
21 +import org.onosproject.netconf.NetconfDeviceOutputEventListener;
22 +import org.slf4j.Logger;
23 +import org.slf4j.LoggerFactory;
24 +
25 +/**
26 + * Example of a listener for events that happen a Netconf session established
27 + * for a particular NETCONF device.
28 + */
29 +public class NetconfDeviceOutputEventListenerImpl implements NetconfDeviceOutputEventListener {
30 +
31 + private static final Logger log =
32 + LoggerFactory.getLogger(NetconfDeviceOutputEventListenerImpl.class);
33 +
34 + private NetconfDeviceInfo deviceInfo;
35 +
36 + public NetconfDeviceOutputEventListenerImpl(NetconfDeviceInfo deviceInfo) {
37 + this.deviceInfo = deviceInfo;
38 + }
39 +
40 + @Override
41 + public void event(NetconfDeviceOutputEvent event) {
42 + switch (event.type()) {
43 + case DEVICE_REPLY:
44 + log.debug("Device {} has reply: {}", deviceInfo, event.getMessagePayload());
45 + break;
46 + case DEVICE_NOTIFICATION:
47 + log.info("Device {} has notification: {}", deviceInfo, event.getMessagePayload());
48 + break;
49 + case DEVICE_UNREGISTERED:
50 + log.warn("Device {} has closed session", deviceInfo);
51 + //TODO tell onos about closed session
52 + break;
53 + case DEVICE_ERROR:
54 + log.warn("Device {} has error: {}", deviceInfo, event.getMessagePayload());
55 + break;
56 + default:
57 + log.warn("Wrong event type {} ", event.type());
58 + }
59 +
60 + }
61 +
62 + @Override
63 + public boolean isRelevant(NetconfDeviceOutputEvent event) {
64 + return deviceInfo.equals(event.getDeviceInfo());
65 + }
66 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.netconf.ctl;
18 +
19 +import org.onosproject.netconf.NetconfDeviceOutputEvent;
20 +
21 +/**
22 + * Entity associated with a NetconfSessionImpl and capable of receiving notifications of
23 + * events about the session.
24 + */
25 +public interface NetconfSessionDelegate {
26 +
27 + /**
28 + * Notifies the delegate via the specified event.
29 + *
30 + * @param event store generated event
31 + */
32 + void notify(NetconfDeviceOutputEvent event);
33 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.netconf.ctl;
18 +
19 +import org.onosproject.netconf.NetconfDeviceOutputEventListener;
20 +
21 +import java.util.concurrent.CompletableFuture;
22 +
23 +/**
24 + * Interface to represent an objects that does all the IO on a NETCONF session
25 + * with a device.
26 + */
27 +public interface NetconfStreamHandler {
28 + /**
29 + * Sends the request on the stream that is used to communicate to and from the device.
30 + *
31 + * @param request request to send to the physical device
32 + * @return a CompletableFuture of type String that will contain the response for the request.
33 + */
34 + CompletableFuture<String> sendMessage(String request);
35 +
36 + /**
37 + * Adds a listener for netconf events on the handled stream.
38 + *
39 + * @param listener Netconf device event listener
40 + */
41 + void addDeviceEventListener(NetconfDeviceOutputEventListener listener);
42 +
43 + /**
44 + * Removes a listener for netconf events on the handled stream.
45 + *
46 + * @param listener Netconf device event listener
47 + */
48 + void removeDeviceEventListener(NetconfDeviceOutputEventListener listener);
49 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.netconf.ctl;
18 +
19 +import com.google.common.base.Preconditions;
20 +import com.google.common.collect.Lists;
21 +import org.onosproject.netconf.NetconfDeviceInfo;
22 +import org.onosproject.netconf.NetconfDeviceOutputEvent;
23 +import org.onosproject.netconf.NetconfDeviceOutputEventListener;
24 +import org.onosproject.netconf.NetconfException;
25 +import org.slf4j.Logger;
26 +import org.slf4j.LoggerFactory;
27 +
28 +import java.io.BufferedReader;
29 +import java.io.IOException;
30 +import java.io.InputStream;
31 +import java.io.InputStreamReader;
32 +import java.io.OutputStream;
33 +import java.io.PrintWriter;
34 +import java.util.List;
35 +import java.util.concurrent.CompletableFuture;
36 +
37 +/**
38 + * Thread that gets spawned each time a session is established and handles all the input
39 + * and output from the session's streams to and from the NETCONF device the session is
40 + * established with.
41 + */
42 +public class NetconfStreamThread extends Thread implements NetconfStreamHandler {
43 +
44 + private static final Logger log = LoggerFactory
45 + .getLogger(NetconfStreamThread.class);
46 + private static final String HELLO = "hello";
47 + private static final String END_PATTERN = "]]>]]>";
48 + private static final String RPC_REPLY = "rpc-reply";
49 + private static final String RPC_ERROR = "rpc-error";
50 + private static final String NOTIFICATION_LABEL = "<notification>";
51 +
52 + private static PrintWriter outputStream;
53 + private static NetconfDeviceInfo netconfDeviceInfo;
54 + private static NetconfSessionDelegate sessionDelegate;
55 + private static NetconfMessageState state;
56 + private static List<NetconfDeviceOutputEventListener> netconfDeviceEventListeners
57 + = Lists.newArrayList();
58 +
59 + public NetconfStreamThread(final InputStream in, final OutputStream out,
60 + final InputStream err, NetconfDeviceInfo deviceInfo,
61 + NetconfSessionDelegate delegate) {
62 + super(handler(in, err));
63 + outputStream = new PrintWriter(out);
64 + netconfDeviceInfo = deviceInfo;
65 + state = NetconfMessageState.NO_MATCHING_PATTERN;
66 + sessionDelegate = delegate;
67 + log.debug("Stream thread for device {} session started", deviceInfo);
68 + start();
69 + }
70 +
71 + @Override
72 + public CompletableFuture<String> sendMessage(String request) {
73 + outputStream.print(request);
74 + outputStream.flush();
75 + return new CompletableFuture<>();
76 + }
77 +
78 + public enum NetconfMessageState {
79 +
80 + NO_MATCHING_PATTERN {
81 + @Override
82 + NetconfMessageState evaluateChar(char c) {
83 + if (c == ']') {
84 + return FIRST_BRAKET;
85 + } else {
86 + return this;
87 + }
88 + }
89 + },
90 + FIRST_BRAKET {
91 + @Override
92 + NetconfMessageState evaluateChar(char c) {
93 + if (c == ']') {
94 + return SECOND_BRAKET;
95 + } else {
96 + return NO_MATCHING_PATTERN;
97 + }
98 + }
99 + },
100 + SECOND_BRAKET {
101 + @Override
102 + NetconfMessageState evaluateChar(char c) {
103 + if (c == '>') {
104 + return FIRST_BIGGER;
105 + } else {
106 + return NO_MATCHING_PATTERN;
107 + }
108 + }
109 + },
110 + FIRST_BIGGER {
111 + @Override
112 + NetconfMessageState evaluateChar(char c) {
113 + if (c == ']') {
114 + return THIRD_BRAKET;
115 + } else {
116 + return NO_MATCHING_PATTERN;
117 + }
118 + }
119 + },
120 + THIRD_BRAKET {
121 + @Override
122 + NetconfMessageState evaluateChar(char c) {
123 + if (c == ']') {
124 + return ENDING_BIGGER;
125 + } else {
126 + return NO_MATCHING_PATTERN;
127 + }
128 + }
129 + },
130 + ENDING_BIGGER {
131 + @Override
132 + NetconfMessageState evaluateChar(char c) {
133 + if (c == '>') {
134 + return END_PATTERN;
135 + } else {
136 + return NO_MATCHING_PATTERN;
137 + }
138 + }
139 + },
140 + END_PATTERN {
141 + @Override
142 + NetconfMessageState evaluateChar(char c) {
143 + return NO_MATCHING_PATTERN;
144 + }
145 + };
146 +
147 + abstract NetconfMessageState evaluateChar(char c);
148 + }
149 +
150 + private static Runnable handler(final InputStream in, final InputStream err) {
151 + BufferedReader bufferReader = new BufferedReader(new InputStreamReader(in));
152 + return () -> {
153 + try {
154 + boolean socketClosed = false;
155 + StringBuilder deviceReplyBuilder = new StringBuilder();
156 + while (!socketClosed) {
157 + int cInt = bufferReader.read();
158 + if (cInt == -1) {
159 + socketClosed = true;
160 + NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
161 + NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED,
162 + null, null, -1, netconfDeviceInfo);
163 + netconfDeviceEventListeners.forEach(
164 + listener -> listener.event(event));
165 + }
166 + char c = (char) cInt;
167 + state = state.evaluateChar(c);
168 + deviceReplyBuilder.append(c);
169 + if (state == NetconfMessageState.END_PATTERN) {
170 + String deviceReply = deviceReplyBuilder.toString()
171 + .replace(END_PATTERN, "");
172 + if (deviceReply.contains(RPC_REPLY) ||
173 + deviceReply.contains(RPC_ERROR) ||
174 + deviceReply.contains(HELLO)) {
175 + NetconfDeviceOutputEvent event = new NetconfDeviceOutputEvent(
176 + NetconfDeviceOutputEvent.Type.DEVICE_REPLY,
177 + null, deviceReply, getMsgId(deviceReply), netconfDeviceInfo);
178 + sessionDelegate.notify(event);
179 + netconfDeviceEventListeners.forEach(
180 + listener -> listener.event(event));
181 + } else if (deviceReply.contains(NOTIFICATION_LABEL)) {
182 + final String finalDeviceReply = deviceReply;
183 + netconfDeviceEventListeners.forEach(
184 + listener -> listener.event(new NetconfDeviceOutputEvent(
185 + NetconfDeviceOutputEvent.Type.DEVICE_NOTIFICATION,
186 + null, finalDeviceReply, getMsgId(finalDeviceReply), netconfDeviceInfo)));
187 + } else {
188 + log.info("Error on replay from device {} ", deviceReply);
189 + }
190 + deviceReplyBuilder.setLength(0);
191 + }
192 + }
193 + } catch (IOException e) {
194 + log.warn("Error in reading from the session for device " + netconfDeviceInfo, e);
195 + throw new RuntimeException(new NetconfException("Error in reading from the session for device {}" +
196 + netconfDeviceInfo, e));
197 + //TODO should we send a socket closed message to listeners ?
198 + }
199 + };
200 + }
201 +
202 + private static int getMsgId(String reply) {
203 + if (!reply.contains(HELLO)) {
204 + String[] outer = reply.split("message-id=");
205 + Preconditions.checkArgument(outer.length != 1,
206 + "Error in retrieving the message id");
207 + String messageID = outer[1].substring(0, 3).replace("\"", "");
208 + Preconditions.checkNotNull(Integer.parseInt(messageID),
209 + "Error in retrieving the message id");
210 + return Integer.parseInt(messageID);
211 + } else {
212 + return 0;
213 + }
214 + }
215 +
216 + public void addDeviceEventListener(NetconfDeviceOutputEventListener listener) {
217 + if (!netconfDeviceEventListeners.contains(listener)) {
218 + netconfDeviceEventListeners.add(listener);
219 + }
220 + }
221 +
222 + public void removeDeviceEventListener(NetconfDeviceOutputEventListener listener) {
223 + netconfDeviceEventListeners.remove(listener);
224 + }
225 +}
...@@ -65,7 +65,7 @@ public class NetconfDeviceProvider extends AbstractProvider ...@@ -65,7 +65,7 @@ public class NetconfDeviceProvider extends AbstractProvider
65 protected DeviceProviderRegistry providerRegistry; 65 protected DeviceProviderRegistry providerRegistry;
66 66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 - protected NetconfController controller; //where is initiated ? 68 + protected NetconfController controller;
69 69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected NetworkConfigRegistry cfgService; 71 protected NetworkConfigRegistry cfgService;
...@@ -73,11 +73,13 @@ public class NetconfDeviceProvider extends AbstractProvider ...@@ -73,11 +73,13 @@ public class NetconfDeviceProvider extends AbstractProvider
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected CoreService coreService; 74 protected CoreService coreService;
75 75
76 + private static final String APP_NAME = "org.onosproject.netconf";
77 + private static final String SCHEME_NAME = "netconf";
78 + private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.netconf.provider.device";
79 + private static final String UNKNOWN = "unknown";
76 80
77 private DeviceProviderService providerService; 81 private DeviceProviderService providerService;
78 private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener(); 82 private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
79 - protected static final String ISNOTNULL = "NetconfDeviceInfo is not null";
80 - private static final String UNKNOWN = "unknown";
81 83
82 private final ConfigFactory factory = 84 private final ConfigFactory factory =
83 new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY, 85 new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
...@@ -96,10 +98,10 @@ public class NetconfDeviceProvider extends AbstractProvider ...@@ -96,10 +98,10 @@ public class NetconfDeviceProvider extends AbstractProvider
96 @Activate 98 @Activate
97 public void activate() { 99 public void activate() {
98 providerService = providerRegistry.register(this); 100 providerService = providerRegistry.register(this);
101 + appId = coreService.registerApplication(APP_NAME);
99 cfgService.registerConfigFactory(factory); 102 cfgService.registerConfigFactory(factory);
100 cfgService.addListener(cfgLister); 103 cfgService.addListener(cfgLister);
101 controller.addDeviceListener(innerNodeListener); 104 controller.addDeviceListener(innerNodeListener);
102 - appId = coreService.registerApplication("org.onosproject.netconf");
103 connectDevices(); 105 connectDevices();
104 log.info("Started"); 106 log.info("Started");
105 } 107 }
...@@ -110,11 +112,12 @@ public class NetconfDeviceProvider extends AbstractProvider ...@@ -110,11 +112,12 @@ public class NetconfDeviceProvider extends AbstractProvider
110 providerRegistry.unregister(this); 112 providerRegistry.unregister(this);
111 providerService = null; 113 providerService = null;
112 cfgService.unregisterConfigFactory(factory); 114 cfgService.unregisterConfigFactory(factory);
115 + controller.removeDeviceListener(innerNodeListener);
113 log.info("Stopped"); 116 log.info("Stopped");
114 } 117 }
115 118
116 public NetconfDeviceProvider() { 119 public NetconfDeviceProvider() {
117 - super(new ProviderId("netconf", "org.onosproject.netconf.provider.device")); 120 + super(new ProviderId(SCHEME_NAME, DEVICE_PROVIDER_PACKAGE));
118 } 121 }
119 122
120 @Override 123 @Override
...@@ -142,15 +145,18 @@ public class NetconfDeviceProvider extends AbstractProvider ...@@ -142,15 +145,18 @@ public class NetconfDeviceProvider extends AbstractProvider
142 145
143 private class InnerNetconfDeviceListener implements NetconfDeviceListener { 146 private class InnerNetconfDeviceListener implements NetconfDeviceListener {
144 147
148 + private static final String IPADDRESS = "ipaddress";
149 + protected static final String ISNULL = "NetconfDeviceInfo is null";
150 +
145 @Override 151 @Override
146 public void deviceAdded(NetconfDeviceInfo nodeId) { 152 public void deviceAdded(NetconfDeviceInfo nodeId) {
147 - Preconditions.checkNotNull(nodeId, ISNOTNULL); 153 + Preconditions.checkNotNull(nodeId, ISNULL);
148 DeviceId deviceId = nodeId.getDeviceId(); 154 DeviceId deviceId = nodeId.getDeviceId();
149 //Netconf configuration object 155 //Netconf configuration object
150 ChassisId cid = new ChassisId(); 156 ChassisId cid = new ChassisId();
151 String ipAddress = nodeId.ip().toString(); 157 String ipAddress = nodeId.ip().toString();
152 SparseAnnotations annotations = DefaultAnnotations.builder() 158 SparseAnnotations annotations = DefaultAnnotations.builder()
153 - .set("ipaddress", ipAddress).build(); 159 + .set(IPADDRESS, ipAddress).build();
154 DeviceDescription deviceDescription = new DefaultDeviceDescription( 160 DeviceDescription deviceDescription = new DefaultDeviceDescription(
155 deviceId.uri(), 161 deviceId.uri(),
156 Device.Type.SWITCH, 162 Device.Type.SWITCH,
...@@ -164,7 +170,7 @@ public class NetconfDeviceProvider extends AbstractProvider ...@@ -164,7 +170,7 @@ public class NetconfDeviceProvider extends AbstractProvider
164 170
165 @Override 171 @Override
166 public void deviceRemoved(NetconfDeviceInfo nodeId) { 172 public void deviceRemoved(NetconfDeviceInfo nodeId) {
167 - Preconditions.checkNotNull(nodeId, ISNOTNULL); 173 + Preconditions.checkNotNull(nodeId, ISNULL);
168 DeviceId deviceId = nodeId.getDeviceId(); 174 DeviceId deviceId = nodeId.getDeviceId();
169 providerService.deviceDisconnected(deviceId); 175 providerService.deviceDisconnected(deviceId);
170 176
...@@ -184,7 +190,7 @@ public class NetconfDeviceProvider extends AbstractProvider ...@@ -184,7 +190,7 @@ public class NetconfDeviceProvider extends AbstractProvider
184 addr.ip(), 190 addr.ip(),
185 addr.port())); 191 addr.port()));
186 } catch (IOException e) { 192 } catch (IOException e) {
187 - log.warn("Can't connect to NETCONF " + 193 + log.info("Can't connect to NETCONF " +
188 "device on {}:{}", 194 "device on {}:{}",
189 addr.ip(), 195 addr.ip(),
190 addr.port()); 196 addr.port());
......