pull/33/merge
Abdelaziz Said 2 years ago committed by GitHub
commit a0b9d04f08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,226 +17,266 @@ import com.beanit.asn1bean.ber.types.BerNull;
import com.beanit.iec61850bean.internal.mms.asn1.Data; import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.UtcTime; import com.beanit.iec61850bean.internal.mms.asn1.UtcTime;
import java.time.Instant; import java.time.Instant;
import java.util.Date; import java.util.Date;
public final class BdaTimestamp extends BasicDataAttribute { public final class BdaTimestamp extends BasicDataAttribute {
private volatile byte[] value; private volatile byte[] value;
public BdaTimestamp( public BdaTimestamp(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd); super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.TIMESTAMP; basicType = BdaType.TIMESTAMP;
setDefault(); setDefault();
} }
/** /**
* The SecondSinceEpoch shall be the interval in seconds continuously counted from the epoch * The SecondSinceEpoch shall be the interval in seconds continuously counted from the epoch
* 1970-01-01 00:00:00 UTC * 1970-01-01 00:00:00 UTC
*/ */
/** /**
* Returns the value as the number of seconds since epoch 1970-01-01 00:00:00 UTC * Returns the value as the number of seconds since epoch 1970-01-01 00:00:00 UTC
* *
* @return the number of seconds since epoch 1970-01-01 00:00:00 UTC * @return the number of seconds since epoch 1970-01-01 00:00:00 UTC
*/ */
private long getSecondsSinceEpoch() { private long getSecondsSinceEpoch() {
return ((0xffL & value[0]) << 24 return ((0xffL & value[0]) << 24
| (0xffL & value[1]) << 16 | (0xffL & value[1]) << 16
| (0xffL & value[2]) << 8 | (0xffL & value[2]) << 8
| (0xffL & value[3])); | (0xffL & value[3]));
} }
/** /**
* The attribute FractionOfSecond shall be the fraction of the current second when the value of * The attribute FractionOfSecond shall be the fraction of the current second when the value of
* the TimeStamp has been determined. The fraction of second shall be calculated as <code> * the TimeStamp has been determined. The fraction of second shall be calculated as <code>
* (SUM from I = 0 to 23 of bi*2**(I+1) s).</code> NOTE 1 The resolution is the smallest unit by * (SUM from I = 0 to 23 of bi*2**(I+1) s).</code> NOTE 1 The resolution is the smallest unit by
* which the time stamp is updated. The 24 bits of the integer provides 1 out of 16777216 counts * which the time stamp is updated. The 24 bits of the integer provides 1 out of 16777216 counts
* as the smallest unit; calculated by 1/2**24 which equals approximately 60 ns. * as the smallest unit; calculated by 1/2**24 which equals approximately 60 ns.
* *
* <p>NOTE 2 The resolution of a time stamp may be 1/2**1 (= 0,5 s) if only the first bit is used; * <p>NOTE 2 The resolution of a time stamp may be 1/2**1 (= 0,5 s) if only the first bit is used;
* or may be 1/2**2 (= 0,25 s) if the first two bits are used; or may be approximately 60 ns if * or may be 1/2**2 (= 0,25 s) if the first two bits are used; or may be approximately 60 ns if
* all 24 bits are used. The resolution provided by an IED is outside the scope of this standard. * all 24 bits are used. The resolution provided by an IED is outside the scope of this standard.
* *
* @return the fraction of seconds * @return the fraction of seconds
*/ */
private int getFractionOfSecond() { private int getFractionOfSecond() {
return ((0xff & value[4]) << 16 | (0xff & value[5]) << 8 | (0xff & value[6])); return ((0xff & value[4]) << 16 | (0xff & value[5]) << 8 | (0xff & value[6]));
} }
@Override public Date getDate() {
public void setValueFrom(BasicDataAttribute bda) { if (value == null || value.length == 0) {
byte[] srcValue = ((BdaTimestamp) bda).getValue(); return null;
if (value.length != srcValue.length) { }
value = new byte[srcValue.length]; long time =
} getSecondsSinceEpoch() * 1000L
System.arraycopy(srcValue, 0, value, 0, srcValue.length); + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5);
} return new Date(time);
}
public Instant getInstant() {
if (value == null || value.length == 0) { public void setDate(Date date) {
return null; if (value == null) {
} value = new byte[8];
long time = }
getSecondsSinceEpoch() * 1000L
+ (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5); int secondsSinceEpoch = (int) (date.getTime() / 1000L);
return Instant.ofEpochMilli(time); int fractionOfSecond = (int) ((date.getTime() % 1000L) / 1000.0 * (1 << 24));
}
// 0x8a = time accuracy of 10 and LeapSecondsKnown = true, ClockFailure
public void setInstant(Instant instant) { // = false, ClockNotSynchronized = false
setInstant(instant, true, false, false, 10); value =
} new byte[] {
(byte) ((secondsSinceEpoch >> 24) & 0xff),
public void setInstant( (byte) ((secondsSinceEpoch >> 16) & 0xff),
Instant instant, (byte) ((secondsSinceEpoch >> 8) & 0xff),
boolean leapSecondsKnown, (byte) (secondsSinceEpoch & 0xff),
boolean clockFailure, (byte) ((fractionOfSecond >> 16) & 0xff),
boolean clockNotSynchronized, (byte) ((fractionOfSecond >> 8) & 0xff),
int timeAccuracy) { (byte) (fractionOfSecond & 0xff),
if (value == null) { (byte) 0x8a
value = new byte[8]; };
} }
int secondsSinceEpoch = (int) (instant.toEpochMilli() / 1000L);
int fractionOfSecond = (int) ((instant.toEpochMilli() % 1000L) / 1000.0 * (1 << 24));
@Override
int timeQuality = timeAccuracy & 0x1f; public void setValueFrom(BasicDataAttribute bda) {
if (leapSecondsKnown) { byte[] srcValue = ((BdaTimestamp) bda).getValue();
timeQuality = timeQuality | 0x80; if (value.length != srcValue.length) {
} value = new byte[srcValue.length];
if (clockFailure) { }
timeQuality = timeQuality | 0x40; System.arraycopy(srcValue, 0, value, 0, srcValue.length);
} }
if (clockNotSynchronized) {
timeQuality = timeQuality | 0x20; public Instant getInstant() {
} if (value == null || value.length == 0) {
return null;
value = }
new byte[] { long time =
(byte) ((secondsSinceEpoch >> 24) & 0xff), getSecondsSinceEpoch() * 1000L
(byte) ((secondsSinceEpoch >> 16) & 0xff), + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5);
(byte) ((secondsSinceEpoch >> 8) & 0xff), return Instant.ofEpochMilli(time);
(byte) (secondsSinceEpoch & 0xff), }
(byte) ((fractionOfSecond >> 16) & 0xff),
(byte) ((fractionOfSecond >> 8) & 0xff), public void setInstant(Instant instant) {
(byte) (fractionOfSecond & 0xff), setInstant(instant, true, false, false, 10);
(byte) timeQuality }
};
} public void setInstant(
Instant instant,
public byte[] getValue() { boolean leapSecondsKnown,
return value; boolean clockFailure,
} boolean clockNotSynchronized,
int timeAccuracy) {
public void setValue(byte[] value) { if (value == null) {
if (value == null) { value = new byte[8];
this.value = new byte[8]; }
}
this.value = value; int secondsSinceEpoch = (int) (instant.toEpochMilli() / 1000L);
} int fractionOfSecond = (int) ((instant.toEpochMilli() % 1000L) / 1000.0 * (1 << 24));
/** int timeQuality = timeAccuracy & 0x1f;
* The value TRUE of the attribute LeapSecondsKnown shall indicate that the value for if (leapSecondsKnown) {
* SecondSinceEpoch takes into account all leap seconds occurred. If it is FALSE then the value timeQuality = timeQuality | 0x80;
* does not take into account the leap seconds that occurred before the initialization of the time }
* source of the device. if (clockFailure) {
* timeQuality = timeQuality | 0x40;
* @return TRUE of the attribute LeapSecondsKnown shall indicate that the value for }
* SecondSinceEpoch takes into account all leap seconds occurred if (clockNotSynchronized) {
*/ timeQuality = timeQuality | 0x20;
public boolean getLeapSecondsKnown() { }
return ((value[7] & 0x80) != 0);
} value =
new byte[]{
/** (byte) ((secondsSinceEpoch >> 24) & 0xff),
* The attribute clockFailure shall indicate that the time source of the sending device is (byte) ((secondsSinceEpoch >> 16) & 0xff),
* unreliable. The value of the TimeStamp shall be ignored. (byte) ((secondsSinceEpoch >> 8) & 0xff),
* (byte) (secondsSinceEpoch & 0xff),
* @return true if the time source of the sending device is unreliable (byte) ((fractionOfSecond >> 16) & 0xff),
*/ (byte) ((fractionOfSecond >> 8) & 0xff),
public boolean getClockFailure() { (byte) (fractionOfSecond & 0xff),
return ((value[7] & 0x40) != 0); (byte) timeQuality
} };
}
/**
* The attribute clockNotSynchronized shall indicate that the time source of the sending device is public byte[] getValue() {
* not synchronized with the external UTC time. return value;
* }
* @return true if the time source of the sending device is not synchronized
*/ public void setValue(byte[] value) {
public boolean getClockNotSynchronized() { if (value == null) {
return ((value[7] & 0x20) != 0); this.value = new byte[8];
} }
this.value = value;
/** }
* The attribute TimeAccuracy shall represent the time accuracy class of the time source of the
* sending device relative to the external UTC time. The timeAccuracy classes shall represent the /**
* number of significant bits in the FractionOfSecond * The value TRUE of the attribute LeapSecondsKnown shall indicate that the value for
* * SecondSinceEpoch takes into account all leap seconds occurred. If it is FALSE then the value
* <p>If the time is set via Java {@link Date} objects, the accuracy is 1 ms, that is a * does not take into account the leap seconds that occurred before the initialization of the time
* timeAccuracy value of 10. * source of the device.
* *
* @return the time accuracy * @return TRUE of the attribute LeapSecondsKnown shall indicate that the value for
*/ * SecondSinceEpoch takes into account all leap seconds occurred
public int getTimeAccuracy() { */
return ((value[7] & 0x1f)); public boolean getLeapSecondsKnown() {
} return ((value[7] & 0x80) != 0);
}
/** Sets Timestamp the empty byte array (indicating an invalid Timestamp) */
@Override /**
public void setDefault() { * The attribute clockFailure shall indicate that the time source of the sending device is
value = new byte[8]; * unreliable. The value of the TimeStamp shall be ignored.
} *
* @return true if the time source of the sending device is unreliable
/** Sets Timestamp to current time */ */
public void setCurrentTime() { public boolean getClockFailure() {
setInstant(Instant.now()); return ((value[7] & 0x40) != 0);
} }
@Override /**
public BdaTimestamp copy() { * The attribute clockNotSynchronized shall indicate that the time source of the sending device is
BdaTimestamp copy = new BdaTimestamp(objectReference, fc, sAddr, dchg, dupd); * not synchronized with the external UTC time.
byte[] valueCopy = new byte[value.length]; *
System.arraycopy(value, 0, valueCopy, 0, value.length); * @return true if the time source of the sending device is not synchronized
copy.setValue(valueCopy); */
if (mirror == null) { public boolean getClockNotSynchronized() {
copy.mirror = this; return ((value[7] & 0x20) != 0);
} else { }
copy.mirror = mirror;
} /**
return copy; * The attribute TimeAccuracy shall represent the time accuracy class of the time source of the
} * sending device relative to the external UTC time. The timeAccuracy classes shall represent the
* number of significant bits in the FractionOfSecond
@Override *
Data getMmsDataObj() { * <p>If the time is set via Java {@link Date} objects, the accuracy is 1 ms, that is a
Data data = new Data(); * timeAccuracy value of 10.
data.setUtcTime(new UtcTime(value)); *
return data; * @return the time accuracy
} */
public int getTimeAccuracy() {
@Override return ((value[7] & 0x1f));
void setValueFromMmsDataObj(Data data) throws ServiceError { }
if (data.getUtcTime() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: utc_time/timestamp"); /**
} * Sets Timestamp the empty byte array (indicating an invalid Timestamp)
value = data.getUtcTime().value; */
} @Override
public void setDefault() {
@Override value = new byte[8];
TypeDescription getMmsTypeSpec() { }
TypeDescription typeDescription = new TypeDescription();
typeDescription.setUtcTime(new BerNull()); /**
return typeDescription; * Sets Timestamp to current time
} */
public void setCurrentTime() {
@Override setInstant(Instant.now());
public String toString() { }
return getReference().toString() + ": " + getInstant();
} @Override
public BdaTimestamp copy() {
@Override BdaTimestamp copy = new BdaTimestamp(objectReference, fc, sAddr, dchg, dupd);
public String getValueString() { byte[] valueCopy = new byte[value.length];
return getInstant().toString(); System.arraycopy(value, 0, valueCopy, 0, value.length);
} copy.setValue(valueCopy);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setUtcTime(new UtcTime(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getUtcTime() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: utc_time/timestamp");
}
value = data.getUtcTime().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setUtcTime(new BerNull());
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + getInstant();
}
@Override
public String getValueString() {
return getInstant().toString();
}
} }

@ -0,0 +1,148 @@
package com.beanit.iec61850bean;
import java.util.Objects;
public class ConnectionParam {
private String iedName;
private String IP;
private String IP_SUBNET;
private String OSI_AP_Title;
private String OSI_AE_Qualifier;
private String OSI_PSEL;
private String OSI_SSEL;
private String OSI_TSEL;
private String IP_GATEWAY;
private String S_Profile;
private String MAC_Address;
public String getIedName() {
return iedName;
}
public void setIedName(String iedName) {
this.iedName = iedName;
}
public String getIP() {
return IP;
}
public void setIP(String IP) {
this.IP = IP;
}
public String getIP_SUBNET() {
return IP_SUBNET;
}
public void setIP_SUBNET(String IP_SUBNET) {
this.IP_SUBNET = IP_SUBNET;
}
public String getOSI_AP_Title() {
return OSI_AP_Title;
}
public void setOSI_AP_Title(String OSI_AP_Title) {
this.OSI_AP_Title = OSI_AP_Title;
}
public String getOSI_AE_Qualifier() {
return OSI_AE_Qualifier;
}
public void setOSI_AE_Qualifier(String OSI_AE_Qualifier) {
this.OSI_AE_Qualifier = OSI_AE_Qualifier;
}
public String getOSI_PSEL() {
return OSI_PSEL;
}
public void setOSI_PSEL(String OSI_PSEL) {
this.OSI_PSEL = OSI_PSEL;
}
public String getOSI_SSEL() {
return OSI_SSEL;
}
public void setOSI_SSEL(String OSI_SSEL) {
this.OSI_SSEL = OSI_SSEL;
}
public String getOSI_TSEL() {
return OSI_TSEL;
}
public void setOSI_TSEL(String OSI_TSEL) {
this.OSI_TSEL = OSI_TSEL;
}
public String getIP_GATEWAY() {
return IP_GATEWAY;
}
public void setIP_GATEWAY(String IP_GATEWAY) {
this.IP_GATEWAY = IP_GATEWAY;
}
public String getS_Profile() {
return S_Profile;
}
public void setS_Profile(String s_Profile) {
S_Profile = s_Profile;
}
public String getMAC_Address() {
return MAC_Address;
}
public void setMAC_Address(String MAC_Address) {
this.MAC_Address = MAC_Address;
}
@Override
public String toString() {
return "iedName = " + iedName + '\n' +
"IP = " + IP + '\n' +
"IP_SUBNET = " + IP_SUBNET + '\n' +
"OSI_AP_Title = " + OSI_AP_Title + '\n' +
"OSI_AE_Qualifier = " + OSI_AE_Qualifier + '\n' +
"OSI_PSEL = " + OSI_PSEL + '\n' +
"OSI_SSEL = " + OSI_SSEL + '\n' +
"OSI_TSEL = " + OSI_TSEL + '\n' +
"IP_GATEWAY = " + IP_GATEWAY + '\n' +
"S_Profile = " + S_Profile + '\n' +
"MAC-Address = " + MAC_Address
;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConnectionParam that = (ConnectionParam) o;
return iedName.equals(that.iedName) &&
IP.equals(that.IP) &&
Objects.equals(IP_SUBNET, that.IP_SUBNET) &&
Objects.equals(OSI_AP_Title, that.OSI_AP_Title) &&
Objects.equals(OSI_AE_Qualifier, that.OSI_AE_Qualifier) &&
Objects.equals(OSI_PSEL, that.OSI_PSEL) &&
Objects.equals(OSI_SSEL, that.OSI_SSEL) &&
Objects.equals(OSI_TSEL, that.OSI_TSEL) &&
Objects.equals(IP_GATEWAY, that.IP_GATEWAY) &&
Objects.equals(S_Profile, that.S_Profile) &&
Objects.equals(MAC_Address, that.MAC_Address);
}
@Override
public int hashCode() {
return Objects.hash(iedName, IP, IP_SUBNET, OSI_AP_Title, OSI_AE_Qualifier, OSI_PSEL, OSI_SSEL,
OSI_TSEL, IP_GATEWAY, S_Profile, MAC_Address);
}
}

@ -14,6 +14,7 @@
package com.beanit.iec61850bean; package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.Data; import com.beanit.iec61850bean.internal.mms.asn1.Data;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -30,66 +31,89 @@ import java.util.List;
*/ */
public class FcDataObject extends FcModelNode { public class FcDataObject extends FcModelNode {
public FcDataObject(ObjectReference objectReference, Fc fc, List<FcModelNode> children) { private final List<FcModelNode> fcModelNodes;
private String doType;
private String cdc;
this.children = new LinkedHashMap<>((int) ((children.size() / 0.75) + 1));
this.objectReference = objectReference; public FcDataObject(ObjectReference objectReference, Fc fc, List<FcModelNode> children) {
for (ModelNode child : children) { this.fcModelNodes = children;
this.children.put(child.getReference().getName(), child); super.setDataAttributes(children);
child.setParent(this); this.children = new LinkedHashMap<>((int) ((children.size() / 0.75) + 1));
} this.objectReference = objectReference;
this.fc = fc;
} for (ModelNode child : children) {
this.children.put(child.getReference().getName(), child);
@Override child.setParent(this);
public FcDataObject copy() { }
List<FcModelNode> childCopies = new ArrayList<>(children.size()); this.fc = fc;
for (ModelNode childNode : children.values()) {
childCopies.add((FcModelNode) childNode.copy());
} }
return new FcDataObject(objectReference, fc, childCopies);
} @Override
public FcDataObject copy() {
@Override List<FcModelNode> childCopies = new ArrayList<>(children.size());
Data getMmsDataObj() { for (ModelNode childNode : children.values()) {
Data.Structure dataStructure = new Data.Structure(); childCopies.add((FcModelNode) childNode.copy());
List<Data> seq = dataStructure.getData(); }
return new FcDataObject(objectReference, fc, childCopies);
for (ModelNode modelNode : getChildren()) {
Data child = modelNode.getMmsDataObj();
if (child == null) {
throw new IllegalArgumentException(
"Unable to convert Child: " + modelNode.objectReference + " to MMS Data Object.");
}
seq.add(child);
} }
if (seq.size() == 0) {
throw new IllegalArgumentException( @Override
"Converting ModelNode: " Data getMmsDataObj() {
+ objectReference Data.Structure dataStructure = new Data.Structure();
+ " to MMS Data Object resulted in Sequence of size zero."); List<Data> seq = dataStructure.getData();
for (ModelNode modelNode : getChildren()) {
Data child = modelNode.getMmsDataObj();
if (child == null) {
throw new IllegalArgumentException(
"Unable to convert Child: " + modelNode.objectReference + " to MMS Data Object.");
}
seq.add(child);
}
if (seq.size() == 0) {
throw new IllegalArgumentException(
"Converting ModelNode: "
+ objectReference
+ " to MMS Data Object resulted in Sequence of size zero.");
}
Data data = new Data();
data.setStructure(dataStructure);
return data;
} }
Data data = new Data(); @Override
data.setStructure(dataStructure); void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getStructure() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: structure");
}
if (data.getStructure().getData().size() != children.size()) {
throw new ServiceError(
ServiceError.TYPE_CONFLICT,
"expected type: structure with " + children.size() + " elements");
}
Iterator<Data> iterator = data.getStructure().getData().iterator();
for (ModelNode child : children.values()) {
child.setValueFromMmsDataObj(iterator.next());
}
}
return data; public String getDoType() {
} return doType;
}
@Override public void setDoType(String doType) {
void setValueFromMmsDataObj(Data data) throws ServiceError { this.doType = doType;
if (data.getStructure() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: structure");
} }
if (data.getStructure().getData().size() != children.size()) {
throw new ServiceError( public String getCdc() {
ServiceError.TYPE_CONFLICT, return cdc;
"expected type: structure with " + children.size() + " elements");
} }
Iterator<Data> iterator = data.getStructure().getData().iterator(); public void setCdc(String cdc) {
for (ModelNode child : children.values()) { this.cdc = cdc;
child.setValueFromMmsDataObj(iterator.next());
} }
}
} }

@ -13,240 +13,373 @@
*/ */
package com.beanit.iec61850bean; package com.beanit.iec61850bean;
import static java.nio.charset.StandardCharsets.UTF_8; import com.beanit.iec61850bean.internal.mms.asn1.*;
import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccess;
import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection;
import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection.SelectAccess; import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection.SelectAccess;
import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection.SelectAccess.Component; import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection.SelectAccess.Component;
import com.beanit.iec61850bean.internal.mms.asn1.BasicIdentifier;
import com.beanit.iec61850bean.internal.mms.asn1.Identifier;
import com.beanit.iec61850bean.internal.mms.asn1.ObjectName;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned32;
import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs;
import com.beanit.iec61850bean.internal.mms.asn1.VariableSpecification;
import java.util.List; import java.util.List;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import static java.nio.charset.StandardCharsets.UTF_8;
public abstract class FcModelNode extends ModelNode { public abstract class FcModelNode extends ModelNode {
Fc fc; Fc fc;
private VariableDefs.SEQUENCE variableDef = null; private VariableDefs.SEQUENCE variableDef = null;
private ServerAssociation selected = null; private ServerAssociation selected = null;
private TimerTask task = null; private TimerTask task = null;
private String daType;
private BdaType basicType = null;
private String sAddr;
private String daiVal;
private boolean dchg;
private boolean dupd;
private boolean qchg;
private String bType;
private List<FcModelNode> bdas;
private short valueShort;
private byte[] valueBytes;
private byte valueByte;
private boolean valueBoolean;
private int valueInt;
private long valueLong;
public Fc getFc() {
return fc;
}
public Fc getFc() { boolean select(ServerAssociation association, Timer timer) {
return fc; if (selected != null) {
} if (selected != association) {
return false;
}
} else {
selected = association;
association.selects.add(this);
}
boolean select(ServerAssociation association, Timer timer) { ModelNode sboTimeoutNode =
if (selected != null) { association.serverModel.findModelNode(objectReference, Fc.CF).getChild("sboTimeout");
if (selected != association) {
return false;
}
} else {
selected = association;
association.selects.add(this);
}
ModelNode sboTimeoutNode = if (sboTimeoutNode == null) {
association.serverModel.findModelNode(objectReference, Fc.CF).getChild("sboTimeout"); return true;
}
if (sboTimeoutNode == null) { long sboTimeout = ((BdaInt32U) sboTimeoutNode).getValue();
return true;
}
long sboTimeout = ((BdaInt32U) sboTimeoutNode).getValue(); if (sboTimeout == 0) {
return true;
}
if (sboTimeout == 0) { class SelectResetTask extends TimerTask {
return true; ServerAssociation association;
}
SelectResetTask(ServerAssociation association) {
this.association = association;
}
@Override
public void run() {
synchronized (association.serverModel) {
if (task == this) {
task = null;
deselectAndRemove(association);
}
}
}
}
class SelectResetTask extends TimerTask { if (task != null) {
ServerAssociation association; task.cancel();
}
SelectResetTask(ServerAssociation association) { task = new SelectResetTask(association);
this.association = association; timer.schedule(task, sboTimeout);
}
return true;
}
@Override void deselectAndRemove(ServerAssociation association) {
public void run() { selected = null;
synchronized (association.serverModel) { if (task != null) {
if (task == this) { task.cancel();
task = null; task = null;
deselectAndRemove(association);
}
} }
} association.selects.remove(this);
} }
if (task != null) { void deselect() {
task.cancel(); selected = null;
if (task != null) {
task.cancel();
task = null;
}
} }
task = new SelectResetTask(association); boolean isSelected() {
timer.schedule(task, sboTimeout); return selected != null;
return true;
}
void deselectAndRemove(ServerAssociation association) {
selected = null;
if (task != null) {
task.cancel();
task = null;
} }
association.selects.remove(this);
}
void deselect() { boolean isSelectedBy(ServerAssociation association) {
selected = null; return selected == association;
if (task != null) {
task.cancel();
task = null;
} }
}
boolean isSelected() { VariableDefs.SEQUENCE getMmsVariableDef() {
return selected != null;
} if (variableDef != null) {
return variableDef;
}
boolean isSelectedBy(ServerAssociation association) { AlternateAccess alternateAccess = null;
return selected == association;
}
VariableDefs.SEQUENCE getMmsVariableDef() { StringBuilder preArrayIndexItemId = new StringBuilder(objectReference.get(1));
preArrayIndexItemId.append("$");
preArrayIndexItemId.append(fc);
if (variableDef != null) { int arrayIndexPosition = objectReference.getArrayIndexPosition();
return variableDef; if (arrayIndexPosition != -1) {
}
AlternateAccess alternateAccess = null; for (int i = 2; i < arrayIndexPosition; i++) {
preArrayIndexItemId.append("$");
preArrayIndexItemId.append(objectReference.get(i));
}
StringBuilder preArrayIndexItemId = new StringBuilder(objectReference.get(1)); alternateAccess = new AlternateAccess();
preArrayIndexItemId.append("$"); List<AlternateAccess.CHOICE> subSeqOfAlternateAccess = alternateAccess.getCHOICE();
preArrayIndexItemId.append(fc); Unsigned32 indexBerInteger =
new Unsigned32(Integer.parseInt(objectReference.get(arrayIndexPosition)));
int arrayIndexPosition = objectReference.getArrayIndexPosition(); if (arrayIndexPosition < (objectReference.size() - 1)) {
if (arrayIndexPosition != -1) { // this reference points to a sub-node of an array element
for (int i = 2; i < arrayIndexPosition; i++) { StringBuilder postArrayIndexItemId =
preArrayIndexItemId.append("$"); new StringBuilder(objectReference.get(arrayIndexPosition + 1));
preArrayIndexItemId.append(objectReference.get(i));
} for (int i = (arrayIndexPosition + 2); i < objectReference.size(); i++) {
postArrayIndexItemId.append("$");
postArrayIndexItemId.append(objectReference.get(i));
}
BasicIdentifier subIndexReference =
new BasicIdentifier(postArrayIndexItemId.toString().getBytes(UTF_8));
AlternateAccessSelection.SelectAccess subIndexReferenceSelectAccess =
new AlternateAccessSelection.SelectAccess();
Component component = new Component();
component.setBasic(subIndexReference);
subIndexReferenceSelectAccess.setComponent(component);
AlternateAccessSelection subIndexReferenceAlternateAccessSelection =
new AlternateAccessSelection();
subIndexReferenceAlternateAccessSelection.setSelectAccess(subIndexReferenceSelectAccess);
AlternateAccess.CHOICE subIndexReferenceAlternateAccessSubChoice =
new AlternateAccess.CHOICE();
subIndexReferenceAlternateAccessSubChoice.setUnnamed(
subIndexReferenceAlternateAccessSelection);
AlternateAccess subIndexReferenceAlternateAccess = new AlternateAccess();
List<AlternateAccess.CHOICE> subIndexReferenceAlternateAccessSubSeqOf =
subIndexReferenceAlternateAccess.getCHOICE();
subIndexReferenceAlternateAccessSubSeqOf.add(subIndexReferenceAlternateAccessSubChoice);
// set array index:
AlternateAccessSelection.SelectAlternateAccess.AccessSelection indexAccessSelectionChoice =
new AlternateAccessSelection.SelectAlternateAccess.AccessSelection();
indexAccessSelectionChoice.setIndex(indexBerInteger);
AlternateAccessSelection.SelectAlternateAccess indexAndLowerReferenceSelectAlternateAccess =
new AlternateAccessSelection.SelectAlternateAccess();
indexAndLowerReferenceSelectAlternateAccess.setAccessSelection(indexAccessSelectionChoice);
indexAndLowerReferenceSelectAlternateAccess.setAlternateAccess(
subIndexReferenceAlternateAccess);
AlternateAccessSelection indexAndLowerReferenceAlternateAccessSelection =
new AlternateAccessSelection();
indexAndLowerReferenceAlternateAccessSelection.setSelectAlternateAccess(
indexAndLowerReferenceSelectAlternateAccess);
AlternateAccess.CHOICE indexAndLowerReferenceAlternateAccessChoice =
new AlternateAccess.CHOICE();
indexAndLowerReferenceAlternateAccessChoice.setUnnamed(
indexAndLowerReferenceAlternateAccessSelection);
subSeqOfAlternateAccess.add(indexAndLowerReferenceAlternateAccessChoice);
} else {
SelectAccess selectAccess = new SelectAccess();
selectAccess.setIndex(indexBerInteger);
AlternateAccessSelection alternateAccessSelection = new AlternateAccessSelection();
alternateAccessSelection.setSelectAccess(selectAccess);
AlternateAccess.CHOICE alternateAccessChoice = new AlternateAccess.CHOICE();
alternateAccessChoice.setUnnamed(alternateAccessSelection);
subSeqOfAlternateAccess.add(alternateAccessChoice);
}
alternateAccess = new AlternateAccess(); } else {
List<AlternateAccess.CHOICE> subSeqOfAlternateAccess = alternateAccess.getCHOICE();
Unsigned32 indexBerInteger =
new Unsigned32(Integer.parseInt(objectReference.get(arrayIndexPosition)));
if (arrayIndexPosition < (objectReference.size() - 1)) { for (int i = 2; i < objectReference.size(); i++) {
// this reference points to a sub-node of an array element preArrayIndexItemId.append("$");
preArrayIndexItemId.append(objectReference.get(i));
}
}
ObjectName.DomainSpecific domainSpecificObjectName = new ObjectName.DomainSpecific();
domainSpecificObjectName.setDomainID(new Identifier(objectReference.get(0).getBytes(UTF_8)));
domainSpecificObjectName.setItemID(
new Identifier(preArrayIndexItemId.toString().getBytes(UTF_8)));
ObjectName objectName = new ObjectName();
objectName.setDomainSpecific(domainSpecificObjectName);
StringBuilder postArrayIndexItemId = VariableSpecification varSpec = new VariableSpecification();
new StringBuilder(objectReference.get(arrayIndexPosition + 1)); varSpec.setName(objectName);
variableDef = new VariableDefs.SEQUENCE();
variableDef.setAlternateAccess(alternateAccess);
variableDef.setVariableSpecification(varSpec);
return variableDef;
}
for (int i = (arrayIndexPosition + 2); i < objectReference.size(); i++) { @Override
postArrayIndexItemId.append("$"); public String toString() {
postArrayIndexItemId.append(objectReference.get(i)); StringBuilder sb = new StringBuilder();
sb.append(getReference().toString()).append(" [").append(fc).append("]");
for (ModelNode childNode : children.values()) {
sb.append("\n");
sb.append(childNode.toString());
} }
return sb.toString();
}
BasicIdentifier subIndexReference = public String getDaType() {
new BasicIdentifier(postArrayIndexItemId.toString().getBytes(UTF_8)); return daType;
}
AlternateAccessSelection.SelectAccess subIndexReferenceSelectAccess = public void setDaType(String daType) {
new AlternateAccessSelection.SelectAccess(); this.daType = daType;
Component component = new Component(); }
component.setBasic(subIndexReference);
subIndexReferenceSelectAccess.setComponent(component); public BdaType getBasicType() {
return basicType;
}
public void setBasicType(BdaType basicType) {
this.basicType = basicType;
}
public String getsAddr() {
return sAddr;
}
public void setsAddr(String sAddr) {
this.sAddr = sAddr;
}
public String getDaiVal() {
return daiVal;
}
public void setDaiVal(String daiVal) {
this.daiVal = daiVal;
}
AlternateAccessSelection subIndexReferenceAlternateAccessSelection = public boolean isDchg() {
new AlternateAccessSelection(); return dchg;
subIndexReferenceAlternateAccessSelection.setSelectAccess(subIndexReferenceSelectAccess); }
AlternateAccess.CHOICE subIndexReferenceAlternateAccessSubChoice = public void setDchg(boolean dchg) {
new AlternateAccess.CHOICE(); this.dchg = dchg;
subIndexReferenceAlternateAccessSubChoice.setUnnamed( }
subIndexReferenceAlternateAccessSelection);
AlternateAccess subIndexReferenceAlternateAccess = new AlternateAccess(); public boolean isDupd() {
return dupd;
}
List<AlternateAccess.CHOICE> subIndexReferenceAlternateAccessSubSeqOf = public void setDupd(boolean dupd) {
subIndexReferenceAlternateAccess.getCHOICE(); this.dupd = dupd;
subIndexReferenceAlternateAccessSubSeqOf.add(subIndexReferenceAlternateAccessSubChoice); }
// set array index: public boolean isQchg() {
return qchg;
}
AlternateAccessSelection.SelectAlternateAccess.AccessSelection indexAccessSelectionChoice = public void setQchg(boolean qchg) {
new AlternateAccessSelection.SelectAlternateAccess.AccessSelection(); this.qchg = qchg;
indexAccessSelectionChoice.setIndex(indexBerInteger); }
AlternateAccessSelection.SelectAlternateAccess indexAndLowerReferenceSelectAlternateAccess = public String getbType() {
new AlternateAccessSelection.SelectAlternateAccess(); return bType;
indexAndLowerReferenceSelectAlternateAccess.setAccessSelection(indexAccessSelectionChoice); }
indexAndLowerReferenceSelectAlternateAccess.setAlternateAccess(
subIndexReferenceAlternateAccess);
AlternateAccessSelection indexAndLowerReferenceAlternateAccessSelection = public void setbType(String bType) {
new AlternateAccessSelection(); this.bType = bType;
indexAndLowerReferenceAlternateAccessSelection.setSelectAlternateAccess( }
indexAndLowerReferenceSelectAlternateAccess);
AlternateAccess.CHOICE indexAndLowerReferenceAlternateAccessChoice = public List<FcModelNode> getDataAttributes() {
new AlternateAccess.CHOICE(); return bdas;
indexAndLowerReferenceAlternateAccessChoice.setUnnamed( }
indexAndLowerReferenceAlternateAccessSelection);
subSeqOfAlternateAccess.add(indexAndLowerReferenceAlternateAccessChoice); public FcModelNode setDataAttributes(List<FcModelNode> bdas) {
this.bdas = bdas;
return this;
}
} else { public short getValueShort() {
SelectAccess selectAccess = new SelectAccess(); return valueShort;
selectAccess.setIndex(indexBerInteger); }
AlternateAccessSelection alternateAccessSelection = new AlternateAccessSelection(); public void setValueShort(short valueShort) {
alternateAccessSelection.setSelectAccess(selectAccess); this.valueShort = valueShort;
}
AlternateAccess.CHOICE alternateAccessChoice = new AlternateAccess.CHOICE(); public byte[] getValueBytes() {
alternateAccessChoice.setUnnamed(alternateAccessSelection); return valueBytes;
}
subSeqOfAlternateAccess.add(alternateAccessChoice); public void setValueBytes(byte[] valueBytes) {
} this.valueBytes = valueBytes;
}
} else { public byte getValueByte() {
return valueByte;
}
for (int i = 2; i < objectReference.size(); i++) { public void setValueByte(byte valueByte) {
preArrayIndexItemId.append("$"); this.valueByte = valueByte;
preArrayIndexItemId.append(objectReference.get(i));
}
} }
ObjectName.DomainSpecific domainSpecificObjectName = new ObjectName.DomainSpecific(); public boolean isValueBoolean() {
domainSpecificObjectName.setDomainID(new Identifier(objectReference.get(0).getBytes(UTF_8))); return valueBoolean;
domainSpecificObjectName.setItemID( }
new Identifier(preArrayIndexItemId.toString().getBytes(UTF_8)));
ObjectName objectName = new ObjectName(); public void setValueBoolean(boolean valueBoolean) {
objectName.setDomainSpecific(domainSpecificObjectName); this.valueBoolean = valueBoolean;
}
VariableSpecification varSpec = new VariableSpecification(); public int getValueInt() {
varSpec.setName(objectName); return valueInt;
}
variableDef = new VariableDefs.SEQUENCE(); public void setValueInt(int valueInt) {
variableDef.setAlternateAccess(alternateAccess); this.valueInt = valueInt;
variableDef.setVariableSpecification(varSpec); }
return variableDef; public long getValueLong() {
} return valueLong;
}
@Override public void setValueLong(long valueLong) {
public String toString() { this.valueLong = valueLong;
StringBuilder sb = new StringBuilder();
sb.append(getReference().toString()).append(" [").append(fc).append("]");
for (ModelNode childNode : children.values()) {
sb.append("\n");
sb.append(childNode.toString());
} }
return sb.toString();
}
} }

@ -19,7 +19,11 @@ import java.util.List;
public final class LogicalDevice extends ModelNode { public final class LogicalDevice extends ModelNode {
private final List<LogicalNode> logicalNodes;
private String ldInst;
public LogicalDevice(ObjectReference objectReference, List<LogicalNode> logicalNodes) { public LogicalDevice(ObjectReference objectReference, List<LogicalNode> logicalNodes) {
this.logicalNodes = logicalNodes;
children = new LinkedHashMap<>((int) ((logicalNodes.size() / 0.75) + 1)); children = new LinkedHashMap<>((int) ((logicalNodes.size() / 0.75) + 1));
this.objectReference = objectReference; this.objectReference = objectReference;
for (LogicalNode logicalNode : logicalNodes) { for (LogicalNode logicalNode : logicalNodes) {
@ -36,4 +40,16 @@ public final class LogicalDevice extends ModelNode {
} }
return new LogicalDevice(objectReference, childCopies); return new LogicalDevice(objectReference, childCopies);
} }
public List<LogicalNode> getLogicalNodes() {
return logicalNodes;
}
public String getLdInst() {
return ldInst;
}
public void setLdInst(String ldInst) {
this.ldInst = ldInst;
}
} }

@ -28,7 +28,14 @@ public final class LogicalNode extends ModelNode {
private final Map<String, Urcb> urcbs = new HashMap<>(); private final Map<String, Urcb> urcbs = new HashMap<>();
private final Map<String, Brcb> brcbs = new HashMap<>(); private final Map<String, Brcb> brcbs = new HashMap<>();
private final List<FcDataObject> dataObjects;
private String prefix;
private String lnClass;
private String lnInst;
private String lnType;
public LogicalNode(ObjectReference objectReference, List<FcDataObject> fcDataObjects) { public LogicalNode(ObjectReference objectReference, List<FcDataObject> fcDataObjects) {
this.dataObjects = fcDataObjects;
children = new LinkedHashMap<>(); children = new LinkedHashMap<>();
for (Fc fc : Fc.values()) { for (Fc fc : Fc.values()) {
this.fcDataObjects.put(fc, new LinkedHashMap<String, FcDataObject>()); this.fcDataObjects.put(fc, new LinkedHashMap<String, FcDataObject>());
@ -59,8 +66,7 @@ public final class LogicalNode extends ModelNode {
dataObjectsCopy.add((FcDataObject) obj.copy()); dataObjectsCopy.add((FcDataObject) obj.copy());
} }
LogicalNode copy = new LogicalNode(objectReference, dataObjectsCopy); return new LogicalNode(objectReference, dataObjectsCopy);
return copy;
} }
public List<FcDataObject> getChildren(Fc fc) { public List<FcDataObject> getChildren(Fc fc) {
@ -134,4 +140,36 @@ public final class LogicalNode extends ModelNode {
} }
return sb.toString(); return sb.toString();
} }
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getLnClass() {
return lnClass;
}
public void setLnClass(String lnClass) {
this.lnClass = lnClass;
}
public String getLnInst() {
return lnInst;
}
public void setLnInst(String lnInst) {
this.lnInst = lnInst;
}
public String getLnType() {
return lnType;
}
public void setLnType(String lnType) {
this.lnType = lnType;
}
} }

File diff suppressed because it is too large Load Diff

@ -17,384 +17,488 @@ import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection;
import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; import com.beanit.iec61850bean.internal.mms.asn1.ObjectName;
import com.beanit.iec61850bean.internal.mms.asn1.ObjectName.DomainSpecific; import com.beanit.iec61850bean.internal.mms.asn1.ObjectName.DomainSpecific;
import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs; import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs;
import java.util.ArrayList;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public final class ServerModel extends ModelNode { public final class ServerModel extends ModelNode {
private final Map<String, DataSet> dataSets = new LinkedHashMap<>(); private final Map<String, DataSet> dataSets = new LinkedHashMap<>();
private final Map<String, Urcb> urcbs = new HashMap<>();
private final Map<String, Brcb> brcbs = new HashMap<>();
private ConnectionParam connectionParam;
private String iedName;
private String iedManufacturer;
private List<String> ldsInsts;
private List<String> ldsRefs;
private List<String> lnsRefs;
private Map<String, Set<String>> lns;
private HashSet<String> lnS;
private Map<String, String> descriptions;
private Map<String,String> dAIDescriptions;
private Map<String, String> dos;
private List<LogicalDevice> logicalDevices;
public ServerModel(List<LogicalDevice> logicalDevices, Collection<DataSet> dataSets) {
children = new LinkedHashMap<>();
objectReference = null;
for (LogicalDevice logicalDevice : logicalDevices) {
children.put(logicalDevice.getReference().getName(), logicalDevice);
logicalDevice.setParent(this);
}
if (dataSets != null) {
addDataSets(dataSets);
}
for (LogicalDevice ld : logicalDevices) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcbs.put(urcb.getReference().toString(), urcb);
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcbs.put(brcb.getReference().toString(), brcb);
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
}
}
private final Map<String, Urcb> urcbs = new HashMap<>(); @Override
private final Map<String, Brcb> brcbs = new HashMap<>(); public ServerModel copy() {
List<LogicalDevice> childCopies = new ArrayList<>(children.size());
for (ModelNode childNode : children.values()) {
childCopies.add((LogicalDevice) childNode.copy());
}
List<DataSet> dataSetCopies = new ArrayList<>(dataSets.size());
for (DataSet dataSet : dataSets.values()) {
dataSetCopies.add(dataSet);
}
return new ServerModel(childCopies, dataSetCopies);
}
/**
* Get the data set with the given reference. Return null if none is found.
*
* @param reference the reference of the requested data set.
* @return the data set with the given reference.
*/
public DataSet getDataSet(String reference) {
return dataSets.get(reference);
}
void addDataSet(DataSet dataSet) {
dataSets.put(dataSet.getReferenceStr().replace('$', '.'), dataSet);
for (ModelNode ld : children.values()) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
}
}
void addDataSets(Collection<DataSet> dataSets) {
for (DataSet dataSet : dataSets) {
addDataSet(dataSet);
}
for (ModelNode ld : children.values()) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
}
}
public ServerModel(List<LogicalDevice> logicalDevices, Collection<DataSet> dataSets) { List<String> getDataSetNames(String ldName) {
children = new LinkedHashMap<>(); // TODO make thread save
objectReference = null; List<String> dataSetNames = new ArrayList<>();
for (LogicalDevice logicalDevice : logicalDevices) { for (String dataSetRef : dataSets.keySet()) {
children.put(logicalDevice.getReference().getName(), logicalDevice); if (dataSetRef.startsWith(ldName)) {
logicalDevice.setParent(this); dataSetNames.add(dataSetRef.substring(dataSetRef.indexOf('/') + 1).replace('.', '$'));
}
}
return dataSetNames;
} }
if (dataSets != null) { /**
addDataSets(dataSets); * Get a collection of all data sets that exist in this model.
*
* @return a collection of all data sets
*/
public Collection<DataSet> getDataSets() {
return dataSets.values();
} }
for (LogicalDevice ld : logicalDevices) { /**
for (ModelNode ln : ld.getChildren()) { * @param dataSetReference the data set reference
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { * @return returns the DataSet that was removed, null if no DataSet with the given reference was
urcbs.put(urcb.getReference().toString(), urcb); * found or the data set is not deletable.
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); */
DataSet removeDataSet(String dataSetReference) {
DataSet dataSet = dataSets.get(dataSetReference);
if (dataSet == null || !dataSet.isDeletable()) {
return null;
} }
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { DataSet removedDataSet = dataSets.remove(dataSetReference);
brcbs.put(brcb.getReference().toString(), brcb); for (ModelNode ld : children.values()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
} }
} return removedDataSet;
}
void addUrcb(Urcb urcb) {
urcbs.put(urcb.getReference().getName(), urcb);
} }
}
@Override /**
public ServerModel copy() { * Get the unbuffered report control block (URCB) with the given reference.
List<LogicalDevice> childCopies = new ArrayList<>(children.size()); *
for (ModelNode childNode : children.values()) { * @param reference the reference of the requested URCB.
childCopies.add((LogicalDevice) childNode.copy()); * @return the reference to the requested URCB or null if none with the given reference is found.
*/
public Urcb getUrcb(String reference) {
return urcbs.get(reference);
} }
List<DataSet> dataSetCopies = new ArrayList<>(dataSets.size()); /**
for (DataSet dataSet : dataSets.values()) { * Get a collection of all unbuffered report control blocks (URCB) that exist in this model.
dataSetCopies.add(dataSet); *
* @return a collection of all unbuffered report control blocks (URCB)
*/
public Collection<Urcb> getUrcbs() {
return urcbs.values();
} }
return new ServerModel(childCopies, dataSetCopies); /**
} * Get the buffered report control block (BRCB) with the given reference.
*
* @param reference the reference of the requested BRCB.
* @return the reference to the requested BRCB or null if none with the given reference is found.
*/
public Brcb getBrcb(String reference) {
return brcbs.get(reference);
}
/** /**
* Get the data set with the given reference. Return null if none is found. * Get a collection of all buffered report control blocks (BRCB) that exist in this model.
* *
* @param reference the reference of the requested data set. * @return a collection of all buffered report control blocks (BRCB)
* @return the data set with the given reference. */
*/ public Collection<Brcb> getBrcbs() {
public DataSet getDataSet(String reference) { return brcbs.values();
return dataSets.get(reference); }
}
void addDataSet(DataSet dataSet) { @Override
dataSets.put(dataSet.getReferenceStr().replace('$', '.'), dataSet); public String toString() {
for (ModelNode ld : children.values()) { StringBuilder sb = new StringBuilder();
for (ModelNode ln : ld.getChildren()) { for (ModelNode logicalDevice : children.values()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { sb.append(logicalDevice.toString());
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
} }
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) { sb.append("\n\n\n---------------------\nURCBs:");
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); for (Urcb urcb : getUrcbs()) {
sb.append("\n\n").append(urcb);
} }
}
sb.append("\n\n\n---------------------\nBRCBs:");
for (Brcb brcb : getBrcbs()) {
sb.append("\n\n").append(brcb);
}
sb.append("\n\n\n---------------------\nData sets:");
for (DataSet dataSet : getDataSets()) {
sb.append("\n\n").append(dataSet);
}
return sb.toString();
}
/**
* Searches and returns the model node with the given object reference and FC. If searching for
* Logical Devices and Logical Nodes the given fc parameter may be <code>null</code>.
*
* @param objectReference the object reference of the node that is being searched for. It has a
* syntax like "ldname/ln.do....".
* @param fc the functional constraint of the requested model node. May be null for Logical Device
* and Logical Node references.
* @return the model node if it was found or null otherwise
*/
public ModelNode findModelNode(ObjectReference objectReference, Fc fc) {
ModelNode currentNode = this;
Iterator<String> searchedNodeReferenceIterator = objectReference.iterator();
while (searchedNodeReferenceIterator.hasNext()) {
currentNode = currentNode.getChild(searchedNodeReferenceIterator.next(), fc);
if (currentNode == null) {
return null;
}
}
return currentNode;
} }
}
void addDataSets(Collection<DataSet> dataSets) { /**
for (DataSet dataSet : dataSets) { * Searches and returns the model node with the given object reference and FC. If searching for
addDataSet(dataSet); * Logical Devices and Logical Nodes the given fc parameter may be <code>null</code>.
*
* @param objectReference the object reference of the node that is being searched for. It has a
* syntax like "ldname/ln.do....".
* @param fc the functional constraint of the requested model node. May be null for Logical Device
* and Logical Node references.
* @return the model node if it was found or null otherwise
*/
public ModelNode findModelNode(String objectReference, Fc fc) {
return findModelNode(new ObjectReference(objectReference), fc);
} }
for (ModelNode ld : children.values()) {
for (ModelNode ln : ld.getChildren()) { /**
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) { * Returns the subModelNode that is referenced by the given VariableDef. Return null in case the
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.')); * referenced ModelNode is not found.
*
* @param variableDef the variableDef
* @return the subModelNode that is referenced by the given VariableDef
* @throws ServiceError if an error occurs
*/
FcModelNode getNodeFromVariableDef(VariableDefs.SEQUENCE variableDef) throws ServiceError {
ObjectName objectName = variableDef.getVariableSpecification().getName();
if (objectName == null) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"name in objectName is not selected");
}
DomainSpecific domainSpecific = objectName.getDomainSpecific();
if (domainSpecific == null) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"domain_specific in name is not selected");
} }
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); ModelNode modelNode = getChild(domainSpecific.getDomainID().toString());
if (modelNode == null) {
return null;
}
String mmsItemId = domainSpecific.getItemID().toString();
int index1 = mmsItemId.indexOf('$');
if (index1 == -1) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"invalid mms item id: " + domainSpecific.getItemID());
} }
}
} LogicalNode ln = (LogicalNode) modelNode.getChild(mmsItemId.substring(0, index1));
}
if (ln == null) {
List<String> getDataSetNames(String ldName) { return null;
// TODO make thread save
List<String> dataSetNames = new ArrayList<>();
for (String dataSetRef : dataSets.keySet()) {
if (dataSetRef.startsWith(ldName)) {
dataSetNames.add(dataSetRef.substring(dataSetRef.indexOf('/') + 1).replace('.', '$'));
}
}
return dataSetNames;
}
/**
* Get a collection of all data sets that exist in this model.
*
* @return a collection of all data sets
*/
public Collection<DataSet> getDataSets() {
return dataSets.values();
}
/**
* @param dataSetReference the data set reference
* @return returns the DataSet that was removed, null if no DataSet with the given reference was
* found or the data set is not deletable.
*/
DataSet removeDataSet(String dataSetReference) {
DataSet dataSet = dataSets.get(dataSetReference);
if (dataSet == null || !dataSet.isDeletable()) {
return null;
}
DataSet removedDataSet = dataSets.remove(dataSetReference);
for (ModelNode ld : children.values()) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
} }
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.')); int index2 = mmsItemId.indexOf('$', index1 + 1);
if (index2 == -1) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "invalid mms item id");
} }
}
}
return removedDataSet;
}
void addUrcb(Urcb urcb) {
urcbs.put(urcb.getReference().getName(), urcb);
}
/**
* Get the unbuffered report control block (URCB) with the given reference.
*
* @param reference the reference of the requested URCB.
* @return the reference to the requested URCB or null if none with the given reference is found.
*/
public Urcb getUrcb(String reference) {
return urcbs.get(reference);
}
/**
* Get a collection of all unbuffered report control blocks (URCB) that exist in this model.
*
* @return a collection of all unbuffered report control blocks (URCB)
*/
public Collection<Urcb> getUrcbs() {
return urcbs.values();
}
/**
* Get the buffered report control block (BRCB) with the given reference.
*
* @param reference the reference of the requested BRCB.
* @return the reference to the requested BRCB or null if none with the given reference is found.
*/
public Brcb getBrcb(String reference) {
return brcbs.get(reference);
}
/**
* Get a collection of all buffered report control blocks (BRCB) that exist in this model.
*
* @return a collection of all buffered report control blocks (BRCB)
*/
public Collection<Brcb> getBrcbs() {
return brcbs.values();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (ModelNode logicalDevice : children.values()) {
sb.append(logicalDevice.toString());
}
sb.append("\n\n\n---------------------\nURCBs:");
for (Urcb urcb : getUrcbs()) {
sb.append("\n\n").append(urcb);
}
sb.append("\n\n\n---------------------\nBRCBs:");
for (Brcb brcb : getBrcbs()) {
sb.append("\n\n").append(brcb);
}
sb.append("\n\n\n---------------------\nData sets:");
for (DataSet dataSet : getDataSets()) {
sb.append("\n\n").append(dataSet);
}
return sb.toString();
}
/** Fc fc = Fc.fromString(mmsItemId.substring(index1 + 1, index2));
* Searches and returns the model node with the given object reference and FC. If searching for
* Logical Devices and Logical Nodes the given fc parameter may be <code>null</code>.
*
* @param objectReference the object reference of the node that is being searched for. It has a
* syntax like "ldname/ln.do....".
* @param fc the functional constraint of the requested model node. May be null for Logical Device
* and Logical Node references.
* @return the model node if it was found or null otherwise
*/
public ModelNode findModelNode(ObjectReference objectReference, Fc fc) {
ModelNode currentNode = this;
Iterator<String> searchedNodeReferenceIterator = objectReference.iterator();
while (searchedNodeReferenceIterator.hasNext()) { if (fc == null) {
currentNode = currentNode.getChild(searchedNodeReferenceIterator.next(), fc); throw new ServiceError(
if (currentNode == null) { ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
return null; "unknown functional constraint: " + mmsItemId.substring(index1 + 1, index2));
} }
}
return currentNode;
}
/** index1 = index2;
* Searches and returns the model node with the given object reference and FC. If searching for
* Logical Devices and Logical Nodes the given fc parameter may be <code>null</code>. index2 = mmsItemId.indexOf('$', index1 + 1);
*
* @param objectReference the object reference of the node that is being searched for. It has a if (index2 == -1) {
* syntax like "ldname/ln.do....". if (fc == Fc.RP) {
* @param fc the functional constraint of the requested model node. May be null for Logical Device return ln.getUrcb(mmsItemId.substring(index1 + 1));
* and Logical Node references. }
* @return the model node if it was found or null otherwise if (fc == Fc.BR) {
*/ return ln.getBrcb(mmsItemId.substring(index1 + 1));
public ModelNode findModelNode(String objectReference, Fc fc) { }
return findModelNode(new ObjectReference(objectReference), fc); return (FcModelNode) ln.getChild(mmsItemId.substring(index1 + 1), fc);
} }
if (fc == Fc.RP) {
modelNode = ln.getUrcb(mmsItemId.substring(index1 + 1, index2));
} else if (fc == Fc.BR) {
modelNode = ln.getBrcb(mmsItemId.substring(index1 + 1, index2));
} else {
modelNode = ln.getChild(mmsItemId.substring(index1 + 1, index2), fc);
}
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
while (index2 != -1) {
modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1, index2));
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
}
/** modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1));
* Returns the subModelNode that is referenced by the given VariableDef. Return null in case the
* referenced ModelNode is not found.
*
* @param variableDef the variableDef
* @return the subModelNode that is referenced by the given VariableDef
* @throws ServiceError if an error occurs
*/
FcModelNode getNodeFromVariableDef(VariableDefs.SEQUENCE variableDef) throws ServiceError {
ObjectName objectName = variableDef.getVariableSpecification().getName(); if (variableDef.getAlternateAccess() == null) {
// no array is in this node path
return (FcModelNode) modelNode;
}
if (objectName == null) { AlternateAccessSelection altAccIt =
throw new ServiceError( variableDef.getAlternateAccess().getCHOICE().get(0).getUnnamed();
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"name in objectName is not selected"); if (altAccIt.getSelectAlternateAccess() != null) {
// path to node below an array element
modelNode =
((Array) modelNode)
.getChild(
altAccIt.getSelectAlternateAccess().getAccessSelection().getIndex().intValue());
String mmsSubArrayItemId =
altAccIt
.getSelectAlternateAccess()
.getAlternateAccess()
.getCHOICE()
.get(0)
.getUnnamed()
.getSelectAccess()
.getComponent()
.getBasic()
.toString();
index1 = -1;
index2 = mmsSubArrayItemId.indexOf('$');
while (index2 != -1) {
modelNode = modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1, index2));
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
}
return (FcModelNode) modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1));
} else {
// path to an array element
return (FcModelNode)
((Array) modelNode).getChild(altAccIt.getSelectAccess().getIndex().intValue());
}
} }
DomainSpecific domainSpecific = objectName.getDomainSpecific(); public ConnectionParam getConnectionParam() {
return connectionParam;
}
if (domainSpecific == null) { public void setConnectionParam(ConnectionParam connectionParam) {
throw new ServiceError( this.connectionParam = connectionParam;
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"domain_specific in name is not selected");
} }
ModelNode modelNode = getChild(domainSpecific.getDomainID().toString()); public String getIedName() {
return iedName;
}
if (modelNode == null) { public void setIedName(String iedName) {
return null; this.iedName = iedName;
} }
String mmsItemId = domainSpecific.getItemID().toString(); public String getIedManufacturer() {
int index1 = mmsItemId.indexOf('$'); return iedManufacturer;
}
if (index1 == -1) { public void setIedManufacturer(String iedManufacturer) {
throw new ServiceError( this.iedManufacturer = iedManufacturer;
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"invalid mms item id: " + domainSpecific.getItemID());
} }
LogicalNode ln = (LogicalNode) modelNode.getChild(mmsItemId.substring(0, index1)); public List<String> getLdsInsts() {
return ldsInsts;
}
if (ln == null) { public void setLdsInsts(List<String> ldsInsts) {
return null; this.ldsInsts = ldsInsts;
} }
int index2 = mmsItemId.indexOf('$', index1 + 1); public List<String> getLdsRefs() {
return ldsRefs;
}
if (index2 == -1) { public void setLdsRefs(List<String> ldsRefs) {
throw new ServiceError( this.ldsRefs = ldsRefs;
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "invalid mms item id");
} }
Fc fc = Fc.fromString(mmsItemId.substring(index1 + 1, index2)); public List<String> getLnsRefs() {
return lnsRefs;
}
if (fc == null) { public void setLnsRefs(List<String> lnsRefs) {
throw new ServiceError( this.lnsRefs = lnsRefs;
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"unknown functional constraint: " + mmsItemId.substring(index1 + 1, index2));
} }
index1 = index2; public Map<String, Set<String>> getLns() {
return lns;
}
index2 = mmsItemId.indexOf('$', index1 + 1); public void setLns(Map<String, Set<String>> lns) {
this.lns = lns;
}
if (index2 == -1) { public HashSet<String> getLnS() {
if (fc == Fc.RP) { return lnS;
return ln.getUrcb(mmsItemId.substring(index1 + 1));
}
if (fc == Fc.BR) {
return ln.getBrcb(mmsItemId.substring(index1 + 1));
}
return (FcModelNode) ln.getChild(mmsItemId.substring(index1 + 1), fc);
} }
if (fc == Fc.RP) { public void setLnS(HashSet<String> lnS) {
modelNode = ln.getUrcb(mmsItemId.substring(index1 + 1, index2)); this.lnS = lnS;
} else if (fc == Fc.BR) {
modelNode = ln.getBrcb(mmsItemId.substring(index1 + 1, index2));
} else {
modelNode = ln.getChild(mmsItemId.substring(index1 + 1, index2), fc);
} }
index1 = index2; public Map<String, String> getDescriptions() {
index2 = mmsItemId.indexOf('$', index1 + 1); return descriptions;
while (index2 != -1) {
modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1, index2));
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
} }
modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1)); public void setDescriptions(Map<String, String> descriptions) {
this.descriptions = descriptions;
}
if (variableDef.getAlternateAccess() == null) { public Map<String, String> getdAIDescriptions() {
// no array is in this node path return dAIDescriptions;
return (FcModelNode) modelNode;
} }
AlternateAccessSelection altAccIt = public void setdAIDescriptions(Map<String, String> dAIDescriptions) {
variableDef.getAlternateAccess().getCHOICE().get(0).getUnnamed(); this.dAIDescriptions = dAIDescriptions;
}
if (altAccIt.getSelectAlternateAccess() != null) { public Map<String, String> getDos() {
// path to node below an array element return dos;
modelNode = }
((Array) modelNode)
.getChild(
altAccIt.getSelectAlternateAccess().getAccessSelection().getIndex().intValue());
String mmsSubArrayItemId = public void setDos(Map<String, String> dos) {
altAccIt this.dos = dos;
.getSelectAlternateAccess() }
.getAlternateAccess()
.getCHOICE()
.get(0)
.getUnnamed()
.getSelectAccess()
.getComponent()
.getBasic()
.toString();
index1 = -1; public List<LogicalDevice> getLogicalDevices() {
index2 = mmsSubArrayItemId.indexOf('$'); return logicalDevices;
while (index2 != -1) { }
modelNode = modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1, index2));
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
}
return (FcModelNode) modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1)); public void setLogicalDevices(List<LogicalDevice> logicalDevices) {
} else { this.logicalDevices = logicalDevices;
// path to an array element
return (FcModelNode)
((Array) modelNode).getChild(altAccIt.getSelectAccess().getIndex().intValue());
} }
} }
}

@ -14,36 +14,45 @@
package com.beanit.iec61850bean.internal.scl; package com.beanit.iec61850bean.internal.scl;
import com.beanit.iec61850bean.SclParseException; import com.beanit.iec61850bean.SclParseException;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
public final class DoType extends AbstractType { public final class DoType extends AbstractType {
// attributes not needed: cdc, iedType // attributes not needed: cdc, iedType
public List<Da> das = new ArrayList<>(); public List<Da> das = new ArrayList<>();
public List<Sdo> sdos = new ArrayList<>(); public List<Sdo> sdos = new ArrayList<>();
public DoType(Node xmlNode) throws SclParseException { private String cdc;
super(xmlNode); public DoType(Node xmlNode) throws SclParseException {
if (xmlNode.getAttributes().getNamedItem("cdc") == null) { super(xmlNode);
throw new SclParseException("Required attribute \"cdc\" not found in DOType!");
} if (xmlNode.getAttributes().getNamedItem("cdc") == null) {
throw new SclParseException("Required attribute \"cdc\" not found in DOType!");
} else {
cdc = xmlNode.getAttributes().getNamedItem("cdc").getNodeValue();
}
NodeList elements = xmlNode.getChildNodes(); NodeList elements = xmlNode.getChildNodes();
for (int i = 0; i < elements.getLength(); i++) {
Node node = elements.item(i);
if (node.getNodeName().equals("SDO")) {
sdos.add(new Sdo(node));
}
if (node.getNodeName().equals("DA")) {
das.add(new Da(node));
}
}
}
for (int i = 0; i < elements.getLength(); i++) { public String getCdc() {
Node node = elements.item(i); return cdc;
if (node.getNodeName().equals("SDO")) {
sdos.add(new Sdo(node));
}
if (node.getNodeName().equals("DA")) {
das.add(new Da(node));
}
} }
}
} }

@ -14,32 +14,44 @@
package com.beanit.iec61850bean.internal.scl; package com.beanit.iec61850bean.internal.scl;
import com.beanit.iec61850bean.SclParseException; import com.beanit.iec61850bean.SclParseException;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import java.util.ArrayList;
import java.util.List;
public final class LnType extends AbstractType { public final class LnType extends AbstractType {
// attributes not needed: lnClass, iedType // attributes not needed: lnClass, iedType
public List<Do> dos = new ArrayList<>();
private String lnClass;
public List<Do> dos = new ArrayList<>(); public LnType(Node xmlNode) throws SclParseException {
public LnType(Node xmlNode) throws SclParseException { super(xmlNode);
super(xmlNode); if (xmlNode.getAttributes().getNamedItem("lnClass") == null) {
throw new SclParseException("Required attribute \"lnClass\" not found in LNType!");
} else {
lnClass = xmlNode.getAttributes().getNamedItem("lnClass").getNodeValue();
}
if (xmlNode.getAttributes().getNamedItem("lnClass") == null) { NodeList elements = xmlNode.getChildNodes();
throw new SclParseException("Required attribute \"lnClass\" not found in LNType!");
for (int i = 0; i < elements.getLength(); i++) {
Node node = elements.item(i);
if (node.getNodeName().equals("DO")) {
dos.add(new Do(node));
}
}
} }
NodeList elements = xmlNode.getChildNodes(); public String getLnClass() {
return lnClass;
}
for (int i = 0; i < elements.getLength(); i++) { public void setLnClass(String lnClass) {
Node node = elements.item(i); this.lnClass = lnClass;
if (node.getNodeName().equals("DO")) {
dos.add(new Do(node));
}
} }
}
} }

Loading…
Cancel
Save