-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Naive implementation of UpgradeProtocol #38
base: jtango-9-lts
Are you sure you want to change the base?
Changes from all commits
437e40a
e683e3e
dd454e6
74cc3c6
db59992
26adec8
d6920fd
09f1571
483b84b
08551dd
ce7e3ea
a4dc994
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,11 +42,15 @@ | |
import fr.esrf.TangoDs.Except; | ||
import fr.esrf.TangoDs.TangoConst; | ||
import org.omg.CORBA.Request; | ||
import org.tango.network.NetworkUtils; | ||
import org.tango.transport.DefaultTransport; | ||
import org.tango.transport.GsonTangoMessage; | ||
import org.tango.transport.TangoMessage; | ||
import org.tango.transport.Transport; | ||
import org.tango.utils.DevFailedUtils; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Vector; | ||
import java.io.IOException; | ||
import java.util.*; | ||
|
||
/** | ||
* Class Description: This class manage device connection for Tango objects. It | ||
|
@@ -80,6 +84,8 @@ public class DeviceProxy extends Connection implements ApiDefs { | |
|
||
private IDeviceProxyDAO deviceProxyDAO = null; | ||
|
||
private final GsonTangoMessage marshaller = new GsonTangoMessage(); | ||
|
||
static final private boolean check_idl = false; | ||
|
||
/** | ||
|
@@ -782,7 +788,26 @@ public void set_attribute_config(AttributeInfo[] attr) throws DevFailed { | |
deviceProxyDAO.set_attribute_info(this, attr); | ||
} | ||
|
||
private Transport transport = new DefaultTransport(); | ||
|
||
// ========================================================================== | ||
|
||
public double readAttributeDouble(String name) throws DevFailed { | ||
if (transport.isConnected()) { | ||
try { | ||
TangoMessage<Double> message = new TangoMessage<>("read", this.get_name(), name, TangoConst.Tango_DEV_DOUBLE, 0D); | ||
|
||
message = marshaller.unmarshal(transport.send(marshaller.marshal(message))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Debug log entry here? |
||
|
||
return message.value; | ||
} catch (IOException e) { | ||
throw DevFailedUtils.newDevFailed(e); | ||
} | ||
} else { | ||
return read_attribute(name).extractDouble(); | ||
} | ||
} | ||
|
||
/** | ||
* Read the attribute value for the specified device. | ||
* | ||
|
@@ -818,6 +843,21 @@ public DeviceAttribute[] read_attribute(String[] attnames) throws DevFailed { | |
return deviceProxyDAO.read_attribute(this, attnames); | ||
} | ||
|
||
//TODO extract and decorate | ||
public void writeAttribute(String name, double value) throws DevFailed { | ||
if (transport.isConnected()) { | ||
try { | ||
TangoMessage<Double> message = new TangoMessage<>("write", this.get_name(), name, TangoConst.Tango_DEV_DOUBLE, value); | ||
|
||
transport.send(marshaller.marshal(message)); | ||
} catch (IOException e) { | ||
throw DevFailedUtils.newDevFailed(e); | ||
} | ||
} | ||
DeviceAttribute deviceAttribute = new DeviceAttribute(name, value); | ||
write_attribute(deviceAttribute); | ||
} | ||
|
||
// ========================================================================== | ||
/** | ||
* Write the attribute value for the specified device. | ||
|
@@ -1825,6 +1865,26 @@ public int subscribe_event(int event, int max_size, boolean stateless) throws De | |
return deviceProxyDAO.subscribe_event(this, event, max_size, stateless); | ||
} | ||
|
||
public void upgradeProtocol(String targetProtocol) throws DevFailed { | ||
DeviceData argin = new DeviceData(); | ||
argin.insert(targetProtocol); | ||
|
||
DeviceData response = this.get_adm_dev().command_inout("UpgradeProtocol", argin); | ||
|
||
String[] array = response.extractStringArray(); | ||
|
||
try { | ||
String endpoint = Arrays.stream(array) | ||
.filter(NetworkUtils.getInstance()::checkEndpoint) | ||
.findFirst() | ||
.orElseThrow(() -> new IOException("No reachable connection points were found")); | ||
transport = TangoFactory.getSingleton().newTransport(targetProtocol); | ||
transport.connect(endpoint); | ||
} catch (IOException e) { | ||
throw DevFailedUtils.newDevFailed(e); | ||
} | ||
} | ||
|
||
// ========================================================================== | ||
// ========================================================================== | ||
public void setEventQueue(EventQueue eq) { | ||
|
@@ -2020,6 +2080,10 @@ private static void checkDuplication(String[] list, String orig) throws DevFaile | |
*/ | ||
//========================================================================== | ||
protected void finalize() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Finalize is deprecated in Java 9 and is discouraged even before. Should use |
||
try { | ||
transport.close(); | ||
} catch (IOException ignored) { | ||
} | ||
if (proxy_lock_cnt>0) { | ||
try { | ||
unlock(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package org.tango.network; | ||
|
||
import com.google.common.collect.Collections2; | ||
import com.google.common.collect.Iterables; | ||
import com.google.common.collect.Lists; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest remove Guava if possible. Using mix of Guava and Java 8 is confusing. Most Guava functions have analogues in Java 8. |
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.net.*; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Random; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* @author Igor Khokhriakov <[email protected]> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Short documentation required |
||
* @since 18.02.2020 | ||
*/ | ||
public class NetworkUtils { | ||
private static final NetworkUtils INSTANCE = new NetworkUtils(); | ||
private final Logger logger = LoggerFactory.getLogger(NetworkUtils.class); | ||
|
||
private NetworkUtils() { | ||
} | ||
|
||
public static NetworkUtils getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
public int getRandomPort() { | ||
//TODO check if available | ||
return new Random().ints(5000, 65535).findFirst().getAsInt(); | ||
} | ||
|
||
public List<String> getIp4Addresses() { | ||
Iterable<NetworkInterface> networkInterfaces = null; | ||
try { | ||
networkInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); | ||
} catch (SocketException e) { | ||
logger.error("Failed to get NICs due to " + e.getMessage(), e); | ||
return Collections.emptyList(); | ||
} | ||
|
||
java.util.function.Predicate<NetworkInterface> filter = networkInterface -> { | ||
try { | ||
return !networkInterface.isLoopback() && !networkInterface.isVirtual() && networkInterface.isUp(); | ||
} catch (SocketException e) { | ||
logger.warn("Ignoring NetworkInterface({}) due to an exception: {}", networkInterface.getName(), e); | ||
return false; | ||
} | ||
}; | ||
|
||
Function<InterfaceAddress, String> interfaceAddressToString = interfaceAddress -> interfaceAddress.getAddress().getHostAddress(); | ||
|
||
Iterable<NetworkInterface> filteredNICs = Iterables.filter(networkInterfaces, filter::test); | ||
|
||
List<String> result = Lists.newArrayList(); | ||
//TODO #17 | ||
for (NetworkInterface nic : filteredNICs) { | ||
result.addAll( | ||
Collections2.filter( | ||
nic.getInterfaceAddresses() | ||
.stream() | ||
.map(interfaceAddressToString::apply) | ||
.collect(Collectors.toList()), | ||
s -> s.split("\\.").length == 4) | ||
); | ||
} | ||
return result; | ||
} | ||
|
||
public boolean checkEndpoint(String endpoint) { | ||
logger.debug("Check endpoint: {}", endpoint); | ||
URI uri = null; | ||
try { | ||
uri = new URI(endpoint); | ||
} catch (URISyntaxException e) { | ||
logger.debug("Bad endpoint: " + endpoint, e); | ||
return false; | ||
} | ||
|
||
// Try to connect | ||
InetSocketAddress ip = new InetSocketAddress(uri.getHost(), uri.getPort()); | ||
try (Socket socket = new Socket()) { | ||
socket.connect(ip, 10); | ||
return true; | ||
} catch (IOException e) { | ||
logger.debug("Failed to connect to " + ip, e); | ||
return false; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package org.tango.transport; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* @author Igor Khokhriakov <[email protected]> | ||
* @since 21.02.2020 | ||
*/ | ||
public class DefaultTransport implements Transport { | ||
@Override | ||
public boolean isConnected() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void connect(String endpoint) throws IOException { | ||
throw new UnsupportedOperationException("This method is not supported in " + this.getClass()); | ||
} | ||
|
||
@Override | ||
public void disconnect(String endpoint) throws IOException { | ||
throw new UnsupportedOperationException("This method is not supported in " + this.getClass()); | ||
} | ||
|
||
@Override | ||
public byte[] send(byte[] data) throws IOException { | ||
throw new UnsupportedOperationException("This method is not supported in " + this.getClass()); | ||
} | ||
|
||
@Override | ||
public void close() throws IOException { | ||
throw new UnsupportedOperationException("This method is not supported in " + this.getClass()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.tango.transport; | ||
|
||
import com.google.gson.Gson; | ||
import com.google.gson.GsonBuilder; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
/** | ||
* @author Igor Khokhriakov <[email protected]> | ||
* @since 21.02.2020 | ||
*/ | ||
public class GsonTangoMessage implements TangoMessageMarshaller, TangoMessageUnmarshaller { | ||
private final Gson gson = new GsonBuilder() | ||
.serializeNulls() | ||
.create(); | ||
|
||
|
||
@Override | ||
public byte[] marshal(TangoMessage tangoMessage) { | ||
return gson.toJson(tangoMessage).getBytes(StandardCharsets.UTF_8); | ||
} | ||
|
||
@Override | ||
public TangoMessage unmarshal(InputStream stream) { | ||
return gson.fromJson(new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)), TangoMessage.class); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential bug here. If there are subsequent reads from the same stream, BufferedReader will read its buffer size and the next reader will start in the wrong place. If the stream is exhausted after read, it should be closed. |
||
} | ||
|
||
@Override | ||
public TangoMessage unmarshal(byte[] stream) { | ||
return unmarshal(new String(stream, StandardCharsets.UTF_8)); | ||
} | ||
|
||
@Override | ||
public TangoMessage unmarshal(String stream) { | ||
return gson.fromJson(stream, TangoMessage.class); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package org.tango.transport; | ||
|
||
import fr.esrf.TangoDs.TangoConst; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.ByteArrayInputStream; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* @author Igor Khokhriakov <[email protected]> | ||
* @since 21.02.2020 | ||
*/ | ||
public class StringTangoMessage implements TangoMessageMarshaller, TangoMessageUnmarshaller { | ||
public static final String PATTERN_STR = "(read|write|exec|response);([\\w\\W]+)/([\\w\\W]+);(\\d+):([\\w.]+)"; | ||
public static final Pattern PATTERN = Pattern.compile(PATTERN_STR); | ||
|
||
@Override | ||
public byte[] marshal(TangoMessage tangoMessage) { | ||
return toString(tangoMessage).getBytes(StandardCharsets.UTF_8); | ||
} | ||
|
||
@Override | ||
public TangoMessage unmarshal(InputStream stream) { | ||
BufferedReader br = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same as above |
||
return fromString(br.lines().collect(Collectors.joining(System.lineSeparator()))); | ||
} | ||
|
||
@Override | ||
public TangoMessage unmarshal(byte[] stream) { | ||
return unmarshal(new ByteArrayInputStream(stream)); | ||
} | ||
|
||
@Override | ||
public TangoMessage unmarshal(String stream) { | ||
return fromString(stream); | ||
} | ||
|
||
private String toString(TangoMessage message) { | ||
return String.format( | ||
"%s;%s/%s;%d:%s", message.action, message.device, message.target, message.dataType, String.valueOf(message.value) | ||
); | ||
} | ||
|
||
private TangoMessage fromString(String str) { | ||
Matcher matcher = PATTERN.matcher(str); | ||
|
||
if (matcher.matches()) { | ||
int dataType = Integer.parseInt(matcher.group(4)); | ||
return new TangoMessage(matcher.group(1), matcher.group(2), matcher.group(3), dataType, parseValue(dataType, matcher.group(5))); | ||
} else | ||
throw new IllegalArgumentException("Unrecognized message: " + str); | ||
} | ||
|
||
private Object parseValue(int dataType, String value) { | ||
switch (dataType) { | ||
case TangoConst | ||
.Tango_DEV_DOUBLE: | ||
return Double.valueOf(value); | ||
default: | ||
return value; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lacking documentation