diff --git a/pom.xml b/pom.xml index 65af4ca..82485c4 100644 --- a/pom.xml +++ b/pom.xml @@ -187,6 +187,12 @@ jsch 0.1.55 + + + com.beanit + asn1bean + 1.14.0 + diff --git a/src/main/java/com/beanit/iec61850bean/AcseListener.java b/src/main/java/com/beanit/iec61850bean/AcseListener.java new file mode 100644 index 0000000..8d63dc8 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/AcseListener.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.josistack.AcseAssociation; +import com.beanit.josistack.AcseAssociationListener; +import java.io.IOException; +import java.nio.ByteBuffer; + +final class AcseListener implements AcseAssociationListener { + + ServerSap serverSap; + + AcseListener(ServerSap serverSap) { + this.serverSap = serverSap; + } + + @Override + public void connectionIndication(AcseAssociation acseAssociation, ByteBuffer psdu) { + serverSap.connectionIndication(acseAssociation, psdu); + } + + @Override + public void serverStoppedListeningIndication(IOException e) { + serverSap.serverStoppedListeningIndication(e); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/Array.java b/src/main/java/com/beanit/iec61850bean/Array.java new file mode 100644 index 0000000..8c9814d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/Array.java @@ -0,0 +1,163 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned32; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * An Array can contain up to n instances of one and the same DataObject, ConstructedDataAttribute, + * or BasicDataAttribute. The children of the array have the name that equals the index in the array + * (e.g. "0","1" etc.) + * + * @author Stefan Feuerhahn + */ +public final class Array extends FcModelNode { + + private final List items; + + /** + * Creates an array object. + * + * @param objectReference the reference of the array + * @param fc the functional constraint of the array + * @param children the children of the array + */ + public Array(ObjectReference objectReference, Fc fc, List children) { + this.objectReference = objectReference; + this.fc = fc; + items = new ArrayList<>(children.size()); + for (ModelNode child : children) { + items.add(child); + child.setParent(this); + } + } + + @Override + public Collection getChildren() { + return new ArrayList<>(items); + } + + @Override + public Iterator iterator() { + return items.iterator(); + } + + @Override + public ModelNode getChild(String childName, Fc fc) { + return items.get(Integer.parseInt(childName)); + } + + public ModelNode getChild(int index) { + return items.get(index); + } + + @Override + public ModelNode copy() { + List itemsCopy = new ArrayList<>(items.size()); + for (ModelNode item : items) { + itemsCopy.add((FcModelNode) item.copy()); + } + return new Array(objectReference, fc, itemsCopy); + } + + @Override + public List getBasicDataAttributes() { + List subBasicDataAttributes = new ArrayList<>(); + for (ModelNode item : items) { + subBasicDataAttributes.addAll(item.getBasicDataAttributes()); + } + return subBasicDataAttributes; + } + + public int size() { + return items.size(); + } + + @Override + Data getMmsDataObj() { + + Data.Array dataArray = new Data.Array(); + List arrayDataList = dataArray.getData(); + + for (ModelNode modelNode : items) { + Data mmsArrayItem = modelNode.getMmsDataObj(); + if (mmsArrayItem == null) { + throw new IllegalArgumentException( + "Unable to convert Child: " + modelNode.objectReference + " to MMS Data Object."); + } + arrayDataList.add(mmsArrayItem); + } + + if (arrayDataList.size() == 0) { + throw new IllegalArgumentException( + "Converting ModelNode: " + + objectReference + + " to MMS Data Object resulted in Sequence of size zero."); + } + + Data data = new Data(); + data.setArray(dataArray); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getArray() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: array"); + } + if (data.getArray().getData().size() != items.size()) { + throw new ServiceError( + ServiceError.TYPE_CONFLICT, "expected type: array with " + children.size() + " elements"); + } + + Iterator iterator = data.getArray().getData().iterator(); + for (ModelNode child : items) { + child.setValueFromMmsDataObj(iterator.next()); + } + } + + @Override + TypeDescription getMmsTypeSpec() { + + TypeSpecification elementType = new TypeSpecification(); + elementType.setTypeDescription(items.get(0).getMmsTypeSpec()); + + TypeDescription.Array array = new TypeDescription.Array(); + array.setNumberOfElements(new Unsigned32(items.size())); + array.setElementType(elementType); + + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setArray(array); + + return typeDescription; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getReference().toString()).append(" [").append(fc).append("]"); + for (ModelNode childNode : items) { + sb.append("\n"); + sb.append(childNode.toString()); + } + return sb.toString(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BasicDataAttribute.java b/src/main/java/com/beanit/iec61850bean/BasicDataAttribute.java new file mode 100644 index 0000000..4a8e267 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BasicDataAttribute.java @@ -0,0 +1,114 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public abstract class BasicDataAttribute extends FcModelNode { + + final List chgRcbs; + final List dupdRcbs; + BasicDataAttribute mirror; + /** attribute value type */ + BdaType basicType = null; + /** short address, can be used by SCSM and for local data mapping */ + String sAddr = null; + + boolean dchg; + boolean qchg; + boolean dupd; + + protected BasicDataAttribute( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + this.objectReference = objectReference; + this.fc = fc; + this.sAddr = sAddr; + this.dchg = dchg; + this.dupd = dupd; + + if (dchg) { + chgRcbs = new ArrayList<>(); + } else { + chgRcbs = null; + } + if (dupd) { + dupdRcbs = new ArrayList<>(); + } else { + dupdRcbs = null; + } + } + + public boolean getDchg() { + return dchg; + } + + public boolean getDupd() { + return dupd; + } + + public boolean getQchg() { + return dupd; + } + + public BdaType getBasicType() { + return basicType; + } + + public String getSAddr() { + return sAddr; + } + + @Override + public ModelNode getChild(String childName, Fc fc) { + return null; + } + + @Override + public ModelNode getChild(String childName) { + return null; + } + + @Override + public Collection getChildren() { + return null; + } + + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + public abstract void setDefault(); + + @Override + public List getBasicDataAttributes() { + List subBasicDataAttributes = new ArrayList<>(); + subBasicDataAttributes.add(this); + return subBasicDataAttributes; + } + + public abstract void setValueFrom(BasicDataAttribute bda); + + void setMirror(BasicDataAttribute bda) { + mirror = bda; + } + + public String getValueString() { + return null; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaBitString.java b/src/main/java/com/beanit/iec61850bean/BdaBitString.java new file mode 100644 index 0000000..458a93f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaBitString.java @@ -0,0 +1,108 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.iec61850bean.internal.HexString; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.Integer32; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; + +public abstract class BdaBitString extends BasicDataAttribute { + + final int maxNumBits; + volatile byte[] value; + + protected BdaBitString( + ObjectReference objectReference, + Fc fc, + String sAddr, + int maxNumBits, + boolean dchg, + boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + this.maxNumBits = maxNumBits; + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + if (value.length != ((maxNumBits - 1) / 8 + 1)) { + throw new IllegalArgumentException("value does not have correct length."); + } + this.value = value; + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaBitString) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public int getMaxNumBits() { + return maxNumBits; + } + + /** Initializes BIT_STRING with all zeros */ + @Override + public void setDefault() { + value = new byte[(maxNumBits - 1) / 8 + 1]; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setBitString(new BerBitString(value, maxNumBits)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getBitString() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: bit_string"); + } + if (data.getBitString().numBits > maxNumBits) { + throw new ServiceError( + ServiceError.TYPE_CONFLICT, + objectReference + + ": bit_string is bigger than type's size: " + + data.getBitString().numBits + + ">" + + maxNumBits); + } + value = data.getBitString().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setBitString(new Integer32(maxNumBits * -1)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + HexString.fromBytes(value); + } + + @Override + public String getValueString() { + return HexString.fromBytes(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaBoolean.java b/src/main/java/com/beanit/iec61850bean/BdaBoolean.java new file mode 100644 index 0000000..2f90c8d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaBoolean.java @@ -0,0 +1,93 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.iec61850bean.internal.BerBoolean; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; + +public final class BdaBoolean extends BasicDataAttribute { + + private volatile boolean value; + + public BdaBoolean( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.BOOLEAN; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaBoolean) bda).getValue(); + } + + public boolean getValue() { + return value; + } + + public void setValue(boolean value) { + this.value = value; + } + + @Override + public void setDefault() { + value = false; + } + + @Override + public BdaBoolean copy() { + BdaBoolean copy = new BdaBoolean(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setBool(new BerBoolean(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getBool() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: boolean"); + } + value = data.getBool().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setBool(new BerNull()); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } + + @Override + public String getValueString() { + return "" + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaCheck.java b/src/main/java/com/beanit/iec61850bean/BdaCheck.java new file mode 100644 index 0000000..501883a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaCheck.java @@ -0,0 +1,68 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +/** Check packed list according to 61850-7-2 */ +public final class BdaCheck extends BdaBitString { + + public BdaCheck(ObjectReference objectReference) { + super(objectReference, Fc.CO, null, 2, false, false); + basicType = BdaType.CHECK; + setDefault(); + } + + public boolean getSynchrocheck() { + return ((value[0] & 0x80) == 0x80); + } + + public void setSynchrocheck(boolean synchrocheck) { + if (synchrocheck) { + value[0] = (byte) (value[0] | 0x80); + } else { + value[0] = (byte) (value[0] & 0x7f); + } + } + + public boolean getInterlockCheck() { + return ((value[0] & 0x40) == 0x40); + } + + public void setInterlockCheck(boolean interlockCheck) { + if (interlockCheck) { + value[0] = (byte) (value[0] | 0x40); + } else { + value[0] = (byte) (value[0] & 0xbf); + } + } + + @Override + public BdaCheck copy() { + BdaCheck copy = new BdaCheck(objectReference); + + byte[] valueCopy = new byte[value.length]; + System.arraycopy(value, 0, valueCopy, 0, value.length); + copy.setValue(valueCopy); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + public String toString() { + return getReference().toString() + ": " + String.format("0x%x", value[0]); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaDoubleBitPos.java b/src/main/java/com/beanit/iec61850bean/BdaDoubleBitPos.java new file mode 100644 index 0000000..3fcd92e --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaDoubleBitPos.java @@ -0,0 +1,94 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class BdaDoubleBitPos extends BdaBitString { + + public BdaDoubleBitPos( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, 2, dchg, dupd); + basicType = BdaType.DOUBLE_BIT_POS; + setDefault(); + } + + /** Sets the value to DoubleBitPos.OFF */ + @Override + public void setDefault() { + value = new byte[] {0x40}; + } + + @Override + public BdaDoubleBitPos copy() { + BdaDoubleBitPos copy = new BdaDoubleBitPos(objectReference, fc, sAddr, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + System.arraycopy(value, 0, valueCopy, 0, value.length); + copy.setValue(valueCopy); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + public DoubleBitPos getDoubleBitPos() { + + if ((value[0] & 0xC0) == 0xC0) { + return DoubleBitPos.BAD_STATE; + } + + if ((value[0] & 0x80) == 0x80) { + return DoubleBitPos.ON; + } + + if ((value[0] & 0x40) == 0x40) { + return DoubleBitPos.OFF; + } + + return DoubleBitPos.INTERMEDIATE_STATE; + } + + public void setDoubleBitPos(DoubleBitPos doubleBitPos) { + if (doubleBitPos == DoubleBitPos.BAD_STATE) { + value[0] = (byte) 0xC0; + } else if (doubleBitPos == DoubleBitPos.ON) { + value[0] = (byte) 0x80; + } else if (doubleBitPos == DoubleBitPos.OFF) { + value[0] = (byte) 0x40; + } else { + value[0] = (byte) 0; + } + } + + @Override + public String getValueString() { + return getDoubleBitPos().toString(); + } + + public enum DoubleBitPos { + INTERMEDIATE_STATE(0), + OFF(1), + ON(2), + BAD_STATE(3); + private final int value; + + DoubleBitPos(int value) { + this.value = value; + } + + public int getIntValue() { + return value; + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaEntryTime.java b/src/main/java/com/beanit/iec61850bean/BdaEntryTime.java new file mode 100644 index 0000000..6273318 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaEntryTime.java @@ -0,0 +1,142 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.BerBoolean; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TimeOfDay; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; + +/** + * BdaEntryTime stores time in terms of days and ms since 1984. + * + * @author Stefan Feuerhahn + */ +public final class BdaEntryTime extends BasicDataAttribute { + + private volatile byte[] value; + + public BdaEntryTime( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.ENTRY_TIME; + setDefault(); + } + + /** + * Set the value of this object to the given timestamp, where timestamp is the number of ms since + * epoch 1970-01-01 00:00:00 UTC. Note that timestamps before 1984 are not valid as they cannot be + * stored. + * + * @param timestamp the number of ms since epoch 1970-01-01 + */ + public void setTimestamp(long timestamp) { + long msSince1984 = timestamp - 441763200000l; + int days = (int) (msSince1984 / 86400000); + int ms = (int) (msSince1984 % 86400000); + value = + new byte[] { + (byte) (ms >> 24), + (byte) (ms >> 16), + (byte) (ms >> 8), + (byte) ms, + (byte) (days >> 8), + (byte) days + }; + } + + public long getTimestampValue() { + if (value.length != 6) { + return -1; + } + return (((value[0] & 0xffl) << 24) + + ((value[1] & 0xffl) << 16) + + ((value[2] & 0xffl) << 8) + + (value[3] & 0xffl) + + (((value[4] & 0xffl) << 8) + (value[5] & 0xffl)) * 86400000l) + + 441763200000l; + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaEntryTime) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + this.value = value; + } + + /** Sets EntryTime to byte[6] with all zeros */ + @Override + public void setDefault() { + value = new byte[6]; + } + + @Override + public BdaEntryTime copy() { + BdaEntryTime copy = new BdaEntryTime(objectReference, fc, sAddr, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + 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() { + if (value == null) { + return null; + } + Data data = new Data(); + data.setBinaryTime(new TimeOfDay(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getBinaryTime() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: binary_time/EntryTime"); + } + value = data.getBinaryTime().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setBinaryTime(new BerBoolean(true)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + getTimestampValue(); + } + + @Override + public String getValueString() { + return "" + getTimestampValue(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaFloat32.java b/src/main/java/com/beanit/iec61850bean/BdaFloat32.java new file mode 100644 index 0000000..199fc02 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaFloat32.java @@ -0,0 +1,121 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.FloatingPoint; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; +import java.nio.ByteBuffer; + +public final class BdaFloat32 extends BasicDataAttribute { + + private volatile byte[] value; + + public BdaFloat32( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.FLOAT32; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaFloat32) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + this.value = value; + } + + public Float getFloat() { + return Float.intBitsToFloat( + ((0xff & value[1]) << 24) + | ((0xff & value[2]) << 16) + | ((0xff & value[3]) << 8) + | ((0xff & value[4]) << 0)); + } + + public void setFloat(Float value) { + this.value = ByteBuffer.allocate(1 + 4).put((byte) 8).putFloat(value).array(); + } + + @Override + public void setDefault() { + value = new byte[] {8, 0, 0, 0, 0}; + } + + @Override + public BdaFloat32 copy() { + BdaFloat32 copy = new BdaFloat32(objectReference, fc, sAddr, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + 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() { + if (value == null) { + return null; + } + Data data = new Data(); + data.setFloatingPoint(new FloatingPoint(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getFloatingPoint() == null || data.getFloatingPoint().value.length != 5) { + throw new ServiceError( + ServiceError.TYPE_CONFLICT, "expected type: floating_point as an octet string of size 5"); + } + value = data.getFloatingPoint().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription.FloatingPoint floatingPointTypeDescription = + new TypeDescription.FloatingPoint(); + floatingPointTypeDescription.setFormatWidth(new Unsigned8(32)); + floatingPointTypeDescription.setExponentWidth(new Unsigned8(8)); + + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setFloatingPoint(floatingPointTypeDescription); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + getFloat(); + } + + @Override + public String getValueString() { + return getFloat().toString(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaFloat64.java b/src/main/java/com/beanit/iec61850bean/BdaFloat64.java new file mode 100644 index 0000000..4d60704 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaFloat64.java @@ -0,0 +1,132 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.FloatingPoint; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; +import java.nio.ByteBuffer; +import java.util.Arrays; + +public final class BdaFloat64 extends BasicDataAttribute { + + private volatile byte[] value = new byte[] {11, 0, 0, 0, 0, 0, 0, 0, 0}; + + public BdaFloat64( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.FLOAT64; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaFloat64) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + if (value != null && value.length != 9) { + throw new IllegalArgumentException("value does not have length 9"); + } + this.value = value; + } + + public Double getDouble() { + if (value == null) { + return null; + } + return Double.longBitsToDouble( + ((0xffL & value[1]) << 56) + | ((0xffL & value[2]) << 48) + | ((0xffL & value[3]) << 40) + | ((0xffL & value[4]) << 32) + | ((0xffL & value[5]) << 24) + | ((0xffL & value[6]) << 16) + | ((0xffL & value[7]) << 8) + | ((0xffL & value[8]) << 0)); + } + + public void setDouble(Double value) { + this.value = ByteBuffer.allocate(1 + 8).put((byte) 11).putDouble(value).array(); + } + + @Override + public void setDefault() { + value = new byte[] {11, 0, 0, 0, 0, 0, 0, 0, 0}; + } + + @Override + public BdaFloat64 copy() { + BdaFloat64 copy = new BdaFloat64(objectReference, fc, sAddr, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + 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() { + if (value == null) { + return null; + } + Data data = new Data(); + data.setFloatingPoint(new FloatingPoint(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getFloatingPoint() == null || data.getFloatingPoint().value.length != 9) { + throw new ServiceError( + ServiceError.TYPE_CONFLICT, "expected type: floating_point as an octet string of size 9"); + } + value = data.getFloatingPoint().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription.FloatingPoint floatingPointTypeDescription = + new TypeDescription.FloatingPoint(); + floatingPointTypeDescription.setFormatWidth(new Unsigned8(64)); + floatingPointTypeDescription.setExponentWidth(new Unsigned8(11)); + + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setFloatingPoint(floatingPointTypeDescription); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + getDouble(); + } + + @Override + public String getValueString() { + return "" + Arrays.toString(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt128.java b/src/main/java/com/beanit/iec61850bean/BdaInt128.java new file mode 100644 index 0000000..f8105d8 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt128.java @@ -0,0 +1,93 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt128 extends BasicDataAttribute { + + private volatile long value; + + public BdaInt128( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT128; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt128) bda).getValue(); + } + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt128 copy() { + BdaInt128 copy = new BdaInt128(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setInteger(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getInteger() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer"); + } + value = data.getInteger().value.longValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setInteger(new Unsigned8(128)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } + + @Override + public String getValueString() { + return "" + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt16.java b/src/main/java/com/beanit/iec61850bean/BdaInt16.java new file mode 100644 index 0000000..6ec3a5b --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt16.java @@ -0,0 +1,88 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt16 extends BasicDataAttribute { + + private volatile short value; + + public BdaInt16( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT16; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt16) bda).getValue(); + } + + public short getValue() { + return value; + } + + public void setValue(short value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt16 copy() { + BdaInt16 copy = new BdaInt16(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setInteger(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getInteger() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer"); + } + value = data.getInteger().value.shortValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setInteger(new Unsigned8(16)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt16U.java b/src/main/java/com/beanit/iec61850bean/BdaInt16U.java new file mode 100644 index 0000000..590c6ae --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt16U.java @@ -0,0 +1,88 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt16U extends BasicDataAttribute { + + private volatile int value; + + public BdaInt16U( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT16U; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt16U) bda).getValue(); + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt16U copy() { + BdaInt16U copy = new BdaInt16U(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setUnsigned(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getUnsigned() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: unsigned"); + } + value = data.getUnsigned().value.intValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setUnsigned(new Unsigned8(16)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt32.java b/src/main/java/com/beanit/iec61850bean/BdaInt32.java new file mode 100644 index 0000000..5484aad --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt32.java @@ -0,0 +1,93 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt32 extends BasicDataAttribute { + + private volatile int value; + + public BdaInt32( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT32; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt32) bda).getValue(); + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt32 copy() { + BdaInt32 copy = new BdaInt32(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setInteger(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getInteger() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer"); + } + value = data.getInteger().value.intValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setInteger(new Unsigned8(32)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } + + @Override + public String getValueString() { + return "" + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt32U.java b/src/main/java/com/beanit/iec61850bean/BdaInt32U.java new file mode 100644 index 0000000..d0e8ebd --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt32U.java @@ -0,0 +1,93 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt32U extends BasicDataAttribute { + + private volatile long value; + + public BdaInt32U( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT32U; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt32U) bda).getValue(); + } + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt32U copy() { + BdaInt32U copy = new BdaInt32U(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setUnsigned(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getUnsigned() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: unsigned"); + } + value = data.getUnsigned().value.longValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setUnsigned(new Unsigned8(32)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } + + @Override + public String getValueString() { + return "" + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt64.java b/src/main/java/com/beanit/iec61850bean/BdaInt64.java new file mode 100644 index 0000000..a6631cd --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt64.java @@ -0,0 +1,88 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt64 extends BasicDataAttribute { + + private volatile long value; + + public BdaInt64( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT64; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt64) bda).getValue(); + } + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt64 copy() { + BdaInt64 copy = new BdaInt64(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setInteger(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getInteger() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer"); + } + value = data.getInteger().value.longValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setInteger(new Unsigned8(64)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt8.java b/src/main/java/com/beanit/iec61850bean/BdaInt8.java new file mode 100644 index 0000000..dfdc8c0 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt8.java @@ -0,0 +1,92 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt8 extends BasicDataAttribute { + + private volatile byte value; + + public BdaInt8(ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT8; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt8) bda).getValue(); + } + + public byte getValue() { + return value; + } + + public void setValue(byte value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt8 copy() { + BdaInt8 copy = new BdaInt8(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setInteger(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getInteger() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer"); + } + value = data.getInteger().value.byteValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setInteger(new Unsigned8(8)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } + + @Override + public String getValueString() { + return "" + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaInt8U.java b/src/main/java/com/beanit/iec61850bean/BdaInt8U.java new file mode 100644 index 0000000..73211ce --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaInt8U.java @@ -0,0 +1,88 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8; + +public final class BdaInt8U extends BasicDataAttribute { + + private volatile short value; + + public BdaInt8U( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.INT8U; + setDefault(); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + value = ((BdaInt8U) bda).getValue(); + } + + public short getValue() { + return value; + } + + public void setValue(short value) { + this.value = value; + } + + @Override + public void setDefault() { + value = 0; + } + + @Override + public BdaInt8U copy() { + BdaInt8U copy = new BdaInt8U(objectReference, fc, sAddr, dchg, dupd); + copy.setValue(value); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + @Override + Data getMmsDataObj() { + Data data = new Data(); + data.setUnsigned(new BerInteger(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getUnsigned() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: unsigned"); + } + value = data.getUnsigned().value.shortValue(); + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setUnsigned(new Unsigned8(8)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaOctetString.java b/src/main/java/com/beanit/iec61850bean/BdaOctetString.java new file mode 100644 index 0000000..ef0f427 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaOctetString.java @@ -0,0 +1,110 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerOctetString; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.Integer32; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import java.util.Arrays; + +public final class BdaOctetString extends BasicDataAttribute { + + private final int maxLength; + private volatile byte[] value; + + public BdaOctetString( + ObjectReference objectReference, + Fc fc, + String sAddr, + int maxLength, + boolean dchg, + boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.OCTET_STRING; + this.maxLength = maxLength; + setDefault(); + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + if (value != null && value.length > maxLength) { + throw new IllegalArgumentException( + "OCTET_STRING value size exceeds maxLength of " + maxLength); + } + this.value = value; + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaOctetString) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public int getMaxLength() { + return maxLength; + } + + @Override + public void setDefault() { + value = new byte[0]; + } + + @Override + public BdaOctetString copy() { + BdaOctetString copy = new BdaOctetString(objectReference, fc, sAddr, maxLength, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + 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.setOctetString(new BerOctetString(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getOctetString() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: octet_string"); + } + value = data.getOctetString().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setOctetString(new Integer32(maxLength * -1)); + return typeDescription; + } + + @Override + public String toString() { + return getReference().toString() + ": " + Arrays.toString(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaOptFlds.java b/src/main/java/com/beanit/iec61850bean/BdaOptFlds.java new file mode 100644 index 0000000..de5870c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaOptFlds.java @@ -0,0 +1,156 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class BdaOptFlds extends BdaBitString { + + public BdaOptFlds(ObjectReference objectReference, Fc fc) { + super(objectReference, fc, null, 10, false, false); + basicType = BdaType.OPTFLDS; + setDefault(); + } + + @Override + public void setDefault() { + /* default of buffer overflow is true by default in IEC 61850-6 sec. 9.3.8 */ + value = new byte[] {0x02, 0x00}; + } + + @Override + public BdaOptFlds copy() { + BdaOptFlds copy = new BdaOptFlds(objectReference, fc); + byte[] valueCopy = new byte[value.length]; + System.arraycopy(value, 0, valueCopy, 0, value.length); + copy.setValue(valueCopy); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + public boolean isSequenceNumber() { + return (value[0] & 0x40) == 0x40; + } + + public void setSequenceNumber(boolean sequenceNumber) { + if (sequenceNumber) { + value[0] = (byte) (value[0] | 0x40); + } else { + value[0] = (byte) (value[0] & 0xbf); + } + } + + public boolean isReportTimestamp() { + return (value[0] & 0x20) == 0x20; + } + + public void setReportTimestamp(boolean reportTimestamp) { + if (reportTimestamp) { + value[0] = (byte) (value[0] | 0x20); + } else { + value[0] = (byte) (value[0] & 0xdf); + } + } + + public boolean isReasonForInclusion() { + return (value[0] & 0x10) == 0x10; + } + + public void setReasonForInclusion(boolean reasonForInclusion) { + if (reasonForInclusion) { + value[0] = (byte) (value[0] | 0x10); + } else { + value[0] = (byte) (value[0] & 0xef); + } + } + + /** + * Will the data set reference (not just the name) be included in the report. + * + * @return true if the data set reference (not just the name) will be included in the report + */ + public boolean isDataSetName() { + return (value[0] & 0x08) == 0x08; + } + + public void setDataSetName(boolean dataSetName) { + if (dataSetName) { + value[0] = (byte) (value[0] | 0x08); + } else { + value[0] = (byte) (value[0] & 0xf7); + } + } + + public boolean isDataReference() { + return (value[0] & 0x04) == 0x04; + } + + public void setDataReference(boolean dataReference) { + if (dataReference) { + value[0] = (byte) (value[0] | 0x04); + } else { + value[0] = (byte) (value[0] & 0xfb); + } + } + + public boolean isBufferOverflow() { + return (value[0] & 0x02) == 0x02; + } + + public void setBufferOverflow(boolean bufferOverflow) { + if (bufferOverflow) { + value[0] = (byte) (value[0] | 0x02); + } else { + value[0] = (byte) (value[0] & 0xfd); + } + } + + public boolean isEntryId() { + return (value[0] & 0x01) == 0x01; + } + + public void setEntryId(boolean entryId) { + if (entryId) { + value[0] = (byte) (value[0] | 0x01); + } else { + value[0] = (byte) (value[0] & 0xfe); + } + } + + public boolean isConfigRevision() { + return (value[1] & 0x80) == 0x80; + } + + public void setConfigRevision(boolean configRevision) { + if (configRevision) { + value[1] = (byte) (value[1] | 0x80); + } else { + value[1] = (byte) (value[1] & 0x7f); + } + } + + public boolean isSegmentation() { + return (value[1] & 0x40) == 0x40; + } + + public void setSegmentation(boolean segmentation) { + if (segmentation) { + value[1] = (byte) (value[1] | 0x40); + } else { + value[1] = (byte) (value[1] & 0xbf); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaQuality.java b/src/main/java/com/beanit/iec61850bean/BdaQuality.java new file mode 100644 index 0000000..67c5523 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaQuality.java @@ -0,0 +1,226 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class BdaQuality extends BdaBitString { + + public BdaQuality(ObjectReference objectReference, Fc fc, String sAddr, boolean qchg) { + super(objectReference, fc, sAddr, 13, qchg, false); + this.qchg = qchg; + basicType = BdaType.QUALITY; + setDefault(); + } + + @Override + public void setDefault() { + value = new byte[] {0x00, 0x00}; + } + + @Override + public BdaQuality copy() { + BdaQuality copy = new BdaQuality(objectReference, fc, sAddr, qchg); + byte[] valueCopy = new byte[value.length]; + System.arraycopy(value, 0, valueCopy, 0, value.length); + copy.setValue(valueCopy); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + public Validity getValidity() { + if ((value[0] & 0xC0) == 0xC0) { + return Validity.QUESTIONABLE; + } + + if ((value[0] & 0x80) == 0x80) { + return Validity.RESERVED; + } + + if ((value[0] & 0x40) == 0x40) { + return Validity.INVALID; + } + + return Validity.GOOD; + } + + public void setValidity(Validity validity) { + if (validity == Validity.QUESTIONABLE) { + value[0] = (byte) (value[0] | 0xC0); + } else if (validity == Validity.RESERVED) { + value[0] = (byte) (value[0] | 0x80); + value[0] = (byte) (value[0] & 0xbf); + } else if (validity == Validity.INVALID) { + value[0] = (byte) (value[0] & 0x7f); + value[0] = (byte) (value[0] | 0x40); + } else { + value[0] = (byte) (value[0] & 0x03); + } + } + + public boolean isOverflow() { + return (value[0] & 0x20) == 0x20; + } + + public void setOverflow(boolean overflow) { + if (overflow) { + value[0] = (byte) (value[0] | 0x20); + } else { + value[0] = (byte) (value[0] & 0xdf); + } + } + + public boolean isOutOfRange() { + return (value[0] & 0x10) == 0x10; + } + + public void setOutOfRange(boolean outOfRange) { + if (outOfRange) { + value[0] = (byte) (value[0] | 0x10); + } else { + value[0] = (byte) (value[0] & 0xef); + } + } + + public boolean isBadReference() { + return (value[0] & 0x08) == 0x08; + } + + public void setBadReference(boolean badReference) { + if (badReference) { + value[0] = (byte) (value[0] | 0x08); + } else { + value[0] = (byte) (value[0] & 0xf7); + } + } + + public boolean isOscillatory() { + return (value[0] & 0x04) == 0x04; + } + + public void setOscillatory(boolean oscillatory) { + if (oscillatory) { + value[0] = (byte) (value[0] | 0x04); + } else { + value[0] = (byte) (value[0] & 0xfb); + } + } + + public boolean isFailure() { + return (value[0] & 0x02) == 0x02; + } + + public void setFailure(boolean failure) { + if (failure) { + value[0] = (byte) (value[0] | 0x02); + } else { + value[0] = (byte) (value[0] & 0xfd); + } + } + + public boolean isOldData() { + return (value[0] & 0x01) == 0x01; + } + + public void setOldData(boolean oldData) { + if (oldData) { + value[0] = (byte) (value[0] | 0x01); + } else { + value[0] = (byte) (value[0] & 0xfe); + } + } + + public boolean isInconsistent() { + return (value[1] & 0x80) == 0x80; + } + + public void setInconsistent(boolean inconsistent) { + if (inconsistent) { + value[1] = (byte) (value[0] | 0x80); + } else { + value[1] = (byte) (value[0] & 0x7f); + } + } + + public boolean isInaccurate() { + return (value[1] & 0x40) == 0x40; + } + + public void setInaccurate(boolean inaccurate) { + if (inaccurate) { + value[1] = (byte) (value[0] | 0x40); + } else { + value[1] = (byte) (value[0] & 0xbf); + } + } + + public boolean isSubstituted() { + return (value[1] & 0x20) == 0x20; + } + + public void setSubstituted(boolean substituted) { + if (substituted) { + value[1] = (byte) (value[0] | 0x20); + } else { + value[1] = (byte) (value[0] & 0xdf); + } + } + + public boolean isTest() { + return (value[1] & 0x10) == 0x10; + } + + public void setTest(boolean test) { + if (test) { + value[1] = (byte) (value[0] | 0x10); + } else { + value[1] = (byte) (value[0] & 0xef); + } + } + + public boolean isOperatorBlocked() { + return (value[1] & 0x08) == 0x08; + } + + public void setOperatorBlocked(boolean operatorBlocked) { + if (operatorBlocked) { + value[1] = (byte) (value[0] | 0x08); + } else { + value[1] = (byte) (value[0] & 0xf7); + } + } + + @Override + public String getValueString() { + return getValidity().toString(); + } + + public enum Validity { + GOOD(0), + INVALID(1), + RESERVED(2), + QUESTIONABLE(3); + private final int value; + + Validity(int value) { + this.value = value; + } + + public int getIntValue() { + return value; + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaReasonForInclusion.java b/src/main/java/com/beanit/iec61850bean/BdaReasonForInclusion.java new file mode 100644 index 0000000..b6e02c4 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaReasonForInclusion.java @@ -0,0 +1,170 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class BdaReasonForInclusion extends BdaBitString { + + public BdaReasonForInclusion(ObjectReference objectReference) { + super(objectReference, null, null, 7, false, false); + basicType = BdaType.REASON_FOR_INCLUSION; + setDefault(); + } + + @Override + public BdaReasonForInclusion copy() { + BdaReasonForInclusion copy = new BdaReasonForInclusion(objectReference); + byte[] valueCopy = new byte[value.length]; + System.arraycopy(value, 0, valueCopy, 0, value.length); + copy.setValue(valueCopy); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + public boolean isDataChange() { + return (value[0] & 0x40) == 0x40; + } + + public void setDataChange(boolean dataChange) { + if (dataChange) { + value[0] = (byte) (value[0] | 0x40); + } else { + value[0] = (byte) (value[0] & 0xbf); + } + } + + public boolean isQualityChange() { + return (value[0] & 0x20) == 0x20; + } + + public void setQualityChange(boolean qualityChange) { + if (qualityChange) { + value[0] = (byte) (value[0] | 0x20); + } else { + value[0] = (byte) (value[0] & 0xdf); + } + } + + public boolean isDataUpdate() { + return (value[0] & 0x10) == 0x10; + } + + public void setDataUpdate(boolean dataUpdate) { + if (dataUpdate) { + value[0] = (byte) (value[0] | 0x10); + } else { + value[0] = (byte) (value[0] & 0xef); + } + } + + public boolean isIntegrity() { + return (value[0] & 0x08) == 0x08; + } + + public void setIntegrity(boolean integrity) { + if (integrity) { + value[0] = (byte) (value[0] | 0x08); + } else { + value[0] = (byte) (value[0] & 0xf7); + } + } + + public boolean isGeneralInterrogation() { + return (value[0] & 0x04) == 0x04; + } + + public void setGeneralInterrogation(boolean generalInterrogation) { + if (generalInterrogation) { + value[0] = (byte) (value[0] | 0x04); + } else { + value[0] = (byte) (value[0] & 0xfb); + } + } + + public boolean isApplicationTrigger() { + return (value[0] & 0x02) == 0x02; + } + + public void setApplicationTrigger(boolean applicationTrigger) { + if (applicationTrigger) { + value[0] = (byte) (value[0] | 0x02); + } else { + value[0] = (byte) (value[0] & 0xfd); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + boolean first = true; + if (isDataChange()) { + if (!first) { + sb.append(","); + } else { + first = false; + } + sb.append("data-change"); + } + + if (isDataUpdate()) { + if (!first) { + sb.append(","); + } else { + first = false; + } + sb.append("data-update"); + } + + if (isQualityChange()) { + if (!first) { + sb.append(","); + } else { + first = false; + } + sb.append("quality-change"); + } + + if (isIntegrity()) { + if (!first) { + sb.append(","); + } else { + first = false; + } + sb.append("integrity"); + } + + if (isGeneralInterrogation()) { + if (!first) { + sb.append(","); + } else { + first = false; + } + sb.append("general-interrogation"); + } + + if (isApplicationTrigger()) { + if (!first) { + sb.append(","); + } else { + first = false; + } + sb.append("application-trigger"); + } + + return sb.toString(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaTapCommand.java b/src/main/java/com/beanit/iec61850bean/BdaTapCommand.java new file mode 100644 index 0000000..8a3e040 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaTapCommand.java @@ -0,0 +1,89 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class BdaTapCommand extends BdaBitString { + + public BdaTapCommand( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, 2, dchg, dupd); + basicType = BdaType.TAP_COMMAND; + setDefault(); + } + + /** Sets the value to TapCommand.STOP */ + @Override + public void setDefault() { + value = new byte[] {0x00}; + } + + @Override + public BdaTapCommand copy() { + BdaTapCommand copy = new BdaTapCommand(objectReference, fc, sAddr, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + System.arraycopy(value, 0, valueCopy, 0, value.length); + copy.setValue(valueCopy); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + public TapCommand getTapCommand() { + + if ((value[0] & 0xC0) == 0xC0) { + return TapCommand.RESERVED; + } + + if ((value[0] & 0x80) == 0x80) { + return TapCommand.HIGHER; + } + + if ((value[0] & 0x40) == 0x40) { + return TapCommand.LOWER; + } + + return TapCommand.STOP; + } + + public void setTapCommand(TapCommand tapCommand) { + if (tapCommand == TapCommand.RESERVED) { + value[0] = (byte) 0xC0; + } else if (tapCommand == TapCommand.HIGHER) { + value[0] = (byte) 0x80; + } else if (tapCommand == TapCommand.LOWER) { + value[0] = (byte) 0x40; + } else { + value[0] = (byte) 0x00; + } + } + + public enum TapCommand { + STOP(0), + LOWER(1), + HIGHER(2), + RESERVED(3); + private final int value; + + TapCommand(int value) { + this.value = value; + } + + public int getIntValue() { + return value; + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaTimestamp.java b/src/main/java/com/beanit/iec61850bean/BdaTimestamp.java new file mode 100644 index 0000000..3e328e9 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaTimestamp.java @@ -0,0 +1,242 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.UtcTime; +import java.time.Instant; +import java.util.Date; + +public final class BdaTimestamp extends BasicDataAttribute { + + private volatile byte[] value; + + public BdaTimestamp( + ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.TIMESTAMP; + setDefault(); + } + + /** + * The SecondSinceEpoch shall be the interval in seconds continuously counted from the 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 + */ + private long getSecondsSinceEpoch() { + return ((0xffL & value[0]) << 24 + | (0xffL & value[1]) << 16 + | (0xffL & value[2]) << 8 + | (0xffL & value[3])); + } + + /** + * 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 + * (SUM from I = 0 to 23 of bi*2**–(I+1) s). 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 + * as the smallest unit; calculated by 1/2**24 which equals approximately 60 ns. + * + *

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 + * all 24 bits are used. The resolution provided by an IED is outside the scope of this standard. + * + * @return the fraction of seconds + */ + private int getFractionOfSecond() { + return ((0xff & value[4]) << 16 | (0xff & value[5]) << 8 | (0xff & value[6])); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaTimestamp) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public Instant getInstant() { + if (value == null || value.length == 0) { + return null; + } + long time = + getSecondsSinceEpoch() * 1000L + + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5); + return Instant.ofEpochMilli(time); + } + + public void setInstant(Instant instant) { + setInstant(instant, true, false, false, 10); + } + + public void setInstant( + Instant instant, + boolean leapSecondsKnown, + boolean clockFailure, + boolean clockNotSynchronized, + int timeAccuracy) { + if (value == null) { + value = new byte[8]; + } + + int secondsSinceEpoch = (int) (instant.toEpochMilli() / 1000L); + int fractionOfSecond = (int) ((instant.toEpochMilli() % 1000L) / 1000.0 * (1 << 24)); + + int timeQuality = timeAccuracy & 0x1f; + if (leapSecondsKnown) { + timeQuality = timeQuality | 0x80; + } + if (clockFailure) { + timeQuality = timeQuality | 0x40; + } + if (clockNotSynchronized) { + timeQuality = timeQuality | 0x20; + } + + value = + new byte[] { + (byte) ((secondsSinceEpoch >> 24) & 0xff), + (byte) ((secondsSinceEpoch >> 16) & 0xff), + (byte) ((secondsSinceEpoch >> 8) & 0xff), + (byte) (secondsSinceEpoch & 0xff), + (byte) ((fractionOfSecond >> 16) & 0xff), + (byte) ((fractionOfSecond >> 8) & 0xff), + (byte) (fractionOfSecond & 0xff), + (byte) timeQuality + }; + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + if (value == null) { + this.value = new byte[8]; + } + this.value = value; + } + + /** + * 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 + * does not take into account the leap seconds that occurred before the initialization of the time + * source of the device. + * + * @return TRUE of the attribute LeapSecondsKnown shall indicate that the value for + * SecondSinceEpoch takes into account all leap seconds occurred + */ + public boolean getLeapSecondsKnown() { + return ((value[7] & 0x80) != 0); + } + + /** + * The attribute clockFailure shall indicate that the time source of the sending device is + * unreliable. The value of the TimeStamp shall be ignored. + * + * @return true if the time source of the sending device is unreliable + */ + public boolean getClockFailure() { + return ((value[7] & 0x40) != 0); + } + + /** + * The attribute clockNotSynchronized shall indicate that the time source of the sending device is + * not synchronized with the external UTC time. + * + * @return true if the time source of the sending device is not synchronized + */ + public boolean getClockNotSynchronized() { + return ((value[7] & 0x20) != 0); + } + + /** + * 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 + * + *

If the time is set via Java {@link Date} objects, the accuracy is 1 ms, that is a + * timeAccuracy value of 10. + * + * @return the time accuracy + */ + public int getTimeAccuracy() { + return ((value[7] & 0x1f)); + } + + /** Sets Timestamp the empty byte array (indicating an invalid Timestamp) */ + @Override + public void setDefault() { + value = new byte[8]; + } + + /** Sets Timestamp to current time */ + public void setCurrentTime() { + setInstant(Instant.now()); + } + + @Override + public BdaTimestamp copy() { + BdaTimestamp copy = new BdaTimestamp(objectReference, fc, sAddr, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + 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(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaTriggerConditions.java b/src/main/java/com/beanit/iec61850bean/BdaTriggerConditions.java new file mode 100644 index 0000000..48e0b8d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaTriggerConditions.java @@ -0,0 +1,119 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class BdaTriggerConditions extends BdaBitString { + + public BdaTriggerConditions(ObjectReference objectReference, Fc fc) { + super(objectReference, fc, null, 6, false, false); + basicType = BdaType.TRIGGER_CONDITIONS; + setDefault(); + } + + @Override + public void setDefault() { + /* default of GI is true by default in IEC 61850-6 sec. 9.3.8 */ + value = new byte[] {0x04}; + } + + @Override + public BdaTriggerConditions copy() { + BdaTriggerConditions copy = new BdaTriggerConditions(objectReference, fc); + byte[] valueCopy = new byte[value.length]; + System.arraycopy(value, 0, valueCopy, 0, value.length); + copy.setValue(valueCopy); + if (mirror == null) { + copy.mirror = this; + } else { + copy.mirror = mirror; + } + return copy; + } + + public boolean isDataChange() { + return (value[0] & 0x40) == 0x40; + } + + public void setDataChange(boolean dataChange) { + if (dataChange) { + value[0] = (byte) (value[0] | 0x40); + } else { + value[0] = (byte) (value[0] & 0xbf); + } + } + + public boolean isQualityChange() { + return (value[0] & 0x20) == 0x20; + } + + public void setQualityChange(boolean qualityChange) { + if (qualityChange) { + value[0] = (byte) (value[0] | 0x20); + } else { + value[0] = (byte) (value[0] & 0xdf); + } + } + + public boolean isDataUpdate() { + return (value[0] & 0x10) == 0x10; + } + + public void setDataUpdate(boolean dataUpdate) { + if (dataUpdate) { + value[0] = (byte) (value[0] | 0x10); + } else { + value[0] = (byte) (value[0] & 0xef); + } + } + + public boolean isIntegrity() { + return (value[0] & 0x08) == 0x08; + } + + public void setIntegrity(boolean integrity) { + if (integrity) { + value[0] = (byte) (value[0] | 0x08); + } else { + value[0] = (byte) (value[0] & 0xf7); + } + } + + public boolean isGeneralInterrogation() { + return (value[0] & 0x04) == 0x04; + } + + public void setGeneralInterrogation(boolean generalInterrogation) { + if (generalInterrogation) { + value[0] = (byte) (value[0] | 0x04); + } else { + value[0] = (byte) (value[0] & 0xfb); + } + } + + @Override + public String toString() { + + return super.toString() + + ", data change: " + + isDataChange() + + ", data update: " + + isDataUpdate() + + ", quality change:" + + isQualityChange() + + ", integrity period: " + + isIntegrity() + + ", GI: " + + isGeneralInterrogation(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaType.java b/src/main/java/com/beanit/iec61850bean/BdaType.java new file mode 100644 index 0000000..4e7e2fe --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaType.java @@ -0,0 +1,44 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +/** + * This Enumeration includes all possible Types for IEC 61850 leave nodes ( {@link + * BasicDataAttribute}). This includes BasicTypes and CommonACSITypes as defined in part 7-2. + */ +public enum BdaType { + BOOLEAN, + INT8, + INT16, + INT32, + INT64, + INT128, + INT8U, + INT16U, + INT32U, + FLOAT32, + FLOAT64, + OCTET_STRING, + VISIBLE_STRING, + UNICODE_STRING, + TIMESTAMP, + ENTRY_TIME, + CHECK, + QUALITY, + DOUBLE_BIT_POS, + TAP_COMMAND, + TRIGGER_CONDITIONS, + OPTFLDS, + REASON_FOR_INCLUSION +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaUnicodeString.java b/src/main/java/com/beanit/iec61850bean/BdaUnicodeString.java new file mode 100644 index 0000000..914268a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaUnicodeString.java @@ -0,0 +1,115 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.Integer32; +import com.beanit.iec61850bean.internal.mms.asn1.MMSString; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; + +public final class BdaUnicodeString extends BasicDataAttribute { + + private final int maxLength; + private byte[] value; + + public BdaUnicodeString( + ObjectReference objectReference, + Fc fc, + String sAddr, + int maxLength, + boolean dchg, + boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.UNICODE_STRING; + this.maxLength = maxLength; + setDefault(); + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + if (value == null || value.length > maxLength) { + throw new IllegalArgumentException( + "Value was null or UNICODE_STRING value size exceeds maxLength of " + maxLength); + } + this.value = value; + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaUnicodeString) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public int getMaxLength() { + return maxLength; + } + + @Override + public void setDefault() { + value = new byte[0]; + } + + @Override + public BdaUnicodeString copy() { + BdaUnicodeString copy = new BdaUnicodeString(objectReference, fc, sAddr, maxLength, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + 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.setMMSString(new MMSString(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getMMSString() == null) { + throw new ServiceError( + ServiceError.TYPE_CONFLICT, "expected type: mms_string/unicode_string"); + } + value = data.getMMSString().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setMMSString(new Integer32(maxLength * -1)); + return typeDescription; + } + + @Override + public String toString() { + if (value == null) { + return getReference().toString() + ": null"; + } + return getReference().toString() + ": " + new String(value, UTF_8); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/BdaVisibleString.java b/src/main/java/com/beanit/iec61850bean/BdaVisibleString.java new file mode 100644 index 0000000..5aa052f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/BdaVisibleString.java @@ -0,0 +1,130 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.asn1bean.ber.types.string.BerVisibleString; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.Integer32; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; + +public final class BdaVisibleString extends BasicDataAttribute { + + private final int maxLength; + private byte[] value; + + public BdaVisibleString( + ObjectReference objectReference, + Fc fc, + String sAddr, + int maxLength, + boolean dchg, + boolean dupd) { + super(objectReference, fc, sAddr, dchg, dupd); + basicType = BdaType.VISIBLE_STRING; + this.maxLength = maxLength; + setDefault(); + } + + public byte[] getValue() { + return value; + } + + public void setValue(byte[] value) { + if (value == null || value.length > maxLength) { + throw new IllegalArgumentException( + "value was null or VISIBLE_STRING value size exceeds maxLength of " + maxLength); + } + this.value = value; + } + + public void setValue(String value) { + setValue(value.getBytes(UTF_8)); + } + + @Override + public void setValueFrom(BasicDataAttribute bda) { + byte[] srcValue = ((BdaVisibleString) bda).getValue(); + if (value.length != srcValue.length) { + value = new byte[srcValue.length]; + } + System.arraycopy(srcValue, 0, value, 0, srcValue.length); + } + + public int getMaxLength() { + return maxLength; + } + + public String getStringValue() { + return new String(value, UTF_8); + } + + @Override + public void setDefault() { + value = new byte[0]; + } + + @Override + public BdaVisibleString copy() { + BdaVisibleString copy = new BdaVisibleString(objectReference, fc, sAddr, maxLength, dchg, dupd); + byte[] valueCopy = new byte[value.length]; + 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.setVisibleString(new BerVisibleString(value)); + return data; + } + + @Override + void setValueFromMmsDataObj(Data data) throws ServiceError { + if (data.getVisibleString() == null) { + throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: visible_string"); + } + value = data.getVisibleString().value; + } + + @Override + TypeDescription getMmsTypeSpec() { + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setVisibleString(new Integer32(maxLength * -1)); + return typeDescription; + } + + @Override + public String toString() { + if (value == null) { + return getReference().toString() + ": null"; + } + if (value.length == 0 || value[0] == (byte) 0) { + return getReference().toString() + ": ''"; + } + return getReference().toString() + ": " + new String(value, UTF_8); + } + + @Override + public String getValueString() { + return new String(value, UTF_8); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/Brcb.java b/src/main/java/com/beanit/iec61850bean/Brcb.java new file mode 100644 index 0000000..14d51f8 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/Brcb.java @@ -0,0 +1,57 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.ArrayList; +import java.util.List; + +public class Brcb extends Rcb { + + public Brcb(ObjectReference objectReference, List children) { + super(objectReference, Fc.BR, children); + } + + public BdaBoolean getPurgeBuf() { + return (BdaBoolean) children.get("PurgeBuf"); + } + + public BdaOctetString getEntryId() { + return (BdaOctetString) children.get("EntryID"); + } + + public BdaEntryTime getTimeOfEntry() { + return (BdaEntryTime) children.get("TimeOfEntry"); + } + + /** + * Gets the ResvTms attribute. This attribute is optional. Will return NULL if the attribute is + * not available. + * + * @return the ResvTms attribute, null if not available. + */ + public BdaInt16 getResvTms() { + return (BdaInt16) children.get("ResvTms"); + } + + @Override + public FcDataObject copy() { + List childCopies = new ArrayList<>(children.size()); + for (ModelNode childNode : children.values()) { + childCopies.add((FcModelNode) childNode.copy()); + } + Brcb brcb = new Brcb(objectReference, childCopies); + brcb.dataSet = dataSet; + return brcb; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ClientAssociation.java b/src/main/java/com/beanit/iec61850bean/ClientAssociation.java new file mode 100644 index 0000000..866ae46 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ClientAssociation.java @@ -0,0 +1,2147 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.asn1bean.ber.types.string.BerGraphicString; +import com.beanit.asn1bean.ber.types.string.BerVisibleString; +import com.beanit.iec61850bean.internal.BerBoolean; +import com.beanit.iec61850bean.internal.mms.asn1.AccessResult; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedRequestPDU; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedResponsePDU; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceRequest; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceResponse; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.DefineNamedVariableListRequest; +import com.beanit.iec61850bean.internal.mms.asn1.DeleteNamedVariableListRequest; +import com.beanit.iec61850bean.internal.mms.asn1.DeleteNamedVariableListRequest.ListOfVariableListName; +import com.beanit.iec61850bean.internal.mms.asn1.DeleteNamedVariableListResponse; +import com.beanit.iec61850bean.internal.mms.asn1.DirectoryEntry; +import com.beanit.iec61850bean.internal.mms.asn1.FileCloseRequest; +import com.beanit.iec61850bean.internal.mms.asn1.FileDeleteRequest; +import com.beanit.iec61850bean.internal.mms.asn1.FileDirectoryRequest; +import com.beanit.iec61850bean.internal.mms.asn1.FileDirectoryResponse; +import com.beanit.iec61850bean.internal.mms.asn1.FileName; +import com.beanit.iec61850bean.internal.mms.asn1.FileOpenRequest; +import com.beanit.iec61850bean.internal.mms.asn1.FileReadRequest; +import com.beanit.iec61850bean.internal.mms.asn1.GetNameListRequest; +import com.beanit.iec61850bean.internal.mms.asn1.GetNameListRequest.ObjectScope; +import com.beanit.iec61850bean.internal.mms.asn1.GetNameListResponse; +import com.beanit.iec61850bean.internal.mms.asn1.GetNamedVariableListAttributesRequest; +import com.beanit.iec61850bean.internal.mms.asn1.GetNamedVariableListAttributesResponse; +import com.beanit.iec61850bean.internal.mms.asn1.GetVariableAccessAttributesRequest; +import com.beanit.iec61850bean.internal.mms.asn1.Identifier; +import com.beanit.iec61850bean.internal.mms.asn1.InitiateRequestPDU; +import com.beanit.iec61850bean.internal.mms.asn1.InitiateResponsePDU; +import com.beanit.iec61850bean.internal.mms.asn1.Integer16; +import com.beanit.iec61850bean.internal.mms.asn1.Integer32; +import com.beanit.iec61850bean.internal.mms.asn1.Integer8; +import com.beanit.iec61850bean.internal.mms.asn1.MMSpdu; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectClass; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; +import com.beanit.iec61850bean.internal.mms.asn1.ParameterSupportOptions; +import com.beanit.iec61850bean.internal.mms.asn1.ReadRequest; +import com.beanit.iec61850bean.internal.mms.asn1.ReadResponse; +import com.beanit.iec61850bean.internal.mms.asn1.RejectPDU.RejectReason; +import com.beanit.iec61850bean.internal.mms.asn1.ServiceError.ErrorClass; +import com.beanit.iec61850bean.internal.mms.asn1.ServiceSupportOptions; +import com.beanit.iec61850bean.internal.mms.asn1.UnconfirmedPDU; +import com.beanit.iec61850bean.internal.mms.asn1.UnconfirmedService; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned32; +import com.beanit.iec61850bean.internal.mms.asn1.VariableAccessSpecification; +import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs; +import com.beanit.iec61850bean.internal.mms.asn1.WriteRequest; +import com.beanit.iec61850bean.internal.mms.asn1.WriteRequest.ListOfData; +import com.beanit.iec61850bean.internal.mms.asn1.WriteResponse; +import com.beanit.josistack.AcseAssociation; +import com.beanit.josistack.ByteBufferInputStream; +import com.beanit.josistack.ClientAcseSap; +import com.beanit.josistack.DecodingException; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.text.ParseException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Represents an association/connection to an IEC 61850 MMS server. An instance of + * ClientAssociation is obtained using ClientSap. An association object can be + * used to execute the IEC 61850 ACSI services. Note that not all ACSI services have a corresponding + * function in this API. For example all GetDirectory and GetDefinition services are covered by + * retrieveModel(). The control services can be executed by using getDataValues and + * setDataValues on the control objects in the data model. + */ +public final class ClientAssociation { + + private static final Integer16 version = new Integer16(new byte[] {(byte) 0x01, (byte) 0x01}); + private static final ParameterSupportOptions proposedParameterCbbBitString = + new ParameterSupportOptions(new byte[] {0x03, 0x05, (byte) 0xf1, 0x00}); + private final ClientReceiver clientReceiver; + private final BlockingQueue incomingResponses = new LinkedBlockingQueue<>(); + private final ReverseByteArrayOutputStream reverseOStream = + new ReverseByteArrayOutputStream(500, true); + ServerModel serverModel; + private AcseAssociation acseAssociation = null; + private int responseTimeout; + + private int invokeId = 0; + private byte[] servicesSupported = null; + + private int negotiatedMaxPduSize; + private ClientEventListener reportListener = null; + + private boolean closed = false; + + ClientAssociation( + InetAddress address, + int port, + InetAddress localAddr, + int localPort, + String authenticationParameter, + ClientAcseSap acseSap, + int proposedMaxMmsPduSize, + int proposedMaxServOutstandingCalling, + int proposedMaxServOutstandingCalled, + int proposedDataStructureNestingLevel, + byte[] servicesSupportedCalling, + int responseTimeout, + int messageFragmentTimeout, + ClientEventListener reportListener) + throws IOException { + + this.responseTimeout = responseTimeout; + + acseSap.tSap.setMessageFragmentTimeout(messageFragmentTimeout); + acseSap.tSap.setMessageTimeout(responseTimeout); + + negotiatedMaxPduSize = proposedMaxMmsPduSize; + + this.reportListener = reportListener; + + associate( + address, + port, + localAddr, + localPort, + authenticationParameter, + acseSap, + proposedMaxMmsPduSize, + proposedMaxServOutstandingCalling, + proposedMaxServOutstandingCalled, + proposedDataStructureNestingLevel, + servicesSupportedCalling); + + acseAssociation.setMessageTimeout(0); + + clientReceiver = new ClientReceiver(negotiatedMaxPduSize); + clientReceiver.start(); + } + + private static ServiceError mmsDataAccessErrorToServiceError(BerInteger dataAccessError) { + + switch (dataAccessError.value.intValue()) { + case 1: + return new ServiceError( + ServiceError.FAILED_DUE_TO_SERVER_CONSTRAINT, "MMS DataAccessError: hardware-fault"); + case 2: + return new ServiceError( + ServiceError.INSTANCE_LOCKED_BY_OTHER_CLIENT, + "MMS DataAccessError: temporarily-unavailable"); + case 3: + return new ServiceError( + ServiceError.ACCESS_VIOLATION, "MMS DataAccessError: object-access-denied"); + case 5: + return new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, "MMS DataAccessError: invalid-address"); + case 7: + return new ServiceError( + ServiceError.TYPE_CONFLICT, "MMS DataAccessError: type-inconsistent"); + case 10: + return new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, "MMS DataAccessError: object-non-existent"); + case 11: + return new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, "MMS DataAccessError: object-value-invalid"); + default: + return new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "MMS DataAccessError: " + dataAccessError.value); + } + } + + private static void testForErrorResponse(MMSpdu mmsResponsePdu) throws ServiceError { + if (mmsResponsePdu.getConfirmedErrorPDU() == null) { + return; + } + + ErrorClass errClass = mmsResponsePdu.getConfirmedErrorPDU().getServiceError().getErrorClass(); + + if (errClass != null) { + if (errClass.getAccess() != null) { + if (errClass.getAccess().value.intValue() == 3) { + throw new ServiceError( + ServiceError.ACCESS_VIOLATION, + "MMS confirmed error: class: \"access\", error code: \"object-access-denied\""); + } else if (errClass.getAccess().value.intValue() == 2) { + + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "MMS confirmed error: class: \"access\", error code: \"object-non-existent\""); + } + + } else if (errClass.getFile() != null) { + if (errClass.getFile().value.intValue() == 7) { + + throw new ServiceError( + ServiceError.FILE_NONE_EXISTENT, + "MMS confirmed error: class: \"file\", error code: \"file-non-existent\""); + } + } + } + + if (mmsResponsePdu.getConfirmedErrorPDU().getServiceError().getAdditionalDescription() + != null) { + throw new ServiceError( + ServiceError.UNKNOWN, + "MMS confirmed error. Description: " + + mmsResponsePdu + .getConfirmedErrorPDU() + .getServiceError() + .getAdditionalDescription() + .toString()); + } + throw new ServiceError(ServiceError.UNKNOWN, "MMS confirmed error."); + } + + private static void testForRejectResponse(MMSpdu mmsResponsePdu) throws ServiceError { + if (mmsResponsePdu.getRejectPDU() == null) { + return; + } + + RejectReason rejectReason = mmsResponsePdu.getRejectPDU().getRejectReason(); + if (rejectReason != null) { + if (rejectReason.getPduError() != null) { + if (rejectReason.getPduError().value.intValue() == 1) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, + "MMS reject: type: \"pdu-error\", reject code: \"invalid-pdu\""); + } + } + } + throw new ServiceError(ServiceError.UNKNOWN, "MMS confirmed error."); + } + + private static void testForInitiateErrorResponse(MMSpdu mmsResponsePdu) throws ServiceError { + if (mmsResponsePdu.getInitiateErrorPDU() != null) { + + ErrorClass errClass = mmsResponsePdu.getInitiateErrorPDU().getErrorClass(); + if (errClass != null) { + if (errClass.getVmdState() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"vmd_state\" with val: " + errClass.getVmdState().value); + } + if (errClass.getApplicationReference() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"application_reference\" with val: " + + errClass.getApplicationReference().value); + } + if (errClass.getDefinition() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"definition\" with val: " + errClass.getDefinition().value); + } + if (errClass.getResource() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"resource\" with val: " + errClass.getResource().value); + } + if (errClass.getService() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"service\" with val: " + errClass.getService().value); + } + if (errClass.getServicePreempt() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"service_preempt\" with val: " + errClass.getServicePreempt().value); + } + if (errClass.getTimeResolution() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"time_resolution\" with val: " + errClass.getTimeResolution().value); + } + if (errClass.getAccess() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"access\" with val: " + errClass.getAccess().value); + } + if (errClass.getInitiate() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"initiate\" with val: " + errClass.getInitiate().value); + } + if (errClass.getConclude() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"conclude\" with val: " + errClass.getConclude()); + } + if (errClass.getCancel() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"cancel\" with val: " + errClass.getCancel().value); + } + if (errClass.getFile() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"file\" with val: " + errClass.getFile().value); + } + if (errClass.getOthers() != null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "error class \"others\" with val: " + errClass.getOthers().value); + } + } + + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "unknown error class"); + } + } + + private static MMSpdu constructInitRequestPdu( + int proposedMaxPduSize, + int proposedMaxServOutstandingCalling, + int proposedMaxServOutstandingCalled, + int proposedDataStructureNestingLevel, + byte[] servicesSupportedCalling) { + + InitiateRequestPDU.InitRequestDetail initRequestDetail = + new InitiateRequestPDU.InitRequestDetail(); + initRequestDetail.setProposedVersionNumber(version); + initRequestDetail.setProposedParameterCBB(proposedParameterCbbBitString); + initRequestDetail.setServicesSupportedCalling( + new ServiceSupportOptions(servicesSupportedCalling, 85)); + + InitiateRequestPDU initiateRequestPdu = new InitiateRequestPDU(); + initiateRequestPdu.setLocalDetailCalling(new Integer32(proposedMaxPduSize)); + initiateRequestPdu.setProposedMaxServOutstandingCalling( + new Integer16(proposedMaxServOutstandingCalling)); + initiateRequestPdu.setProposedMaxServOutstandingCalled( + new Integer16(proposedMaxServOutstandingCalled)); + initiateRequestPdu.setProposedDataStructureNestingLevel( + new Integer8(proposedDataStructureNestingLevel)); + initiateRequestPdu.setInitRequestDetail(initRequestDetail); + + MMSpdu initiateRequestMMSpdu = new MMSpdu(); + initiateRequestMMSpdu.setInitiateRequestPDU(initiateRequestPdu); + + return initiateRequestMMSpdu; + } + + /** + * Gets the response timeout. The response timeout is used whenever a request is sent to the + * server. The client will wait for this amount of time for the server's response before throwing + * a ServiceError.TIMEOUT. Responses received after the timeout will be automatically discarded. + * + * @return the response timeout in milliseconds. + */ + public int getResponseTimeout() { + return responseTimeout; + } + + /** + * Sets the response timeout. The response timeout is used whenever a request is sent to the + * server. The client will wait for this amount of time for the server's response before throwing + * a ServiceError.TIMEOUT. Responses received after the timeout will be automatically discarded. + * + * @param timeout the response timeout in milliseconds. + */ + public void setResponseTimeout(int timeout) { + responseTimeout = timeout; + } + + private int getInvokeId() { + invokeId = (invokeId + 1) % 2147483647; + return invokeId; + } + + /** + * Gets the ServicesSupported. The 11-byte array of bit flags is available after InitiateResponse + * is received from the server, otherwise null is returned + * + * @return the ServicesSupported byte array, or null. + */ + public byte[] getServicesSupported() { + return servicesSupported; + } + + private ConfirmedServiceResponse encodeWriteReadDecode(ConfirmedServiceRequest serviceRequest) + throws ServiceError, IOException { + + int currentInvokeId = getInvokeId(); + + ConfirmedRequestPDU confirmedRequestPdu = new ConfirmedRequestPDU(); + confirmedRequestPdu.setInvokeID(new Unsigned32(currentInvokeId)); + confirmedRequestPdu.setService(serviceRequest); + + MMSpdu requestPdu = new MMSpdu(); + requestPdu.setConfirmedRequestPDU(confirmedRequestPdu); + + reverseOStream.reset(); + + try { + requestPdu.encode(reverseOStream); + } catch (Exception e) { + IOException e2 = new IOException("Error encoding MmsPdu.", e); + clientReceiver.close(e2); + throw e2; + } + + clientReceiver.setResponseExpected(currentInvokeId); + try { + acseAssociation.send(reverseOStream.getByteBuffer()); + } catch (IOException e) { + IOException e2 = new IOException("Error sending packet.", e); + clientReceiver.close(e2); + throw e2; + } + + MMSpdu decodedResponsePdu = null; + + try { + if (responseTimeout == 0) { + decodedResponsePdu = incomingResponses.take(); + } else { + decodedResponsePdu = incomingResponses.poll(responseTimeout, TimeUnit.MILLISECONDS); + } + } catch (InterruptedException e) { + // TODO can this ever be interrupted? + } + + if (decodedResponsePdu == null) { + decodedResponsePdu = clientReceiver.removeExpectedResponse(); + if (decodedResponsePdu == null) { + throw new ServiceError(ServiceError.TIMEOUT); + } + } + + if (decodedResponsePdu.getConfirmedRequestPDU() != null) { + incomingResponses.add(decodedResponsePdu); + throw new IOException("connection was closed", clientReceiver.getLastIOException()); + } + + testForInitiateErrorResponse(decodedResponsePdu); + testForErrorResponse(decodedResponsePdu); + testForRejectResponse(decodedResponsePdu); + + ConfirmedResponsePDU confirmedResponsePdu = decodedResponsePdu.getConfirmedResponsePDU(); + if (confirmedResponsePdu == null) { + throw new IllegalStateException("Response PDU is not a confirmed response pdu"); + } + + return confirmedResponsePdu.getService(); + } + + private void associate( + InetAddress address, + int port, + InetAddress localAddr, + int localPort, + String authenticationParameter, + ClientAcseSap acseSap, + int proposedMaxPduSize, + int proposedMaxServOutstandingCalling, + int proposedMaxServOutstandingCalled, + int proposedDataStructureNestingLevel, + byte[] servicesSupportedCalling) + throws IOException { + + MMSpdu initiateRequestMMSpdu = + constructInitRequestPdu( + proposedMaxPduSize, + proposedMaxServOutstandingCalling, + proposedMaxServOutstandingCalled, + proposedDataStructureNestingLevel, + servicesSupportedCalling); + + ReverseByteArrayOutputStream reverseOStream = new ReverseByteArrayOutputStream(500, true); + initiateRequestMMSpdu.encode(reverseOStream); + + try { + acseAssociation = + acseSap.associate( + address, + port, + localAddr, + localPort, + authenticationParameter, + reverseOStream.getByteBuffer()); + + ByteBuffer initResponse = acseAssociation.getAssociateResponseAPdu(); + + MMSpdu initiateResponseMmsPdu = new MMSpdu(); + + initiateResponseMmsPdu.decode(new ByteBufferInputStream(initResponse), null); + + handleInitiateResponse( + initiateResponseMmsPdu, + proposedMaxPduSize, + proposedMaxServOutstandingCalling, + proposedMaxServOutstandingCalled, + proposedDataStructureNestingLevel); + } catch (IOException e) { + if (acseAssociation != null) { + acseAssociation.close(); + } + throw e; + } + } + + private void handleInitiateResponse( + MMSpdu responsePdu, + int proposedMaxPduSize, + int proposedMaxServOutstandingCalling, + int proposedMaxServOutstandingCalled, + int proposedDataStructureNestingLevel) + throws IOException { + + if (responsePdu.getInitiateErrorPDU() != null) { + throw new IOException( + "Got response error of class: " + responsePdu.getInitiateErrorPDU().getErrorClass()); + } + + if (responsePdu.getInitiateResponsePDU() == null) { + acseAssociation.disconnect(); + throw new IOException("Error decoding InitiateResponse Pdu"); + } + + InitiateResponsePDU initiateResponsePdu = responsePdu.getInitiateResponsePDU(); + + if (initiateResponsePdu.getLocalDetailCalled() != null) { + negotiatedMaxPduSize = initiateResponsePdu.getLocalDetailCalled().intValue(); + } + + int negotiatedMaxServOutstandingCalling = + initiateResponsePdu.getNegotiatedMaxServOutstandingCalling().intValue(); + int negotiatedMaxServOutstandingCalled = + initiateResponsePdu.getNegotiatedMaxServOutstandingCalled().intValue(); + + int negotiatedDataStructureNestingLevel; + if (initiateResponsePdu.getNegotiatedDataStructureNestingLevel() != null) { + negotiatedDataStructureNestingLevel = + initiateResponsePdu.getNegotiatedDataStructureNestingLevel().intValue(); + } else { + negotiatedDataStructureNestingLevel = proposedDataStructureNestingLevel; + } + + if (negotiatedMaxPduSize < ClientSap.MINIMUM_MMS_PDU_SIZE + || negotiatedMaxPduSize > proposedMaxPduSize + || negotiatedMaxServOutstandingCalling > proposedMaxServOutstandingCalling + || negotiatedMaxServOutstandingCalling < 0 + || negotiatedMaxServOutstandingCalled > proposedMaxServOutstandingCalled + || negotiatedMaxServOutstandingCalled < 0 + || negotiatedDataStructureNestingLevel > proposedDataStructureNestingLevel + || negotiatedDataStructureNestingLevel < 0) { + acseAssociation.disconnect(); + throw new IOException("Error negotiating parameters"); + } + + int version = + initiateResponsePdu.getInitResponseDetail().getNegotiatedVersionNumber().intValue(); + if (version != 1) { + throw new IOException("Unsupported version number was negotiated."); + } + + servicesSupported = + initiateResponsePdu.getInitResponseDetail().getServicesSupportedCalled().value; + if ((servicesSupported[0] & 0x40) != 0x40) { + throw new IOException("Obligatory services are not supported by the server."); + } + } + + /** + * Set the server model instead of retrieving it from the server device. + * + * @param model the server model + */ + public void setServerModel(ServerModel model) { + this.serverModel = model; + } + + /** + * Triggers all GetDirectory and GetDefinition ACSI services needed to get the complete server + * model. Because in MMS SubDataObjects cannot be distinguished from Constructed Data Attributes + * they will always be represented as Constructed Data Attributes in the returned model. + * + * @return the ServerModel that is the root node of the complete server model. + * @throws ServiceError if a ServiceError occurs while calling any of the ASCI services. + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public ServerModel retrieveModel() throws ServiceError, IOException { + + List ldNames = retrieveLogicalDevices(); + List> lnNames = new ArrayList<>(ldNames.size()); + + for (int i = 0; i < ldNames.size(); i++) { + lnNames.add(retrieveLogicalNodeNames(ldNames.get(i))); + } + List lds = new ArrayList<>(); + for (int i = 0; i < ldNames.size(); i++) { + List lns = new ArrayList<>(); + for (int j = 0; j < lnNames.get(i).size(); j++) { + lns.add( + retrieveDataDefinitions( + new ObjectReference(ldNames.get(i) + "/" + lnNames.get(i).get(j)))); + } + lds.add(new LogicalDevice(new ObjectReference(ldNames.get(i)), lns)); + } + + serverModel = new ServerModel(lds, null); + + updateDataSets(); + + return serverModel; + } + + private List retrieveLogicalDevices() throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructGetServerDirectoryRequest(); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + return decodeGetServerDirectoryResponse(confirmedServiceResponse); + } + + private ConfirmedServiceRequest constructGetServerDirectoryRequest() { + ObjectClass objectClass = new ObjectClass(); + objectClass.setBasicObjectClass(new BerInteger(9)); + + GetNameListRequest.ObjectScope objectScope = new GetNameListRequest.ObjectScope(); + objectScope.setVmdSpecific(new BerNull()); + + GetNameListRequest getNameListRequest = new GetNameListRequest(); + getNameListRequest.setObjectClass(objectClass); + getNameListRequest.setObjectScope(objectScope); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setGetNameList(getNameListRequest); + + return confirmedServiceRequest; + } + + private List decodeGetServerDirectoryResponse( + ConfirmedServiceResponse confirmedServiceResponse) throws ServiceError { + + if (confirmedServiceResponse.getGetNameList() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding Get Server Directory Response Pdu"); + } + + List identifiers = + confirmedServiceResponse.getGetNameList().getListOfIdentifier().getIdentifier(); + ArrayList objectRefs = new ArrayList<>(); // ObjectReference[identifiers.size()]; + + for (BerVisibleString identifier : identifiers) { + objectRefs.add(identifier.toString()); + } + + return objectRefs; + } + + private List retrieveLogicalNodeNames(String ld) throws ServiceError, IOException { + List lns = new ArrayList<>(); + String continueAfterRef = ""; + do { + ConfirmedServiceRequest serviceRequest = + constructGetDirectoryRequest(ld, continueAfterRef, true); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + continueAfterRef = decodeGetDirectoryResponse(confirmedServiceResponse, lns); + + } while (!continueAfterRef.isEmpty()); + return lns; + } + + private ConfirmedServiceRequest constructGetDirectoryRequest( + String ldRef, String continueAfter, boolean logicalDevice) { + + ObjectClass objectClass = new ObjectClass(); + + if (logicalDevice) { + objectClass.setBasicObjectClass(new BerInteger(0)); + } else { // for data sets + objectClass.setBasicObjectClass(new BerInteger(2)); + } + + GetNameListRequest getNameListRequest; + + ObjectScope objectScopeChoiceType = new ObjectScope(); + objectScopeChoiceType.setDomainSpecific(new Identifier(ldRef.getBytes(UTF_8))); + + getNameListRequest = new GetNameListRequest(); + getNameListRequest.setObjectClass(objectClass); + getNameListRequest.setObjectScope(objectScopeChoiceType); + if (!continueAfter.isEmpty()) { + getNameListRequest.setContinueAfter(new Identifier(continueAfter.getBytes(UTF_8))); + } + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setGetNameList(getNameListRequest); + return confirmedServiceRequest; + } + + /** + * Decodes an MMS response which contains the structure of a LD and its LNs including names of + * DOs. + */ + private String decodeGetDirectoryResponse( + ConfirmedServiceResponse confirmedServiceResponse, List lns) throws ServiceError { + + if (confirmedServiceResponse.getGetNameList() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "decodeGetLDDirectoryResponse: Error decoding server response"); + } + + GetNameListResponse getNameListResponse = confirmedServiceResponse.getGetNameList(); + + List identifiers = getNameListResponse.getListOfIdentifier().getIdentifier(); + + if (identifiers.size() == 0) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "decodeGetLDDirectoryResponse: Instance not available"); + } + + BerVisibleString identifier = null; + Iterator it = identifiers.iterator(); + + String idString; + + while (it.hasNext()) { + identifier = it.next(); + idString = identifier.toString(); + + if (idString.indexOf('$') == -1) { + lns.add(idString); + } + } + + if (getNameListResponse.getMoreFollows() != null + && getNameListResponse.getMoreFollows().value == false) { + return ""; + } else { + return identifier.toString(); + } + } + + private LogicalNode retrieveDataDefinitions(ObjectReference lnRef) + throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructGetDataDefinitionRequest(lnRef); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + return decodeGetDataDefinitionResponse(confirmedServiceResponse, lnRef); + } + + private ConfirmedServiceRequest constructGetDataDefinitionRequest(ObjectReference lnRef) { + + ObjectName.DomainSpecific domainSpec = new ObjectName.DomainSpecific(); + domainSpec.setDomainID(new Identifier(lnRef.get(0).getBytes(UTF_8))); + domainSpec.setItemID(new Identifier(lnRef.get(1).getBytes(UTF_8))); + + ObjectName objectName = new ObjectName(); + objectName.setDomainSpecific(domainSpec); + + GetVariableAccessAttributesRequest getVariableAccessAttributesRequest = + new GetVariableAccessAttributesRequest(); + getVariableAccessAttributesRequest.setName(objectName); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setGetVariableAccessAttributes(getVariableAccessAttributesRequest); + + return confirmedServiceRequest; + } + + private LogicalNode decodeGetDataDefinitionResponse( + ConfirmedServiceResponse confirmedServiceResponse, ObjectReference lnRef) + throws ServiceError { + + return DataDefinitionResParser.parseGetDataDefinitionResponse(confirmedServiceResponse, lnRef); + } + + /** + * The implementation of the GetDataValues ACSI service. Will send an MMS read request for the + * given model node. After a successful return, the Basic Data Attributes of the passed model node + * will contain the values read. If one of the Basic Data Attributes cannot be read then none of + * the values will be read and a ServiceError will be thrown. + * + * @param modelNode the functionally constrained model node that is to be read. + * @throws ServiceError if a ServiceError is returned by the server. + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public void getDataValues(FcModelNode modelNode) throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructGetDataValuesRequest(modelNode); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + decodeGetDataValuesResponse(confirmedServiceResponse, modelNode); + } + + private boolean decodeGetFileDirectoryResponse( + ConfirmedServiceResponse confirmedServiceResponse, List files) + throws ServiceError { + if (confirmedServiceResponse.getFileDirectory() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding GetFileDirectoryResponsePdu"); + } + + FileDirectoryResponse fileDirectoryRes = confirmedServiceResponse.getFileDirectory(); + + List entries = fileDirectoryRes.getListOfDirectoryEntry().getDirectoryEntry(); + + for (DirectoryEntry entry : entries) { + List graphicStrings = entry.getFileName().getBerGraphicString(); + + StringBuilder filename = new StringBuilder(); + + for (BerGraphicString bgs : graphicStrings) { + filename.append(bgs.toString()); + } + + long fileSize = entry.getFileAttributes().getSizeOfFile().longValue(); + + Calendar lastModified = null; + + try { + + if (entry.getFileAttributes().getLastModified() != null) { + lastModified = entry.getFileAttributes().getLastModified().asCalendar(); + } + + } catch (ParseException e) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding GetFileDirectoryResponsePdu"); + } + + FileInformation fileInfo = new FileInformation(filename.toString(), fileSize, lastModified); + + files.add(fileInfo); + } + + boolean moreFollows = + (fileDirectoryRes.getMoreFollows() != null) && fileDirectoryRes.getMoreFollows().value; + + return moreFollows; + } + + /** + * Read the file directory of the server + * + * @param directoryName name of a directory or empty string for the root directory + * @return the list of available + * @throws ServiceError if a ServiceError is returned by the server or parsing of response failed. + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public List getFileDirectory(String directoryName) + throws ServiceError, IOException { + List files = new ArrayList<>(); + + boolean moreFollows = true; + + String continueAfter = null; + + while (moreFollows) { + + FileDirectoryRequest fileDirectoryRequest = new FileDirectoryRequest(); + + BerGraphicString berGraphicString = new BerGraphicString(directoryName.getBytes(UTF_8)); + + FileName fileSpecification = new FileName(); + fileSpecification.getBerGraphicString().add(berGraphicString); + + fileDirectoryRequest.setFileSpecification(fileSpecification); + + if (continueAfter != null) { + FileName continueAfterSpecification = new FileName(); + + continueAfterSpecification + .getBerGraphicString() + .add(new BerGraphicString(continueAfter.getBytes(UTF_8))); + + fileDirectoryRequest.setContinueAfter(continueAfterSpecification); + } + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileDirectory(fileDirectoryRequest); + + ConfirmedServiceResponse confirmedServiceResponse = + encodeWriteReadDecode(confirmedServiceRequest); + + moreFollows = decodeGetFileDirectoryResponse(confirmedServiceResponse, files); + + if (moreFollows) { + continueAfter = files.get(files.size() - 1).getFilename(); + } + } + + return files; + } + + /** + * Delete a file from the server + * + * @param filename name of the file to delete + * @throws ServiceError if a ServiceError is returned by the server + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public void deleteFile(String filename) throws ServiceError, IOException { + FileDeleteRequest fileDeleteRequest = new FileDeleteRequest(); + + fileDeleteRequest.getBerGraphicString().add(new BerGraphicString(filename.getBytes(UTF_8))); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileDelete(fileDeleteRequest); + + ConfirmedServiceResponse confirmedServiceResponse = + encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileDelete() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding DeleteFileResponsePdu"); + } + } + + private Integer32 openFile(String filename) throws ServiceError, IOException { + FileOpenRequest fileOpenRequest = new FileOpenRequest(); + + FileName fileSpecification = new FileName(); + fileSpecification.getBerGraphicString().add(new BerGraphicString(filename.getBytes(UTF_8))); + + fileOpenRequest.setFileName(fileSpecification); + fileOpenRequest.setInitialPosition(new Unsigned32(0)); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileOpen(fileOpenRequest); + + ConfirmedServiceResponse confirmedServiceResponse = + encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileOpen() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding FileOpenResponsePdu"); + } + + Integer32 frsmId = confirmedServiceResponse.getFileOpen().getFrsmID(); + + return frsmId; + } + + private boolean readNextFileDataBlock(Integer32 frsmId, GetFileListener listener) + throws ServiceError, IOException { + FileReadRequest fileReadRequest = new FileReadRequest(frsmId.longValue()); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileRead(fileReadRequest); + + ConfirmedServiceResponse confirmedServiceResponse = + encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileRead() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding FileReadResponsePdu"); + } + + byte[] fileData = confirmedServiceResponse.getFileRead().getFileData().value; + + boolean moreFollows = true; + + if (confirmedServiceResponse.getFileRead().getMoreFollows() != null) { + moreFollows = confirmedServiceResponse.getFileRead().getMoreFollows().value; + } + + if (listener != null) { + boolean continueRead = listener.dataReceived(fileData, moreFollows); + + if (moreFollows == true) { + moreFollows = continueRead; + } + } + + return moreFollows; + } + + private void closeFile(Integer32 frsmId) throws ServiceError, IOException { + FileCloseRequest fileCloseRequest = new FileCloseRequest(frsmId.longValue()); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileClose(fileCloseRequest); + + ConfirmedServiceResponse confirmedServiceResponse = + encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileClose() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding FileCloseResponsePdu"); + } + } + + /** + * Read a file from the server + * + * @param filename name of the file to delete + * @param listener callback handler to receive fall data + * @throws ServiceError if a ServiceError is returned by the server + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public void getFile(String filename, GetFileListener listener) throws ServiceError, IOException { + Integer32 frsmId = openFile(filename); + + boolean moreFollows = true; + + while (moreFollows) { + moreFollows = readNextFileDataBlock(frsmId, listener); + } + + closeFile(frsmId); + } + + /** + * Will update all data inside the model except for control variables (those that have FC=CO). + * Control variables are not meant to be read. Update is done by calling getDataValues on the + * FCDOs below the Logical Nodes. + * + * @throws ServiceError if a ServiceError is returned by the server. + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public void getAllDataValues() throws ServiceError, IOException { + for (ModelNode logicalDevice : serverModel.getChildren()) { + for (ModelNode logicalNode : logicalDevice.getChildren()) { + for (ModelNode dataObject : logicalNode.getChildren()) { + FcModelNode fcdo = (FcModelNode) dataObject; + if (fcdo.getFc() != Fc.CO && fcdo.getFc() != Fc.SE) { + try { + getDataValues(fcdo); + } catch (ServiceError e) { + throw new ServiceError( + e.getErrorCode(), + "service error retrieving " + + fcdo.getReference() + + "[" + + fcdo.getFc() + + "]" + + ", " + + e.getMessage(), + e); + } + } + } + } + } + } + + private ConfirmedServiceRequest constructGetDataValuesRequest(FcModelNode modelNode) { + VariableAccessSpecification varAccessSpec = constructVariableAccessSpecification(modelNode); + + ReadRequest readRequest = new ReadRequest(); + readRequest.setVariableAccessSpecification(varAccessSpec); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setRead(readRequest); + + return confirmedServiceRequest; + } + + private void decodeGetDataValuesResponse( + ConfirmedServiceResponse confirmedServiceResponse, ModelNode modelNode) throws ServiceError { + + if (confirmedServiceResponse.getRead() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding GetDataValuesReponsePdu"); + } + + List listOfAccessResults = + confirmedServiceResponse.getRead().getListOfAccessResult().getAccessResult(); + + if (listOfAccessResults.size() != 1) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, "Multiple results received."); + } + + AccessResult accRes = listOfAccessResults.get(0); + + if (accRes.getFailure() != null) { + throw mmsDataAccessErrorToServiceError(accRes.getFailure()); + } + modelNode.setValueFromMmsDataObj(accRes.getSuccess()); + } + + /** + * The implementation of the SetDataValues ACSI service. Will send an MMS write request with the + * values of all Basic Data Attributes of the given model node. Will simply return if all values + * have been successfully written. If one of the Basic Data Attributes could not be written then a + * ServiceError will be thrown. In this case it is not possible to find out which of + * several Basic Data Attributes could not be written. + * + * @param modelNode the functionally constrained model node that is to be written. + * @throws ServiceError if a ServiceError is returned by the server. + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public void setDataValues(FcModelNode modelNode) throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructSetDataValuesRequest(modelNode); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + decodeSetDataValuesResponse(confirmedServiceResponse); + } + + private ConfirmedServiceRequest constructSetDataValuesRequest(FcModelNode modelNode) + throws ServiceError { + + VariableAccessSpecification variableAccessSpecification = + constructVariableAccessSpecification(modelNode); + + ListOfData listOfData = new ListOfData(); + List dataList = listOfData.getData(); + dataList.add(modelNode.getMmsDataObj()); + + WriteRequest writeRequest = new WriteRequest(); + writeRequest.setListOfData(listOfData); + writeRequest.setVariableAccessSpecification(variableAccessSpecification); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setWrite(writeRequest); + + return confirmedServiceRequest; + } + + private VariableAccessSpecification constructVariableAccessSpecification(FcModelNode modelNode) { + VariableDefs listOfVariable = new VariableDefs(); + + List variableDefsSeqOf = listOfVariable.getSEQUENCE(); + variableDefsSeqOf.add(modelNode.getMmsVariableDef()); + + VariableAccessSpecification variableAccessSpecification = new VariableAccessSpecification(); + variableAccessSpecification.setListOfVariable(listOfVariable); + + return variableAccessSpecification; + } + + private void decodeSetDataValuesResponse(ConfirmedServiceResponse confirmedServiceResponse) + throws ServiceError { + + WriteResponse writeResponse = confirmedServiceResponse.getWrite(); + + if (writeResponse == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "SetDataValuesResponse: improper response"); + } + + WriteResponse.CHOICE subChoice = writeResponse.getCHOICE().get(0); + + if (subChoice.getFailure() != null) { + throw mmsDataAccessErrorToServiceError(subChoice.getFailure()); + } + } + + /** + * This function will get the definition of all persistent DataSets from the server and update the + * DataSets in the ServerModel that was returned by {@code retrieveModel} or set using {@code + * setServerModel}. It will delete DataSets that have been deleted since the last update and add + * any new DataSets + * + * @throws ServiceError if a ServiceError is returned by the server. + * @throws IOException if a fatal association error occurs. The association object will be closed + * and can no longer be used after this exception is thrown. + */ + public void updateDataSets() throws ServiceError, IOException { + + if (serverModel == null) { + throw new IllegalStateException( + "Before calling this function you have to get the ServerModel using the retrieveModel() function"); + } + + Collection lds = serverModel.getChildren(); + + for (ModelNode ld : lds) { + ConfirmedServiceRequest serviceRequest = + constructGetDirectoryRequest(ld.getName(), "", false); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + decodeAndRetrieveDsNamesAndDefinitions(confirmedServiceResponse, (LogicalDevice) ld); + } + } + + private void decodeAndRetrieveDsNamesAndDefinitions( + ConfirmedServiceResponse confirmedServiceResponse, LogicalDevice ld) + throws ServiceError, IOException { + + if (confirmedServiceResponse.getGetNameList() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "decodeGetDataSetResponse: Error decoding server response"); + } + + GetNameListResponse getNameListResponse = confirmedServiceResponse.getGetNameList(); + + List identifiers = getNameListResponse.getListOfIdentifier().getIdentifier(); + + if (identifiers.size() == 0) { + return; + } + + for (Identifier identifier : identifiers) { + // TODO delete DataSets that no longer exist + getDataSetDirectory(identifier, ld); + } + + if (getNameListResponse.getMoreFollows() != null + && getNameListResponse.getMoreFollows().value == true) { + throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT); + } + } + + private void getDataSetDirectory(Identifier dsId, LogicalDevice ld) + throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructGetDataSetDirectoryRequest(dsId, ld); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + decodeGetDataSetDirectoryResponse(confirmedServiceResponse, dsId, ld); + } + + private ConfirmedServiceRequest constructGetDataSetDirectoryRequest( + Identifier dsId, LogicalDevice ld) throws ServiceError { + ObjectName.DomainSpecific domainSpecificObjectName = new ObjectName.DomainSpecific(); + domainSpecificObjectName.setDomainID(new Identifier(ld.getName().getBytes(UTF_8))); + domainSpecificObjectName.setItemID(dsId); + + GetNamedVariableListAttributesRequest dataSetObj = new GetNamedVariableListAttributesRequest(); + dataSetObj.setDomainSpecific(domainSpecificObjectName); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setGetNamedVariableListAttributes(dataSetObj); + + return confirmedServiceRequest; + } + + private void decodeGetDataSetDirectoryResponse( + ConfirmedServiceResponse confirmedServiceResponse, BerVisibleString dsId, LogicalDevice ld) + throws ServiceError { + + if (confirmedServiceResponse.getGetNamedVariableListAttributes() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "decodeGetDataSetDirectoryResponse: Error decoding server response"); + } + + GetNamedVariableListAttributesResponse getNamedVariableListAttResponse = + confirmedServiceResponse.getGetNamedVariableListAttributes(); + boolean deletable = getNamedVariableListAttResponse.getMmsDeletable().value; + List variables = + getNamedVariableListAttResponse.getListOfVariable().getSEQUENCE(); + + if (variables.size() == 0) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "decodeGetDataSetDirectoryResponse: Instance not available"); + } + + List dsMems = new ArrayList<>(); + + for (VariableDefs.SEQUENCE variableDef : variables) { + + FcModelNode member; + // TODO remove this try catch statement once all possible FCs are + // supported + // it is only there so that Functional Constraints such as GS will + // be ignored and DataSet cotaining elements with these FCs are + // ignored and not created. + try { + member = serverModel.getNodeFromVariableDef(variableDef); + } catch (ServiceError e) { + return; + } + if (member == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "decodeGetDataSetDirectoryResponse: data set memeber does not exist, you might have to call retrieveModel first"); + } + dsMems.add(member); + } + + String dsObjRef = ld.getName() + "/" + dsId.toString().replace('$', '.'); + + DataSet dataSet = new DataSet(dsObjRef, dsMems, deletable); + + if (ld.getChild(dsId.toString().substring(0, dsId.toString().indexOf('$'))) == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "decodeGetDataSetDirectoryResponse: LN for returned DataSet is not available"); + } + + DataSet existingDs = serverModel.getDataSet(dsObjRef); + if (existingDs == null) { + serverModel.addDataSet(dataSet); + } else if (!existingDs.isDeletable()) { + return; + } else { + serverModel.removeDataSet(dsObjRef); + serverModel.addDataSet(dataSet); + } + } + + /** + * The client should create the data set first and add it to either the non-persistent list or to + * the model. Then it should call this method for creation on the server side + * + * @param dataSet the data set to be created on the server side + * @throws ServiceError if a ServiceError is returned by the server. + * @throws IOException if a fatal IO error occurs. The association object will be closed and can + * no longer be used after this exception is thrown. + */ + public void createDataSet(DataSet dataSet) throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructCreateDataSetRequest(dataSet); + encodeWriteReadDecode(serviceRequest); + handleCreateDataSetResponse(dataSet); + } + + /** + * dsRef = either LD/LN.DataSetName (persistent) or @DataSetname (non-persistent) Names in + * dsMemberRef should be in the form: LD/LNName.DoName or LD/LNName.DoName.DaName + */ + private ConfirmedServiceRequest constructCreateDataSetRequest(DataSet dataSet) + throws ServiceError { + + VariableDefs listOfVariable = new VariableDefs(); + + List variableDefs = listOfVariable.getSEQUENCE(); + for (FcModelNode dsMember : dataSet) { + variableDefs.add(dsMember.getMmsVariableDef()); + } + + DefineNamedVariableListRequest createDSRequest = new DefineNamedVariableListRequest(); + createDSRequest.setVariableListName(dataSet.getMmsObjectName()); + createDSRequest.setListOfVariable(listOfVariable); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setDefineNamedVariableList(createDSRequest); + + return confirmedServiceRequest; + } + + private void handleCreateDataSetResponse(DataSet dataSet) throws ServiceError { + serverModel.addDataSet(dataSet); + } + + public void deleteDataSet(DataSet dataSet) throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructDeleteDataSetRequest(dataSet); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + decodeDeleteDataSetResponse(confirmedServiceResponse, dataSet); + } + + private ConfirmedServiceRequest constructDeleteDataSetRequest(DataSet dataSet) + throws ServiceError { + + ListOfVariableListName listOfVariableListName = new ListOfVariableListName(); + + List objectList = listOfVariableListName.getObjectName(); + objectList.add(dataSet.getMmsObjectName()); + + DeleteNamedVariableListRequest requestDeleteDS = new DeleteNamedVariableListRequest(); + requestDeleteDS.setListOfVariableListName(listOfVariableListName); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setDeleteNamedVariableList(requestDeleteDS); + + return confirmedServiceRequest; + } + + private void decodeDeleteDataSetResponse( + ConfirmedServiceResponse confirmedServiceResponse, DataSet dataSet) throws ServiceError { + + if (confirmedServiceResponse.getDeleteNamedVariableList() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "decodeDeleteDataSetResponse: Error decoding server response"); + } + + DeleteNamedVariableListResponse deleteNamedVariableListResponse = + confirmedServiceResponse.getDeleteNamedVariableList(); + + if (deleteNamedVariableListResponse.getNumberDeleted().intValue() != 1) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "number deleted not 1"); + } + + if (serverModel.removeDataSet(dataSet.getReferenceStr()) == null) { + throw new ServiceError(ServiceError.UNKNOWN, "unable to delete dataset locally"); + } + } + + /** + * The implementation of the GetDataSetValues ACSI service. After a successful return, the Basic + * Data Attributes of the data set members will contain the values read. If one of the data set + * members could not be read, this will be indicated in the returned list. The returned list will + * have the same size as the member list of the data set. For each member it will contain + * null if reading was successful and a ServiceError if reading of this member failed. + * + * @param dataSet the DataSet that is to be read. + * @return a list indicating ServiceErrors that may have occurred. + * @throws IOException if a fatal IO error occurs. The association object will be closed and can + * no longer be used after this exception is thrown. + */ + public List getDataSetValues(DataSet dataSet) throws IOException { + + ConfirmedServiceResponse confirmedServiceResponse; + try { + ConfirmedServiceRequest serviceRequest = constructGetDataSetValuesRequest(dataSet); + confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + } catch (ServiceError e) { + int dataSetSize = dataSet.getMembers().size(); + List serviceErrors = new ArrayList<>(dataSetSize); + for (int i = 0; i < dataSetSize; i++) { + serviceErrors.add(e); + } + return serviceErrors; + } + return decodeGetDataSetValuesResponse(confirmedServiceResponse, dataSet); + } + + private ConfirmedServiceRequest constructGetDataSetValuesRequest(DataSet dataSet) + throws ServiceError { + + VariableAccessSpecification varAccSpec = new VariableAccessSpecification(); + varAccSpec.setVariableListName(dataSet.getMmsObjectName()); + + ReadRequest getDataSetValuesRequest = new ReadRequest(); + getDataSetValuesRequest.setSpecificationWithResult(new BerBoolean(true)); + getDataSetValuesRequest.setVariableAccessSpecification(varAccSpec); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setRead(getDataSetValuesRequest); + + return confirmedServiceRequest; + } + + private List decodeGetDataSetValuesResponse( + ConfirmedServiceResponse confirmedServiceResponse, DataSet ds) { + + int dataSetSize = ds.getMembers().size(); + List serviceErrors = new ArrayList<>(dataSetSize); + + if (confirmedServiceResponse.getRead() == null) { + ServiceError serviceError = + new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding GetDataValuesReponsePdu"); + for (int i = 0; i < dataSetSize; i++) { + serviceErrors.add(serviceError); + } + return serviceErrors; + } + + ReadResponse readResponse = confirmedServiceResponse.getRead(); + List listOfAccessResults = readResponse.getListOfAccessResult().getAccessResult(); + + if (listOfAccessResults.size() != ds.getMembers().size()) { + ServiceError serviceError = + new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "Number of AccessResults does not match the number of DataSet members."); + for (int i = 0; i < dataSetSize; i++) { + serviceErrors.add(serviceError); + } + return serviceErrors; + } + + Iterator accessResultIterator = listOfAccessResults.iterator(); + + for (FcModelNode dsMember : ds) { + AccessResult accessResult = accessResultIterator.next(); + if (accessResult.getSuccess() != null) { + try { + dsMember.setValueFromMmsDataObj(accessResult.getSuccess()); + } catch (ServiceError e) { + serviceErrors.add(e); + } + serviceErrors.add(null); + } else { + serviceErrors.add(mmsDataAccessErrorToServiceError(accessResult.getFailure())); + } + } + + return serviceErrors; + } + + public List setDataSetValues(DataSet dataSet) throws ServiceError, IOException { + ConfirmedServiceRequest serviceRequest = constructSetDataSetValues(dataSet); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest); + return decodeSetDataSetValuesResponse(confirmedServiceResponse); + } + + private ConfirmedServiceRequest constructSetDataSetValues(DataSet dataSet) throws ServiceError { + VariableAccessSpecification varAccessSpec = new VariableAccessSpecification(); + varAccessSpec.setVariableListName(dataSet.getMmsObjectName()); + + ListOfData listOfData = new ListOfData(); + List dataList = listOfData.getData(); + + for (ModelNode member : dataSet) { + dataList.add(member.getMmsDataObj()); + } + + WriteRequest writeRequest = new WriteRequest(); + writeRequest.setVariableAccessSpecification(varAccessSpec); + writeRequest.setListOfData(listOfData); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setWrite(writeRequest); + + return confirmedServiceRequest; + } + + private List decodeSetDataSetValuesResponse( + ConfirmedServiceResponse confirmedServiceResponse) throws ServiceError { + + if (confirmedServiceResponse.getWrite() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding SetDataSetValuesReponsePdu"); + } + + WriteResponse writeResponse = confirmedServiceResponse.getWrite(); + List writeResChoiceType = writeResponse.getCHOICE(); + List serviceErrors = new ArrayList<>(writeResChoiceType.size()); + + for (WriteResponse.CHOICE accessResult : writeResChoiceType) { + if (accessResult.getSuccess() != null) { + serviceErrors.add(null); + } else { + serviceErrors.add(mmsDataAccessErrorToServiceError(accessResult.getFailure())); + } + } + return serviceErrors; + } + + public void getRcbValues(Rcb rcb) throws ServiceError, IOException { + getDataValues(rcb); + } + + public void reserveUrcb(Urcb urcb) throws ServiceError, IOException { + BdaBoolean resvBda = urcb.getResv(); + resvBda.setValue(true); + setDataValues(resvBda); + } + + public void reserveBrcb(Brcb brcb, short resvTime) throws ServiceError, IOException { + BdaInt16 resvTmsBda = brcb.getResvTms(); + resvTmsBda.setValue(resvTime); + setDataValues(resvTmsBda); + } + + public void cancelUrcbReservation(Urcb urcb) throws ServiceError, IOException { + BdaBoolean resvBda = urcb.getResv(); + resvBda.setValue(false); + setDataValues(resvBda); + } + + public void enableReporting(Rcb rcb) throws ServiceError, IOException { + BdaBoolean rptEnaBda = rcb.getRptEna(); + rptEnaBda.setValue(true); + setDataValues(rptEnaBda); + } + + public void disableReporting(Rcb rcb) throws ServiceError, IOException { + BdaBoolean rptEnaBda = rcb.getRptEna(); + rptEnaBda.setValue(false); + setDataValues(rptEnaBda); + } + + public void startGi(Rcb rcb) throws ServiceError, IOException { + BdaBoolean rptGiBda = (BdaBoolean) rcb.getChild("GI"); + rptGiBda.setValue(true); + setDataValues(rptGiBda); + } + + /** + * Sets the selected values of the given report control block. Note that all these parameters may + * only be set if the RCB has been reserved but reporting has not been enabled yet. + * + *

The data set reference as it is set in an RCB must contain a dollar sign instead of a dot to + * separate the logical node from the data set name, e.g.: 'LDevice1/LNode$DataSetName'. Therefore + * his method will check the reference for a dot and if necessary convert it to a '$' sign before + * sending the request to the server. + * + *

The parameters PurgeBuf, EntryId are only applicable if the given rcb is of type BRCB. + * + * @param rcb the report control block + * @param setRptId whether to set the report ID + * @param setDatSet whether to set the data set + * @param setOptFlds whether to set the optional fields + * @param setBufTm whether to set the buffer time + * @param setTrgOps whether to set the trigger options + * @param setIntgPd whether to set the integrity period + * @param setPurgeBuf whether to set purge buffer + * @param setEntryId whether to set the entry ID + * @return a list indicating ServiceErrors that may have occurred. + * @throws IOException if a fatal IO error occurs. The association object will be closed and can + * no longer be used after this exception is thrown. + */ + public List setRcbValues( + Rcb rcb, + boolean setRptId, + boolean setDatSet, + boolean setOptFlds, + boolean setBufTm, + boolean setTrgOps, + boolean setIntgPd, + boolean setPurgeBuf, + boolean setEntryId) + throws IOException { + + List parametersToSet = new ArrayList<>(6); + + if (setRptId == true) { + parametersToSet.add(rcb.getRptId()); + } + if (setDatSet == true) { + rcb.getDatSet().setValue(rcb.getDatSet().getStringValue().replace('.', '$')); + parametersToSet.add(rcb.getDatSet()); + } + if (setOptFlds == true) { + parametersToSet.add(rcb.getOptFlds()); + } + if (setBufTm == true) { + parametersToSet.add(rcb.getBufTm()); + } + if (setTrgOps == true) { + parametersToSet.add(rcb.getTrgOps()); + } + if (setIntgPd == true) { + parametersToSet.add(rcb.getIntgPd()); + } + if (rcb instanceof Brcb) { + Brcb brcb = (Brcb) rcb; + if (setPurgeBuf == true) { + parametersToSet.add(brcb.getPurgeBuf()); + } + if (setEntryId == true) { + parametersToSet.add(brcb.getEntryId()); + } + } + + List serviceErrors = new ArrayList<>(parametersToSet.size()); + + for (FcModelNode child : parametersToSet) { + try { + setDataValues(child); + serviceErrors.add(null); + } catch (ServiceError e) { + serviceErrors.add(e); + } + } + + return serviceErrors; + } + + private Report processReport(MMSpdu mmsPdu) throws ServiceError { + + if (mmsPdu.getUnconfirmedPDU() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "getReport: Error decoding server response"); + } + + UnconfirmedPDU unconfirmedRes = mmsPdu.getUnconfirmedPDU(); + + if (unconfirmedRes.getService() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "getReport: Error decoding server response"); + } + + UnconfirmedService unconfirmedServ = unconfirmedRes.getService(); + + if (unconfirmedServ.getInformationReport() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "getReport: Error decoding server response"); + } + + List listRes = + unconfirmedServ.getInformationReport().getListOfAccessResult().getAccessResult(); + + int index = 0; + + if (listRes.get(index).getSuccess().getVisibleString() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "processReport: report does not contain RptID"); + } + + String rptId = listRes.get(index++).getSuccess().getVisibleString().toString(); + + if (listRes.get(index).getSuccess().getBitString() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "processReport: report does not contain OptFlds"); + } + + BdaOptFlds optFlds = new BdaOptFlds(new ObjectReference("none"), null); + optFlds.setValue(listRes.get(index++).getSuccess().getBitString().value); + + Integer sqNum = null; + if (optFlds.isSequenceNumber()) { + sqNum = listRes.get(index++).getSuccess().getUnsigned().intValue(); + } + + BdaEntryTime timeOfEntry = null; + if (optFlds.isReportTimestamp()) { + timeOfEntry = new BdaEntryTime(new ObjectReference("none"), null, "", false, false); + timeOfEntry.setValueFromMmsDataObj(listRes.get(index++).getSuccess()); + } + + String dataSetRef = null; + if (optFlds.isDataSetName()) { + dataSetRef = listRes.get(index++).getSuccess().getVisibleString().toString(); + } else { + for (Urcb urcb : serverModel.getUrcbs()) { + if ((urcb.getRptId() != null && urcb.getRptId().getStringValue().equals(rptId)) + || urcb.getReference().toString().equals(rptId)) { + dataSetRef = urcb.getDatSet().getStringValue(); + break; + } + } + if (dataSetRef == null) { + for (Brcb brcb : serverModel.getBrcbs()) { + if ((brcb.getRptId() != null && brcb.getRptId().getStringValue().equals(rptId)) + || brcb.getReference().toString().equals(rptId)) { + dataSetRef = brcb.getDatSet().getStringValue(); + break; + } + } + } + } + if (dataSetRef == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "unable to find RCB that matches the given RptID in the report."); + } + dataSetRef = dataSetRef.replace('$', '.'); + + DataSet dataSet = serverModel.getDataSet(dataSetRef); + if (dataSet == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "unable to find data set that matches the given data set reference of the report."); + } + + Boolean bufOvfl = null; + if (optFlds.isBufferOverflow()) { + bufOvfl = listRes.get(index++).getSuccess().getBool().value; + } + + BdaOctetString entryId = null; + if (optFlds.isEntryId()) { + entryId = new BdaOctetString(new ObjectReference("none"), null, "", 8, false, false); + entryId.setValue(listRes.get(index++).getSuccess().getOctetString().value); + } + + Long confRev = null; + if (optFlds.isConfigRevision()) { + confRev = listRes.get(index++).getSuccess().getUnsigned().longValue(); + } + + Integer subSqNum = null; + boolean moreSegmentsFollow = false; + if (optFlds.isSegmentation()) { + subSqNum = listRes.get(index++).getSuccess().getUnsigned().intValue(); + moreSegmentsFollow = listRes.get(index++).getSuccess().getBool().value; + } + + boolean[] inclusionBitString = + listRes.get(index++).getSuccess().getBitString().getValueAsBooleans(); + int numMembersReported = 0; + for (boolean bit : inclusionBitString) { + if (bit) { + numMembersReported++; + } + } + + if (optFlds.isDataReference()) { + // this is just to move the index to the right place + // The next part will process the changes to the values + // without the dataRefs + index += numMembersReported; + } + + List reportedDataSetMembers = new ArrayList<>(numMembersReported); + int dataSetIndex = 0; + for (FcModelNode dataSetMember : dataSet.getMembers()) { + if (inclusionBitString[dataSetIndex]) { + AccessResult accessRes = listRes.get(index++); + FcModelNode dataSetMemberCopy = (FcModelNode) dataSetMember.copy(); + dataSetMemberCopy.setValueFromMmsDataObj(accessRes.getSuccess()); + reportedDataSetMembers.add(dataSetMemberCopy); + } + dataSetIndex++; + } + + List reasonCodes = null; + if (optFlds.isReasonForInclusion()) { + reasonCodes = new ArrayList<>(dataSet.getMembers().size()); + for (int i = 0; i < dataSet.getMembers().size(); i++) { + if (inclusionBitString[i]) { + BdaReasonForInclusion reasonForInclusion = new BdaReasonForInclusion(null); + reasonCodes.add(reasonForInclusion); + byte[] reason = listRes.get(index++).getSuccess().getBitString().value; + reasonForInclusion.setValue(reason); + } + } + } + + return new Report( + rptId, + sqNum, + subSqNum, + moreSegmentsFollow, + dataSetRef, + bufOvfl, + confRev, + timeOfEntry, + entryId, + inclusionBitString, + reportedDataSetMembers, + reasonCodes); + } + + /** + * Performs the Select ACSI Service of the control model on the given controllable Data Object + * (DO). By selecting a controllable DO you can reserve it for exclusive control/operation. This + * service is only applicable if the ctlModel Data Attribute is set to "sbo-with-normal-security" + * (2). + * + *

The selection is canceled in one of the following events: + * + *

    + *
  • The "Cancel" ACSI service is issued. + *
  • The sboTimemout (select before operate timeout) runs out. If the given controlDataObject + * contains a sboTimeout Data Attribute it is possible to change the timeout after which the + * selection/reservation is automatically canceled by the server. Otherwise the timeout is a + * local issue of the server. + *
  • The connection to the server is closed. + *
  • An operate service failed because of some error + *
  • The sboClass is set to "operate-once" then the selection is also canceled after a + * successful operate service. + *
+ * + * @param controlDataObject needs to be a controllable Data Object that contains a Data Attribute + * named "SBO". + * @return false if the selection/reservation was not successful (because it is already selected + * by another client). Otherwise true is returned. + * @throws ServiceError if a ServiceError is returned by the server. + * @throws IOException if a fatal IO error occurs. The association object will be closed and can + * no longer be used after this exception is thrown. + */ + public boolean select(FcModelNode controlDataObject) throws ServiceError, IOException { + BdaVisibleString sbo; + try { + sbo = (BdaVisibleString) controlDataObject.getChild("SBO"); + } catch (Exception e) { + throw new IllegalArgumentException( + "ModelNode needs to conain a child node named SBO in order to select"); + } + + getDataValues(sbo); + + return sbo.getValue().length != 0; + } + + /** + * Executes the Operate ACSI Service on the given controllable Data Object (DO). The following + * subnodes of the given control DO should be set according your needs before calling this + * function. (Note that you can probably leave most attributes with their default value): + * + *
    + *
  • Oper.ctlVal - has to be set to actual control value that is to be written using the + * operate service. + *
  • Oper.operTm (type: BdaTimestamp) - is an optional sub data attribute of Oper (thus it may + * not exist). If it exists it can be used to set the timestamp when the operation shall be + * performed by the server. Thus the server will delay execution of the operate command + * until the given date is reached. Can be set to an empty byte array (new byte[0]) or null + * so that the server executes the operate command immediately. This is also the default. + *
  • Oper.check (type: BdaCheck) is used to tell the server whether to perform the + * synchrocheck and interlockcheck. By default they are turned off. + *
  • Oper.orign - contains the two data attributes orCat (origin category, type: BdaInt8) and + * orIdent (origin identifier, type BdaOctetString). Origin is optionally reflected in the + * status Data Attribute controlDO.origin. By reading this data attribute other clients can + * see who executed the last operate command. The default value for orCat is 0 + * ("not-supported") and the default value for orIdent is ""(the empty string). + *
  • Oper.Test (BdaBoolean) - if true this operate command is sent for test purposes only. + * Default is false. + *
+ * + * All other operate parameters are automatically handled by this function. + * + * @param controlDataObject needs to be a controllable Data Object that contains a Data Attribute + * named "Oper". + * @throws ServiceError if a ServiceError is returned by the server + * @throws IOException if a fatal IO error occurs. The association object will be closed and can + * no longer be used after this exception is thrown. + */ + public void operate(FcModelNode controlDataObject) throws ServiceError, IOException { + ConstructedDataAttribute oper; + try { + oper = (ConstructedDataAttribute) controlDataObject.getChild("Oper"); + } catch (Exception e) { + throw new IllegalArgumentException("ModelNode needs to conain a child node named \"Oper\"."); + } + + ((BdaInt8U) oper.getChild("ctlNum")).setValue((short) 1); + ((BdaTimestamp) oper.getChild("T")).setInstant(Instant.now()); + + setDataValues(oper); + } + + public boolean isOpen() { + return !closed; + } + + /** Will close the connection simply by closing the TCP socket. */ + public void close() { + clientReceiver.close(new IOException("Connection closed by client")); + } + + /** Will send a disconnect request first and then close the TCP socket. */ + public void disconnect() { + clientReceiver.disconnect(); + } + + final class ClientReceiver extends Thread { + + private final ByteBuffer pduBuffer; + private Integer expectedResponseId; + private IOException lastIOException = null; + + public ClientReceiver(int maxMmsPduSize) { + pduBuffer = ByteBuffer.allocate(maxMmsPduSize + 400); + } + + @Override + public void run() { + try { + while (true) { + + pduBuffer.clear(); + byte[] buffer; + try { + buffer = acseAssociation.receive(pduBuffer); + } catch (TimeoutException e) { + // Illegal state: A timeout exception was thrown. + throw new IllegalStateException(); + } catch (DecodingException e) { + // Error decoding the OSI headers of the received packet + continue; + } + + MMSpdu decodedResponsePdu = new MMSpdu(); + try { + decodedResponsePdu.decode(new ByteArrayInputStream(buffer), null); + } catch (IOException e) { + // Error decoding the received MMS PDU + continue; + } + + if (decodedResponsePdu.getUnconfirmedPDU() != null) { + if (decodedResponsePdu + .getUnconfirmedPDU() + .getService() + .getInformationReport() + .getVariableAccessSpecification() + .getListOfVariable() + != null) { + // Discarding LastApplError Report + } else { + if (reportListener != null) { + final Report report = processReport(decodedResponsePdu); + + Thread t1 = + new Thread( + new Runnable() { + @Override + public void run() { + reportListener.newReport(report); + } + }); + t1.start(); + } else { + // discarding report because no ReportListener was registered. + } + } + } else if (decodedResponsePdu.getRejectPDU() != null) { + synchronized (incomingResponses) { + if (expectedResponseId == null) { + // Discarding Reject MMS PDU because no listener for request was found. + continue; + } else if (decodedResponsePdu.getRejectPDU().getOriginalInvokeID().value.intValue() + != expectedResponseId) { + // Discarding Reject MMS PDU because no listener with fitting invokeID was found. + continue; + } else { + try { + incomingResponses.put(decodedResponsePdu); + } catch (InterruptedException e) { + // TODO can this ever be interrupted? + } + } + } + } else if (decodedResponsePdu.getConfirmedErrorPDU() != null) { + synchronized (incomingResponses) { + if (expectedResponseId == null) { + // Discarding ConfirmedError MMS PDU because no listener for request was found. + continue; + } else if (decodedResponsePdu.getConfirmedErrorPDU().getInvokeID().value.intValue() + != expectedResponseId) { + // Discarding ConfirmedError MMS PDU because no listener with fitting invokeID was + // found. + continue; + } else { + try { + incomingResponses.put(decodedResponsePdu); + } catch (InterruptedException e) { + // TODO can this ever be interrupted? + } + } + } + } else { + synchronized (incomingResponses) { + if (expectedResponseId == null) { + // Discarding ConfirmedResponse MMS PDU because no listener for request was found. + continue; + } else if (decodedResponsePdu.getConfirmedResponsePDU().getInvokeID().value.intValue() + != expectedResponseId) { + // Discarding ConfirmedResponse MMS PDU because no listener with fitting invokeID + // was + // found. + continue; + } else { + try { + incomingResponses.put(decodedResponsePdu); + } catch (InterruptedException e) { + // TODO can this ever be interrupted? + } + } + } + } + } + } catch (IOException e) { + close(e); + } catch (Exception e) { + close(new IOException("unexpected exception while receiving", e)); + } + } + + public void setResponseExpected(int invokeId) { + expectedResponseId = invokeId; + } + + private void disconnect() { + synchronized (this) { + if (closed == false) { + closed = true; + acseAssociation.disconnect(); + lastIOException = new IOException("Connection disconnected by client"); + if (reportListener != null) { + Thread t1 = + new Thread( + new Runnable() { + @Override + public void run() { + reportListener.associationClosed(lastIOException); + } + }); + t1.start(); + } + + MMSpdu mmsPdu = new MMSpdu(); + mmsPdu.setConfirmedRequestPDU(new ConfirmedRequestPDU()); + try { + incomingResponses.put(mmsPdu); + } catch (InterruptedException e1) { + // TODO can this ever be interrupted? + } + } + } + } + + private void close(IOException e) { + synchronized (this) { + if (closed == false) { + closed = true; + acseAssociation.close(); + lastIOException = e; + if (reportListener != null) { + Thread t1 = + new Thread( + new Runnable() { + @Override + public void run() { + reportListener.associationClosed(lastIOException); + } + }); + t1.start(); + } + + MMSpdu mmsPdu = new MMSpdu(); + mmsPdu.setConfirmedRequestPDU(new ConfirmedRequestPDU()); + try { + incomingResponses.put(mmsPdu); + } catch (InterruptedException e1) { + // TODO can this ever be interrupted? + } + } + } + } + + IOException getLastIOException() { + return lastIOException; + } + + MMSpdu removeExpectedResponse() { + synchronized (incomingResponses) { + expectedResponseId = null; + return incomingResponses.poll(); + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ClientEventListener.java b/src/main/java/com/beanit/iec61850bean/ClientEventListener.java new file mode 100644 index 0000000..4507aaf --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ClientEventListener.java @@ -0,0 +1,44 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.io.IOException; + +/** + * The listener interface for receiving incoming reports and association closed events. A listener + * is registered through the {@link ClientSap#associate(java.net.InetAddress, int, String, + * ClientEventListener) associate} method. + * + * @author Stefan Feuerhahn + */ +public interface ClientEventListener { + + /** + * Invoked when a new report arrives. Note that the implementation of this method needs to be + * thread safe as it can be called in parallel if a new report arrives while an old one is still + * being processed. + * + * @param report the report that arrived. + */ + void newReport(Report report); + + /** + * Invoked when an IOException occurred for the association. An IOException implies that the + * ClientAssociation that feeds this listener was automatically closed and can no longer be used + * to receive reports. + * + * @param e the exception that occured. + */ + void associationClosed(IOException e); +} diff --git a/src/main/java/com/beanit/iec61850bean/ClientSap.java b/src/main/java/com/beanit/iec61850bean/ClientSap.java new file mode 100644 index 0000000..c67f771 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ClientSap.java @@ -0,0 +1,346 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.josistack.ClientAcseSap; +import java.io.IOException; +import java.net.InetAddress; +import javax.net.SocketFactory; + +/** + * The ClientSap class represents the IEC 61850 service access point for client + * applications. A client application that wants to connect to a server should first create an + * instance of ClientSap. Next all the necessary configuration parameters can be set. + * Finally the associate function is called to connect to the server. An instance of + * ClientSap can be used to create an unlimited number of associations. Changing the + * parameters of a ClientSap has no affect on associations that have already been created. + */ +public final class ClientSap { + + static final int MINIMUM_MMS_PDU_SIZE = 64; + private static final int MAXIMUM_MMS_PDU_SIZE = 65000; + + private static final byte[] DEFAULT_TSEL_LOCAL = new byte[] {0, 0}; + private static final byte[] DEFAULT_TSEL_REMOTE = new byte[] {0, 1}; + private static final int DEFAULT_TPDU_SIZE_PARAMETER = 10; // size = 1024 + private final ClientAcseSap acseSap; + private int proposedMaxServOutstandingCalling = 5; + private int proposedMaxServOutstandingCalled = 5; + private int proposedDataStructureNestingLevel = 10; + private int proposedMaxMmsPduSize = 65000; + private byte[] servicesSupportedCalling = + new byte[] {(byte) 0xee, 0x1c, 0, 0, 0x04, 0x08, 0, 0, 0x79, (byte) 0xef, 0x18}; + private int messageFragmentTimeout = 10000; + private int responseTimeout = 20000; + + /** Use this constructor to create a default client SAP. */ + public ClientSap() { + acseSap = new ClientAcseSap(); + acseSap.tSap.tSelLocal = DEFAULT_TSEL_LOCAL; + acseSap.tSap.tSelRemote = DEFAULT_TSEL_REMOTE; + acseSap.tSap.setMaxTPDUSizeParam(DEFAULT_TPDU_SIZE_PARAMETER); + } + + /** + * Use this constructor to create a client SAP that uses the given SocketFactory to + * connect to servers. You could pass an SSLSocketFactory to enable SSL. + * + * @param socketFactory the socket factory to construct the socket + */ + public ClientSap(SocketFactory socketFactory) { + acseSap = new ClientAcseSap(socketFactory); + acseSap.tSap.tSelLocal = DEFAULT_TSEL_LOCAL; + acseSap.tSap.tSelRemote = DEFAULT_TSEL_REMOTE; + acseSap.tSap.setMaxTPDUSizeParam(DEFAULT_TPDU_SIZE_PARAMETER); + } + + /** + * Gets the maximum MMS PDU size. + * + * @return the maximum MMS PDU size. + */ + public int getMaxMmsPduSize() { + return proposedMaxMmsPduSize; + } + + /** + * Sets the maximum MMS PDU size in bytes that the client association will support. The client + * proposes this value to the server during association. If the server requires the use of a + * smaller maximum MMS PDU size, then the smaller size will be accepted by the client. The default + * size is 65000. + * + * @param size cannot be less than 64. The upper limit is 65000 so that segmentation at the lower + * transport layer is avoided. The Transport Layer's maximum PDU size is 65531. + */ + public void setMaxMmsPduSize(int size) { + if (size >= MINIMUM_MMS_PDU_SIZE && size <= MAXIMUM_MMS_PDU_SIZE) { + proposedMaxMmsPduSize = size; + } else { + throw new IllegalArgumentException("maximum size is out of bound"); + } + } + + public void setProposedMaxServOutstandingCalling(int proposedMaxServOutstandingCalling) { + this.proposedMaxServOutstandingCalling = proposedMaxServOutstandingCalling; + } + + public void setProposedMaxServOutstandingCalled(int proposedMaxServOutstandingCalled) { + this.proposedMaxServOutstandingCalled = proposedMaxServOutstandingCalled; + } + + public void setProposedDataStructureNestingLevel(int proposedDataStructureNestingLevel) { + this.proposedDataStructureNestingLevel = proposedDataStructureNestingLevel; + } + + /** + * Gets the ServicesSupportedCalling parameter. + * + * @return the ServicesSupportedCalling parameter. + */ + public byte[] getServicesSupportedCalling() { + return servicesSupportedCalling; + } + + /** + * Sets the SevicesSupportedCalling parameter. The given parameter is sent to the server but has + * no affect on the functionality of this client. + * + * @param services the ServicesSupportedCalling parameter + */ + public void setServicesSupportedCalling(byte[] services) { + if (services.length != 11) { + throw new IllegalArgumentException("The services parameter needs to be of lenth 11"); + } + servicesSupportedCalling = services; + } + + /** + * Sets the remote/called Session-Selector (S-SEL). The default remote S-SEL is byte[] { 0, 1 }. + * + * @param sSelRemote the remote/called S-SEL. + */ + public void setSSelRemote(byte[] sSelRemote) { + acseSap.sSelRemote = sSelRemote; + } + + /** + * Sets the local/calling Session-Selector (S-SEL). The default local S-SEL is byte[] { 0, 1 }. + * + * @param sSelLocal the local/calling S-SEL. + */ + public void setSSelLocal(byte[] sSelLocal) { + acseSap.sSelLocal = sSelLocal; + } + + /** + * Sets the remote/called Presentation-Selector (P-SEL). The default remote P-SEL is byte[] { 0, + * 0, 0, 1 }. + * + * @param pSelRemote the remote/called P-SEL. + */ + public void setPSelRemote(byte[] pSelRemote) { + acseSap.pSelRemote = pSelRemote; + } + + /** + * Sets the local/calling Presentation-Selector (P-SEL). The default local P-SEL is byte[] { 0, 0, + * 0, 1 }. + * + * @param pSelLocal the local/calling P-SEL. + */ + public void setPSelLocal(byte[] pSelLocal) { + acseSap.pSelLocal = pSelLocal; + } + + /** + * Sets the remote/called Transport-Selector (T-SEL). It is optionally transmitted in the OSI + * Transport Layer connection request (CR). The default remote T-SEL is byte[] { 0, 1 }. + * + * @param tSelRemote the remote/called T-SEL. If null the T-SEL will be omitted. No maximum size + * is defined by the standard. + */ + public void setTSelRemote(byte[] tSelRemote) { + acseSap.tSap.tSelRemote = tSelRemote; + } + + /** + * Sets the local/calling Transport-Selector (T-SEL). It is optionally transmitted in the OSI + * Transport Layer connection request (CR). The default local T-SEL byte[] { 0, 0 }. + * + * @param tSelLocal the local/calling T-SEL. If null the T-SEL will be omitted. No maximum size is + * defined by the standard. + */ + public void setTSelLocal(byte[] tSelLocal) { + acseSap.tSap.tSelLocal = tSelLocal; + } + + /** + * Set the maxTPDUSize. The default maxTPduSize is 65531 (see RFC 1006). + * + * @param maxTPduSizeParam The maximum length is equal to 2^(maxTPduSizeParam) octets. Note that + * the actual TSDU size that can be transfered is equal to TPduSize-3. Default is 65531 octets + * (see RFC 1006), 7 <= maxTPduSizeParam <= 16, needs to be set before listening or + * connecting + */ + public void setMaxTPduSizeParameter(int maxTPduSizeParam) { + acseSap.tSap.setMaxTPDUSizeParam(maxTPduSizeParam); + } + + /** + * Sets the remote/called Application Process Title. The default value is int[] { 1, 1, 999, 1, 1 + * } + * + * @param title the remote/called AP title. + */ + public void setApTitleCalled(int[] title) { + acseSap.setApTitleCalled(title); + } + + /** + * Sets the local/calling Application Process Title. The default value is int[] { 1, 1, 999, 1 } + * + * @param title the local/calling AP title. + */ + public void setApTitleCalling(int[] title) { + acseSap.setApTitleCalling(title); + } + + /** + * Sets the remote/called Application Entity Qualifier. The default value is 12. + * + * @param qualifier the remote/called AE Qualifier + */ + public void setAeQualifierCalled(int qualifier) { + acseSap.setAeQualifierCalled(qualifier); + } + + /** + * Sets the local/calling Application Entity Qualifier. The default value is 12. + * + * @param qualifier the local/calling AE Qualifier + */ + public void setAeQualifierCalling(int qualifier) { + acseSap.setAeQualifierCalling(qualifier); + } + + /** + * Sets the default response timeout of the ClientAssociation that is created using + * this ClientSap. + * + * @param timeout the response timeout in milliseconds. The default is 20000. + */ + public void setResponseTimeout(int timeout) { + responseTimeout = timeout; + } + + /** + * Sets the message fragment timeout. This is the timeout that the socket timeout is set to after + * the first byte of a message has been received. A request function (e.g. setDataValues()) will + * throw an IOException if the socket throws this timeout because the association/connection + * cannot recover from this kind of error. + * + * @param timeout the timeout in milliseconds. The default is 10000. + */ + public void setMessageFragmentTimeout(int timeout) { + messageFragmentTimeout = timeout; + } + + /** + * Connects to the IEC 61850 MMS server at the given address and port and returns the resulting + * association object. + * + * @param address the address to connect to. + * @param port the port to connect to. Usually the MMS port is 102. + * @param authenticationParameter an optional authentication parameters that is transmitted. It + * will be omitted if equal to null. + * @param reportListener the listener to be notified of incoming reports + * @return the association object + * @throws IOException if any kind of error occurs trying build up the association + */ + public ClientAssociation associate( + InetAddress address, + int port, + String authenticationParameter, + ClientEventListener reportListener) + throws IOException { + return associate(address, port, authenticationParameter, null, -1, reportListener); + } + + /** + * Connects to the IEC 61850 MMS server at the given address and port and returns the resulting + * association object. + * + * @param address the address to connect to + * @param port the port to connect to. Usually the MMS port is 102. + * @param authenticationParameter an optional authentication parameters that is transmitted. It + * will be omitted if equal to null. + * @param localAddr the local address to use + * @param localPort the local port to use + * @param reportListener the listener to be notified of incoming reports + * @return the association object. + * @throws IOException if any kind of error occurs trying build up the association + */ + public ClientAssociation associate( + InetAddress address, + int port, + String authenticationParameter, + InetAddress localAddr, + int localPort, + ClientEventListener reportListener) + throws IOException { + + if (port < 0 || port > 65535) { + throw new IllegalArgumentException("invalid port"); + } + + if (address == null) { + throw new IllegalArgumentException("address may not be null"); + } + + if (acseSap.sSelRemote == null) { + throw new IllegalArgumentException("sSelRemote may not be null"); + } + + if (acseSap.sSelRemote.length != 2) { + throw new IllegalArgumentException("sSelRemote lenght must be two"); + } + + if (acseSap.sSelLocal == null) { + throw new IllegalArgumentException("sSelLocal may not be null"); + } + + if (acseSap.sSelLocal.length != 2) { + throw new IllegalArgumentException("sSelLocal lenght must be two"); + } + + ClientAssociation clientAssociation = + new ClientAssociation( + address, + port, + localAddr, + localPort, + authenticationParameter, + acseSap, + proposedMaxMmsPduSize, + proposedMaxServOutstandingCalling, + proposedMaxServOutstandingCalled, + proposedDataStructureNestingLevel, + servicesSupportedCalling, + responseTimeout, + messageFragmentTimeout, + reportListener); + + return clientAssociation; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ConstructedDataAttribute.java b/src/main/java/com/beanit/iec61850bean/ConstructedDataAttribute.java new file mode 100644 index 0000000..12c8810 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ConstructedDataAttribute.java @@ -0,0 +1,87 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.Data.Structure; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; + +public final class ConstructedDataAttribute extends FcModelNode { + + public ConstructedDataAttribute( + ObjectReference objectReference, Fc fc, List children) { + this.objectReference = objectReference; + this.fc = fc; + this.children = new LinkedHashMap<>((int) ((children.size() / 0.75) + 1)); + for (ModelNode child : children) { + this.children.put(child.getName(), child); + child.setParent(this); + } + } + + @Override + public ConstructedDataAttribute copy() { + List subDataAttributesCopy = new ArrayList<>(); + for (ModelNode subDA : children.values()) { + subDataAttributesCopy.add((FcModelNode) subDA.copy()); + } + return new ConstructedDataAttribute(getReference(), fc, subDataAttributesCopy); + } + + @Override + Data getMmsDataObj() { + Structure structure = new Structure(); + List seq = structure.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(structure); + + return data; + } + + @Override + 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 iterator = data.getStructure().getData().iterator(); + for (ModelNode child : children.values()) { + child.setValueFromMmsDataObj(iterator.next()); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/DataDefinitionResParser.java b/src/main/java/com/beanit/iec61850bean/DataDefinitionResParser.java new file mode 100644 index 0000000..e9ee458 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/DataDefinitionResParser.java @@ -0,0 +1,274 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceResponse; +import com.beanit.iec61850bean.internal.mms.asn1.GetVariableAccessAttributesResponse; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure.Components; +import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +final class DataDefinitionResParser { + + static LogicalNode parseGetDataDefinitionResponse( + ConfirmedServiceResponse confirmedServiceResponse, ObjectReference lnRef) + throws ServiceError { + + if (confirmedServiceResponse.getGetVariableAccessAttributes() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "decodeGetDataDefinitionResponse: Error decoding GetDataDefinitionResponsePdu"); + } + + GetVariableAccessAttributesResponse varAccAttrs = + confirmedServiceResponse.getGetVariableAccessAttributes(); + TypeDescription typeSpec = varAccAttrs.getTypeDescription(); + if (typeSpec.getStructure() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "decodeGetDataDefinitionResponse: Error decoding GetDataDefinitionResponsePdu"); + } + + Components structure = typeSpec.getStructure().getComponents(); + + List fcDataObjects = new ArrayList<>(); + + Fc fc; + for (TypeDescription.Structure.Components.SEQUENCE fcComponent : structure.getSEQUENCE()) { + if (fcComponent.getComponentName() == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "Error decoding GetDataDefinitionResponsePdu"); + } + + if (fcComponent.getComponentType().getTypeDescription().getStructure() == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "Error decoding GetDataDefinitionResponsePdu"); + } + + String fcString = fcComponent.getComponentName().toString(); + if (fcString.equals("LG") + || fcString.equals("GO") + || fcString.equals("GS") + || fcString.equals("MS") + || fcString.equals("US")) { + continue; + } + + fc = Fc.fromString(fcComponent.getComponentName().toString()); + Components subStructure = + fcComponent.getComponentType().getTypeDescription().getStructure().getComponents(); + + fcDataObjects.addAll(getFcDataObjectsFromSubStructure(lnRef, fc, subStructure)); + } + + LogicalNode ln = new LogicalNode(lnRef, fcDataObjects); + + return ln; + } + + private static List getFcDataObjectsFromSubStructure( + ObjectReference lnRef, Fc fc, Components components) throws ServiceError { + + List structComponents = components.getSEQUENCE(); + List dataObjects = new ArrayList<>(structComponents.size()); + + for (TypeDescription.Structure.Components.SEQUENCE doComp : structComponents) { + if (doComp.getComponentName() == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "Error decoding GetDataDefinitionResponsePdu"); + } + if (doComp.getComponentType().getTypeDescription() == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "Error decoding GetDataDefinitionResponsePdu"); + } + + ObjectReference doRef = + new ObjectReference(lnRef + "." + doComp.getComponentName().toString()); + List children = + getDoSubModelNodesFromSubStructure( + doRef, + fc, + doComp.getComponentType().getTypeDescription().getStructure().getComponents()); + if (fc == Fc.RP) { + dataObjects.add(new Urcb(doRef, children)); + } else if (fc == Fc.BR) { + dataObjects.add(new Brcb(doRef, children)); + } else { + dataObjects.add(new FcDataObject(doRef, fc, children)); + } + } + + return dataObjects; + } + + private static List getDoSubModelNodesFromSubStructure( + ObjectReference parentRef, Fc fc, Components structure) throws ServiceError { + + Collection structComponents = + structure.getSEQUENCE(); + List dataObjects = new ArrayList<>(structComponents.size()); + + for (TypeDescription.Structure.Components.SEQUENCE component : structComponents) { + if (component.getComponentName() == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "Error decoding GetDataDefinitionResponsePdu"); + } + + String childName = component.getComponentName().toString(); + dataObjects.add( + getModelNodesFromTypeSpecification( + new ObjectReference(parentRef + "." + childName), fc, component.getComponentType())); + } + return dataObjects; + } + + private static FcModelNode getModelNodesFromTypeSpecification( + ObjectReference ref, Fc fc, TypeSpecification mmsTypeSpec) throws ServiceError { + + if (mmsTypeSpec.getTypeDescription().getArray() != null) { + + int numArrayElements = + mmsTypeSpec.getTypeDescription().getArray().getNumberOfElements().intValue(); + List arrayChildren = new ArrayList<>(numArrayElements); + for (int i = 0; i < numArrayElements; i++) { + arrayChildren.add( + getModelNodesFromTypeSpecification( + new ObjectReference(ref + "(" + i + ")"), + fc, + mmsTypeSpec.getTypeDescription().getArray().getElementType())); + } + + return new Array(ref, fc, arrayChildren); + } + + if (mmsTypeSpec.getTypeDescription().getStructure() != null) { + List children = + getDoSubModelNodesFromSubStructure( + ref, fc, mmsTypeSpec.getTypeDescription().getStructure().getComponents()); + return (new ConstructedDataAttribute(ref, fc, children)); + } + + // it is a single element + BasicDataAttribute bt = convertMmsBasicTypeSpec(ref, fc, mmsTypeSpec.getTypeDescription()); + if (bt == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "decodeGetDataDefinitionResponse: Unknown data type received " + ref); + } + return (bt); + } + + private static BasicDataAttribute convertMmsBasicTypeSpec( + ObjectReference ref, Fc fc, TypeDescription mmsTypeSpec) throws ServiceError { + + if (mmsTypeSpec.getBool() != null) { + return new BdaBoolean(ref, fc, null, false, false); + } + if (mmsTypeSpec.getBitString() != null) { + int bitStringMaxLength = Math.abs(mmsTypeSpec.getBitString().intValue()); + + if (bitStringMaxLength == 13) { + return new BdaQuality(ref, fc, null, false); + } else if (bitStringMaxLength == 10) { + return new BdaOptFlds(ref, fc); + } else if (bitStringMaxLength == 6) { + return new BdaTriggerConditions(ref, fc); + } else if (bitStringMaxLength == 2) { + if (fc == Fc.CO) { + // if name == ctlVal + if (ref.getName().charAt(1) == 't') { + return new BdaTapCommand(ref, fc, null, false, false); + } + // name == Check + else { + return new BdaCheck(ref); + } + } else { + return new BdaDoubleBitPos(ref, fc, null, false, false); + } + } + return null; + } else if (mmsTypeSpec.getInteger() != null) { + switch (mmsTypeSpec.getInteger().intValue()) { + case 8: + return new BdaInt8(ref, fc, null, false, false); + case 16: + return new BdaInt16(ref, fc, null, false, false); + case 32: + return new BdaInt32(ref, fc, null, false, false); + case 64: + return new BdaInt64(ref, fc, null, false, false); + case 128: + return new BdaInt128(ref, fc, null, false, false); + } + } else if (mmsTypeSpec.getUnsigned() != null) { + switch (mmsTypeSpec.getUnsigned().intValue()) { + case 8: + return new BdaInt8U(ref, fc, null, false, false); + case 16: + return new BdaInt16U(ref, fc, null, false, false); + case 32: + return new BdaInt32U(ref, fc, null, false, false); + } + } else if (mmsTypeSpec.getFloatingPoint() != null) { + int floatSize = mmsTypeSpec.getFloatingPoint().getFormatWidth().intValue(); + if (floatSize == 32) { + return new BdaFloat32(ref, fc, null, false, false); + } else if (floatSize == 64) { + return new BdaFloat64(ref, fc, null, false, false); + } + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "FLOAT of size: " + floatSize + " is not supported."); + } else if (mmsTypeSpec.getOctetString() != null) { + int stringSize = mmsTypeSpec.getOctetString().intValue(); + if (stringSize > 255 || stringSize < -255) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "OCTET_STRING of size: " + stringSize + " is not supported."); + } + return new BdaOctetString(ref, fc, null, Math.abs(stringSize), false, false); + + } else if (mmsTypeSpec.getVisibleString() != null) { + int stringSize = mmsTypeSpec.getVisibleString().intValue(); + if (stringSize > 255 || stringSize < -255) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "VISIBLE_STRING of size: " + stringSize + " is not supported."); + } + return new BdaVisibleString(ref, fc, null, Math.abs(stringSize), false, false); + } else if (mmsTypeSpec.getMMSString() != null) { + int stringSize = mmsTypeSpec.getMMSString().intValue(); + if (stringSize > 255 || stringSize < -255) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "UNICODE_STRING of size: " + stringSize + " is not supported."); + } + return new BdaUnicodeString(ref, fc, null, Math.abs(stringSize), false, false); + } else if (mmsTypeSpec.getUtcTime() != null) { + return new BdaTimestamp(ref, fc, null, false, false); + } else if (mmsTypeSpec.getBinaryTime() != null) { + return new BdaEntryTime(ref, fc, null, false, false); + } + return null; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/DataSet.java b/src/main/java/com/beanit/iec61850bean/DataSet.java new file mode 100644 index 0000000..7ca483d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/DataSet.java @@ -0,0 +1,152 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.iec61850bean.internal.mms.asn1.Identifier; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class DataSet implements Iterable { + + private final String dataSetReference; + private final List members; + private final Map> membersMap = new EnumMap<>(Fc.class); + private final boolean deletable; + private ObjectName mmsObjectName = null; + + public DataSet(String dataSetReference, List members) { + this(dataSetReference, members, true); + } + + public DataSet(String dataSetReference, List members, boolean deletable) { + if (!dataSetReference.startsWith("@") && dataSetReference.indexOf('/') == -1) { + throw new IllegalArgumentException( + "DataSet reference " + + dataSetReference + + " is invalid. Must either start with @ or contain a slash."); + } + this.members = new ArrayList<>(); + this.dataSetReference = dataSetReference; + this.deletable = deletable; + + for (Fc myfc : Fc.values()) { + membersMap.put(myfc, new LinkedHashMap()); + } + + for (FcModelNode member : members) { + this.members.add(member); + membersMap.get(member.getFc()).put(member.getReference().toString(), member); + } + } + + public String getReferenceStr() { + return dataSetReference; + } + + public DataSet copy() { + List membersCopy = new ArrayList<>(members.size()); + for (FcModelNode node : members) { + membersCopy.add((FcModelNode) node.copy()); + } + return new DataSet(dataSetReference, membersCopy, deletable); + } + + public FcModelNode getMember(ObjectReference memberReference, Fc fc) { + if (fc != null) { + return membersMap.get(fc).get(memberReference.toString()); + } + for (FcModelNode member : members) { + if (member.getReference().toString().equals(memberReference.toString())) { + return member; + } + } + return null; + } + + public FcModelNode getMember(int index) { + return members.get(index); + } + + public List getMembers() { + return members; + } + + /** + * Those DataSets defined in the SCL file are not deletable. All other DataSets are deletable. + * Note that no Reports/Logs may be using the DataSet otherwise it cannot be deleted (but this + * function will still return true). + * + * @return true if deletable + */ + public boolean isDeletable() { + return deletable; + } + + @Override + public Iterator iterator() { + return members.iterator(); + } + + public List getBasicDataAttributes() { + List subBasicDataAttributes = new ArrayList<>(); + for (ModelNode member : members) { + subBasicDataAttributes.addAll(member.getBasicDataAttributes()); + } + return subBasicDataAttributes; + } + + ObjectName getMmsObjectName() { + + if (mmsObjectName != null) { + return mmsObjectName; + } + + if (dataSetReference.charAt(0) == '@') { + mmsObjectName = new ObjectName(); + mmsObjectName.setAaSpecific(new Identifier(dataSetReference.getBytes(UTF_8))); + return mmsObjectName; + } + + int slash = dataSetReference.indexOf('/'); + String domainID = dataSetReference.substring(0, slash); + String itemID = dataSetReference.substring(slash + 1).replace('.', '$'); + + ObjectName.DomainSpecific domainSpecificObjectName = new ObjectName.DomainSpecific(); + domainSpecificObjectName.setDomainID(new Identifier(domainID.getBytes(UTF_8))); + domainSpecificObjectName.setItemID(new Identifier(itemID.getBytes(UTF_8))); + + mmsObjectName = new ObjectName(); + mmsObjectName.setDomainSpecific(domainSpecificObjectName); + + return mmsObjectName; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getReferenceStr()); + for (FcModelNode member : members) { + sb.append("\n"); + sb.append(member.toString()); + } + return sb.toString(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/Fc.java b/src/main/java/com/beanit/iec61850bean/Fc.java new file mode 100644 index 0000000..fd8ff9c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/Fc.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public enum Fc { + + // The following FCs are not part of this enum because they are not really + // FCs and only defined in part 8-1: + // RP (report), LG (log), BR (buffered report), GO, GS, MS, US + + // FCs according to IEC 61850-7-2: + /** Status information */ + ST, + /** Measurands - analogue values */ + MX, + /** Setpoint */ + SP, + /** Substitution */ + SV, + /** Configuration */ + CF, + /** Description */ + DC, + /** Setting group */ + SG, + /** Setting group editable */ + SE, + /** Service response / Service tracking */ + SR, + /** Operate received */ + OR, + /** Blocking */ + BL, + /** Extended definition */ + EX, + /** Control, deprecated but kept here for backward compatibility */ + CO, + /** Unbuffered Reporting */ + RP, + /** Buffered Reporting */ + BR; + + public static Fc fromString(String fc) { + try { + return Fc.valueOf(fc); + } catch (Exception e) { + return null; + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/FcDataObject.java b/src/main/java/com/beanit/iec61850bean/FcDataObject.java new file mode 100644 index 0000000..8b0cf5a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/FcDataObject.java @@ -0,0 +1,95 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; + +/** + * This class represents a functionally constraint DataObject. That means it has unique reference + * and FunctionalConstraint. A DataObject as defined in part 7-3 is made up of 1..n FcDataObjects + * where n is the number of different FunctionalConstraints that the children of the DataObject + * have. An FcDataObject can have children of types FcDataObject, Array, ConstructedDataAttribute or + * BasicDataAttribute. + * + * @author Stefan Feuerhahn + */ +public class FcDataObject extends FcModelNode { + + public FcDataObject(ObjectReference objectReference, Fc fc, List children) { + + this.children = new LinkedHashMap<>((int) ((children.size() / 0.75) + 1)); + this.objectReference = objectReference; + for (ModelNode child : children) { + this.children.put(child.getReference().getName(), child); + child.setParent(this); + } + this.fc = fc; + } + + @Override + public FcDataObject copy() { + List childCopies = new ArrayList<>(children.size()); + for (ModelNode childNode : children.values()) { + childCopies.add((FcModelNode) childNode.copy()); + } + return new FcDataObject(objectReference, fc, childCopies); + } + + @Override + Data getMmsDataObj() { + Data.Structure dataStructure = new Data.Structure(); + List 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; + } + + @Override + 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 iterator = data.getStructure().getData().iterator(); + for (ModelNode child : children.values()) { + child.setValueFromMmsDataObj(iterator.next()); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/FcModelNode.java b/src/main/java/com/beanit/iec61850bean/FcModelNode.java new file mode 100644 index 0000000..e414979 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/FcModelNode.java @@ -0,0 +1,252 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +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.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.Timer; +import java.util.TimerTask; + +public abstract class FcModelNode extends ModelNode { + + Fc fc; + private VariableDefs.SEQUENCE variableDef = null; + private ServerAssociation selected = null; + private TimerTask task = null; + + public Fc getFc() { + return fc; + } + + boolean select(ServerAssociation association, Timer timer) { + if (selected != null) { + if (selected != association) { + return false; + } + } else { + selected = association; + association.selects.add(this); + } + + ModelNode sboTimeoutNode = + association.serverModel.findModelNode(objectReference, Fc.CF).getChild("sboTimeout"); + + if (sboTimeoutNode == null) { + return true; + } + + long sboTimeout = ((BdaInt32U) sboTimeoutNode).getValue(); + + if (sboTimeout == 0) { + return true; + } + + class SelectResetTask extends TimerTask { + ServerAssociation association; + + SelectResetTask(ServerAssociation association) { + this.association = association; + } + + @Override + public void run() { + synchronized (association.serverModel) { + if (task == this) { + task = null; + deselectAndRemove(association); + } + } + } + } + + if (task != null) { + task.cancel(); + } + + task = new SelectResetTask(association); + timer.schedule(task, sboTimeout); + + return true; + } + + void deselectAndRemove(ServerAssociation association) { + selected = null; + if (task != null) { + task.cancel(); + task = null; + } + association.selects.remove(this); + } + + void deselect() { + selected = null; + if (task != null) { + task.cancel(); + task = null; + } + } + + boolean isSelected() { + return selected != null; + } + + boolean isSelectedBy(ServerAssociation association) { + return selected == association; + } + + VariableDefs.SEQUENCE getMmsVariableDef() { + + if (variableDef != null) { + return variableDef; + } + + AlternateAccess alternateAccess = null; + + StringBuilder preArrayIndexItemId = new StringBuilder(objectReference.get(1)); + preArrayIndexItemId.append("$"); + preArrayIndexItemId.append(fc); + + int arrayIndexPosition = objectReference.getArrayIndexPosition(); + if (arrayIndexPosition != -1) { + + for (int i = 2; i < arrayIndexPosition; i++) { + preArrayIndexItemId.append("$"); + preArrayIndexItemId.append(objectReference.get(i)); + } + + alternateAccess = new AlternateAccess(); + List subSeqOfAlternateAccess = alternateAccess.getCHOICE(); + Unsigned32 indexBerInteger = + new Unsigned32(Integer.parseInt(objectReference.get(arrayIndexPosition))); + + if (arrayIndexPosition < (objectReference.size() - 1)) { + // this reference points to a sub-node of an array element + + StringBuilder postArrayIndexItemId = + new StringBuilder(objectReference.get(arrayIndexPosition + 1)); + + 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 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); + } + + } else { + + for (int i = 2; i < objectReference.size(); i++) { + 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); + + VariableSpecification varSpec = new VariableSpecification(); + varSpec.setName(objectName); + + variableDef = new VariableDefs.SEQUENCE(); + variableDef.setAlternateAccess(alternateAccess); + variableDef.setVariableSpecification(varSpec); + + return variableDef; + } + + @Override + public String toString() { + 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(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/FileInformation.java b/src/main/java/com/beanit/iec61850bean/FileInformation.java new file mode 100644 index 0000000..750abb0 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/FileInformation.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.Calendar; + +/** Contains file information received by the GetFileDirectory service */ +public class FileInformation { + + private final String filename; + + private final long fileSize; + + private final Calendar lastModified; + + public FileInformation(String filename, long fileSize, Calendar lastModified) { + super(); + this.filename = filename; + this.fileSize = fileSize; + this.lastModified = lastModified; + } + + public String getFilename() { + return filename; + } + + public long getFileSize() { + return fileSize; + } + + /** + * Get the time stamp of last modification. As it is an optional attribute the return value can be + * null + * + * @return the time stamp of last modification, or null if the time stamp is not present + */ + public Calendar getLastModified() { + return lastModified; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/GetFileListener.java b/src/main/java/com/beanit/iec61850bean/GetFileListener.java new file mode 100644 index 0000000..426febe --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/GetFileListener.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +/** Callback handler for GetFile service */ +public interface GetFileListener { + /** + * Is called when a new block of file data is received + * + * @param fileData block of file data received + * @param moreFollows true if more data blocks will follow, false otherwise + * @return true to continue the GetFile service, false to cancel + */ + boolean dataReceived(byte[] fileData, boolean moreFollows); +} diff --git a/src/main/java/com/beanit/iec61850bean/LogicalDevice.java b/src/main/java/com/beanit/iec61850bean/LogicalDevice.java new file mode 100644 index 0000000..c67bfe6 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/LogicalDevice.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +public final class LogicalDevice extends ModelNode { + + public LogicalDevice(ObjectReference objectReference, List logicalNodes) { + children = new LinkedHashMap<>((int) ((logicalNodes.size() / 0.75) + 1)); + this.objectReference = objectReference; + for (LogicalNode logicalNode : logicalNodes) { + children.put(logicalNode.getReference().getName(), logicalNode); + logicalNode.setParent(this); + } + } + + @Override + public LogicalDevice copy() { + List childCopies = new ArrayList<>(children.size()); + for (ModelNode childNode : children.values()) { + childCopies.add((LogicalNode) childNode.copy()); + } + return new LogicalDevice(objectReference, childCopies); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/LogicalNode.java b/src/main/java/com/beanit/iec61850bean/LogicalNode.java new file mode 100644 index 0000000..c5f9e2a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/LogicalNode.java @@ -0,0 +1,137 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class LogicalNode extends ModelNode { + + private final Map> fcDataObjects = new EnumMap<>(Fc.class); + + private final Map urcbs = new HashMap<>(); + private final Map brcbs = new HashMap<>(); + + public LogicalNode(ObjectReference objectReference, List fcDataObjects) { + children = new LinkedHashMap<>(); + for (Fc fc : Fc.values()) { + this.fcDataObjects.put(fc, new LinkedHashMap()); + } + + this.objectReference = objectReference; + + for (FcDataObject fcDataObject : fcDataObjects) { + children.put( + fcDataObject.getReference().getName() + fcDataObject.fc.toString(), fcDataObject); + this.fcDataObjects + .get(fcDataObject.getFc()) + .put(fcDataObject.getReference().getName(), fcDataObject); + fcDataObject.setParent(this); + if (fcDataObject.getFc() == Fc.RP) { + addUrcb((Urcb) fcDataObject, false); + } else if (fcDataObject.getFc() == Fc.BR) { + addBrcb((Brcb) fcDataObject); + } + } + } + + @Override + public LogicalNode copy() { + + List dataObjectsCopy = new ArrayList<>(); + for (ModelNode obj : children.values()) { + dataObjectsCopy.add((FcDataObject) obj.copy()); + } + + LogicalNode copy = new LogicalNode(objectReference, dataObjectsCopy); + return copy; + } + + public List getChildren(Fc fc) { + Map requestedDataObjectsMap = fcDataObjects.get(fc); + if (requestedDataObjectsMap == null) { + return null; + } + + Collection fcChildren = requestedDataObjectsMap.values(); + if (fcChildren.size() == 0) { + return null; + } else { + return new ArrayList<>(fcChildren); + } + } + + void addUrcb(Urcb urcb, boolean addDataSet) { + urcbs.put(urcb.getReference().getName(), urcb); + if (addDataSet) { + String dataSetRef = urcb.getDatSet().getStringValue(); + if (dataSetRef != null) { + urcb.dataSet = + ((ServerModel) getParent().getParent()).getDataSet(dataSetRef.replace('$', '.')); + } + } + } + + public Collection getUrcbs() { + return urcbs.values(); + } + + public Urcb getUrcb(String urcbName) { + return urcbs.get(urcbName); + } + + void addBrcb(Brcb brcb) { + brcbs.put(brcb.getReference().getName(), brcb); + } + + public Brcb getBrcb(String brcbName) { + return brcbs.get(brcbName); + } + + public Collection getBrcbs() { + return brcbs.values(); + } + + @Override + public ModelNode getChild(String childName, Fc fc) { + if (fc != null) { + return fcDataObjects.get(fc).get(childName); + } + for (Map map : fcDataObjects.values()) { + FcDataObject fcDataObject = map.get(childName); + if (fcDataObject != null) { + return fcDataObject; + } + } + return null; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getReference().toString()); + for (Map fcChildNodes : fcDataObjects.values()) { + for (ModelNode childNode : fcChildNodes.values()) { + sb.append("\n"); + sb.append(childNode.toString()); + } + } + return sb.toString(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ModelNode.java b/src/main/java/com/beanit/iec61850bean/ModelNode.java new file mode 100644 index 0000000..4aed617 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ModelNode.java @@ -0,0 +1,178 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.Identifier; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure.Components; +import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public abstract class ModelNode implements Iterable { + + protected ObjectReference objectReference; + protected Map children; + ModelNode parent; + + /** + * Returns a copy of model node with all of its children. Creates new BasicDataAttribute values + * but reuses ObjectReferences, FunctionalConstraints. + * + * @return a copy of model node with all of its children. + */ + public abstract ModelNode copy(); + + /** + * Returns the child node with the given name. Will always return null if called on a logical node + * because a logical node need the functional constraint to uniquely identify a child. For logical + * nodes use getChild(String name, Fc fc) instead. + * + * @param name the name of the requested child node + * @return the child node with the given name. + */ + public ModelNode getChild(String name) { + return getChild(name, null); + } + + /** + * Returns the child node with the given name and functional constraint. The fc is ignored if this + * function is called on any model node other than logical node. + * + * @param name the name of the requested child node + * @param fc the functional constraint of the requested child node + * @return the child node with the given name and functional constrain + */ + public ModelNode getChild(String name, Fc fc) { + return children.get(name); + } + + @SuppressWarnings("unchecked") + public Collection getChildren() { + if (children == null) { + return null; + } + return children.values(); + } + + protected Iterator> getIterators() { + List> iterators = new ArrayList<>(); + if (children != null) { + iterators.add(children.values().iterator()); + } + return iterators.iterator(); + } + + /** + * Returns the reference of the model node. + * + * @return the reference of the model node. + */ + public ObjectReference getReference() { + return objectReference; + } + + /** + * Returns the name of the model node. + * + * @return the name of the model node. + */ + public String getName() { + return objectReference.getName(); + } + + @Override + public Iterator iterator() { + return children.values().iterator(); + } + + /** + * Returns a list of all leaf nodes (basic data attributes) contained in the subtree of this model + * node. + * + * @return a list of all leaf nodes (basic data attributes) contained in the subtree of this model + * node. + */ + public List getBasicDataAttributes() { + List subBasicDataAttributes = new ArrayList<>(); + for (ModelNode child : children.values()) { + subBasicDataAttributes.addAll(child.getBasicDataAttributes()); + } + return subBasicDataAttributes; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getReference().toString()); + for (ModelNode childNode : children.values()) { + sb.append("\n"); + sb.append(childNode.toString()); + } + return sb.toString(); + } + + /** + * Returns the parent node of this node. + * + * @return the parent node of this node. + */ + public ModelNode getParent() { + return parent; + } + + void setParent(ModelNode parent) { + this.parent = parent; + } + + Data getMmsDataObj() { + return null; + } + + void setValueFromMmsDataObj(Data data) throws ServiceError {} + + TypeDescription getMmsTypeSpec() { + + Components componentsSequenceType = new Components(); + + List structComponents = + componentsSequenceType.getSEQUENCE(); + for (ModelNode child : children.values()) { + TypeSpecification typeSpecification = new TypeSpecification(); + typeSpecification.setTypeDescription(child.getMmsTypeSpec()); + + TypeDescription.Structure.Components.SEQUENCE component = + new TypeDescription.Structure.Components.SEQUENCE(); + component.setComponentName(new Identifier(child.getName().getBytes(UTF_8))); + component.setComponentType(typeSpecification); + + structComponents.add(component); + } + + Structure structure = new Structure(); + structure.setComponents(componentsSequenceType); + + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setStructure(structure); + + return typeDescription; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ObjectReference.java b/src/main/java/com/beanit/iec61850bean/ObjectReference.java new file mode 100644 index 0000000..a2a0742 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ObjectReference.java @@ -0,0 +1,175 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** ObjectReference syntax: LDName/LNName.DOName[.Name[. ...]] */ +public final class ObjectReference implements Iterable { + + private final String objectReference; + private List nodeNames = null; + + // if the ObjectReference contains an array index this variable will save + // its position in the nodeNames List + private int arrayIndexPosition = -1; + + public ObjectReference(String objectReference) { + if (objectReference == null || objectReference.isEmpty()) { + throw new IllegalArgumentException(); + } + this.objectReference = objectReference; + } + + /** + * Returns name part of the reference. + * + * @return the name + */ + public String getName() { + if (nodeNames == null) { + parseForNameList(); + } + return nodeNames.get(nodeNames.size() - 1); + } + + public String getLdName() { + if (nodeNames == null) { + parseForNameList(); + } + + return nodeNames.get(0); + } + + @Override + public String toString() { + return objectReference; + } + + public boolean isLogicalDeviceRef() { + if (nodeNames == null) { + parseForNameList(); + } + return (nodeNames.size() == 1); + } + + public boolean isLogicalNodeRef() { + if (nodeNames == null) { + parseForNameList(); + } + return (nodeNames.size() == 2); + } + + public boolean isDataRef() { + if (nodeNames == null) { + parseForNameList(); + } + return (nodeNames.size() > 2); + } + + int getArrayIndexPosition() { + if (nodeNames == null) { + parseForNameList(); + } + return arrayIndexPosition; + } + + @Override + public Iterator iterator() { + if (nodeNames == null) { + parseForNameList(); + } + return nodeNames.iterator(); + } + + public String get(int i) { + if (nodeNames == null) { + parseForNameList(); + } + return nodeNames.get(i); + } + + public int size() { + if (nodeNames == null) { + parseForNameList(); + } + return nodeNames.size(); + } + + private void parseForNameList() { + + nodeNames = new ArrayList<>(); + + int lastDelim = -1; + int nextDelim = objectReference.indexOf('/'); + if (nextDelim == -1) { + nodeNames.add(objectReference.substring(lastDelim + 1)); + return; + } + + nodeNames.add(objectReference.substring(lastDelim + 1, nextDelim)); + + int dotIndex = -1; + int openingbracketIndex = -1; + int closingbracketIndex = -1; + while (true) { + lastDelim = nextDelim; + if (dotIndex == -1) { + dotIndex = objectReference.indexOf('.', lastDelim + 1); + if (dotIndex == -1) { + dotIndex = objectReference.length(); + } + } + if (openingbracketIndex == -1) { + openingbracketIndex = objectReference.indexOf('(', lastDelim + 1); + if (openingbracketIndex == -1) { + openingbracketIndex = objectReference.length(); + } + } + if (closingbracketIndex == -1) { + closingbracketIndex = objectReference.indexOf(')', lastDelim + 1); + if (closingbracketIndex == -1) { + closingbracketIndex = objectReference.length(); + } + } + + if (dotIndex == openingbracketIndex && dotIndex == closingbracketIndex) { + nodeNames.add(objectReference.substring(lastDelim + 1)); + return; + } + + if (dotIndex < openingbracketIndex && dotIndex < closingbracketIndex) { + nextDelim = dotIndex; + dotIndex = -1; + } else if (openingbracketIndex < dotIndex && openingbracketIndex < closingbracketIndex) { + nextDelim = openingbracketIndex; + openingbracketIndex = -1; + arrayIndexPosition = nodeNames.size() + 1; + } else if (closingbracketIndex < dotIndex && closingbracketIndex < openingbracketIndex) { + if (closingbracketIndex == (objectReference.length() - 1)) { + nodeNames.add(objectReference.substring(lastDelim + 1, closingbracketIndex)); + return; + } + nextDelim = closingbracketIndex + 1; + closingbracketIndex = -1; + dotIndex = -1; + nodeNames.add(objectReference.substring(lastDelim + 1, nextDelim - 1)); + continue; + } + nodeNames.add(objectReference.substring(lastDelim + 1, nextDelim)); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/Rcb.java b/src/main/java/com/beanit/iec61850bean/Rcb.java new file mode 100644 index 0000000..fc3db99 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/Rcb.java @@ -0,0 +1,117 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.List; + +public abstract class Rcb extends FcDataObject { + + DataSet dataSet; + + protected Rcb(ObjectReference objectReference, Fc fc, List children) { + super(objectReference, fc, children); + } + + /** + * Gets the RptID (Report ID). The RptID will be included in every report sent by the server. If + * it is equal to NULL, then the RptID sent will be equal to the reference of the RCB. + * + * @return the report ID + */ + public BdaVisibleString getRptId() { + return (BdaVisibleString) children.get("RptID"); + } + + /** + * Gets the boolean value which states whether reporting is enabled. + * + * @return BdaBoolean that contains true as value if reporting is enabled. + */ + public BdaBoolean getRptEna() { + return (BdaBoolean) children.get("RptEna"); + } + + /** + * Gets the object reference of the DataSet that is to be monitored for reporting events. + * + * @return the object reference of the DataSet + */ + public BdaVisibleString getDatSet() { + return (BdaVisibleString) children.get("DatSet"); + } + + /** + * Configuration revision The attribute ConfRev shall represent a count of the number of times + * that the configuration of the DATA-SET referenced by DatSet has been changed. Changes that + * shall be counted are: + * + *
    + *
  • any deletion of a member of the DATA-SET; + *
  • the reordering of members of the DATA-SET; and + *
  • Successful SetBRCBValues of the DatSet attribute where the DatSet attribute value + * changes. + *
+ * + * The counter shall be incremented when the configuration changes. At configuration time, the + * configuration tool will be responsible for incrementing/maintaining the ConfRev value. When + * configuration changes occur due to SetBRCBValues, the IED shall be responsible for incrementing + * the value of ConfRev. + * + * @return the configuration revision + */ + public BdaInt32U getConfRev() { + return (BdaInt32U) children.get("ConfRev"); + } + + /** + * Gets the optional fields parameter which specifies which optional fields should be included in + * the reports sent by this RCB. + * + * @return the optional fields parameter + */ + public BdaOptFlds getOptFlds() { + return (BdaOptFlds) children.get("OptFlds"); + } + + /** + * Gets the buffer time - The attribute BufTm (see Figure 27) shall specify the time interval in + * milliseconds for the buffering of internal notifications caused by data-change (dchg), + * quality-change (qchg), data update (dupd) by the BRCB for inclusion into a single report. + * + * @return the buffer time + */ + public BdaInt32U getBufTm() { + return (BdaInt32U) children.get("BufTm"); + } + + /** + * Gets the sequence number - The attribute SqNum shall specify the sequence number for each BRCB + * that has report enable set to TRUE. This number is to be incremented by the BRCB for each + * report generated and sent. The increment shall occur once the BRCB has formatted the report and + * requested for transmission. + * + * @return the sequence number + */ + public BdaInt8U getSqNum() { + return (BdaInt8U) children.get("SqNum"); + } + + public BdaTriggerConditions getTrgOps() { + return (BdaTriggerConditions) children.get("TrgOps"); + } + + public BdaInt32U getIntgPd() { + return (BdaInt32U) children.get("IntgPd"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/Report.java b/src/main/java/com/beanit/iec61850bean/Report.java new file mode 100644 index 0000000..80f1c42 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/Report.java @@ -0,0 +1,189 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.HexString; +import java.util.List; + +public class Report { + + private final String rptId; + private final Integer sqNum; + private final Integer subSqNum; + private final boolean moreSegmentsFollow; + private final String dataSetRef; + private final Boolean bufOvfl; + private final Long confRev; + private final BdaEntryTime timeOfEntry; + private final BdaOctetString entryId; + private final boolean[] inclusionBitString; + private final List values; + private final List reasonCodes; + + public Report( + String rptId, + Integer sqNum, + Integer subSqNum, + boolean moreSegmentsFollow, + String dataSetRef, + Boolean bufOvfl, + Long confRev, + BdaEntryTime timeOfEntry, + BdaOctetString entryId, + boolean[] inclusionBitString, + List values, + List reasonCodes) { + this.rptId = rptId; + this.sqNum = sqNum; + this.subSqNum = subSqNum; + this.moreSegmentsFollow = moreSegmentsFollow; + this.dataSetRef = dataSetRef; + this.bufOvfl = bufOvfl; + this.confRev = confRev; + this.timeOfEntry = timeOfEntry; + this.entryId = entryId; + this.inclusionBitString = inclusionBitString; + this.values = values; + this.reasonCodes = reasonCodes; + } + + public String getRptId() { + return rptId; + } + + /** + * Sequence numberThe parameter MoreSegmentsFollow indicates that more report segments with the + * same sequence number follow, counted up for every {@code Report} instance generated + * + * @return the sequence number + */ + public Integer getSqNum() { + return sqNum; + } + + /** + * For the case of long reports that do not fit into one message, a single report shall be divided + * into subreports. Each segment – of one report – shall be numbered with the same sequence number + * and a unique SubSqNum. + * + * @return the subsequence number + */ + public Integer getSubSqNum() { + return subSqNum; + } + + /** + * The parameter MoreSegmentsFollow indicates that more report segments with the same sequence + * number follow + * + * @return true if more segments follow + */ + public boolean isMoreSegmentsFollow() { + return moreSegmentsFollow; + } + + public String getDataSetRef() { + return dataSetRef; + } + + /** + * The parameter BufOvfl shall indicate to the client that entries within the buffer may have been + * lost. The detection of possible loss of information occurs when a client requests a + * resynchronization to a non-existent entry or to the first entry in the queue. + * + * @return true if buffer overflow is true + */ + public Boolean getBufOvfl() { + return bufOvfl; + } + + public Long getConfRev() { + return confRev; + } + + /** + * The parameter TimeOfEntry shall specify the time when the EntryID was created + * + * @return the time of entry + */ + public BdaEntryTime getTimeOfEntry() { + return timeOfEntry; + } + + public BdaOctetString getEntryId() { + return entryId; + } + + /** + * Indicator of data set members included in the report + * + * @return the inclusion bit string as a byte array + */ + public boolean[] getInclusionBitString() { + return inclusionBitString; + } + + /** + * Gets the reasons for inclusion + * + * @return the reasons for inclusion + */ + public List getReasonCodes() { + return reasonCodes; + } + + public List getValues() { + return values; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Report ID: ").append(rptId); + sb.append("\nData set reference: ").append(dataSetRef); + + if (sqNum != null) { + sb.append("\nSequence number: ").append(sqNum); + } + if (subSqNum != null) { + sb.append("\nSubsequence number: ").append(subSqNum); + if (moreSegmentsFollow) { + sb.append(" (more segments follow)"); + } + } + if (timeOfEntry != null) { + sb.append("\nTime of entry (unix timestamp): ").append(timeOfEntry.getTimestampValue()); + } + if (bufOvfl != null) { + sb.append("\nBuffer overflow: ").append(bufOvfl); + } + if (entryId != null) { + sb.append("\nEntry ID: ").append(HexString.fromBytes(entryId.getValue())); + } + if (confRev != null) { + sb.append("\nConfiguration revision: ").append(confRev.toString()); + } + sb.append("\nReported data set members:"); + int index = 0; + for (FcModelNode reportedDataSetMember : values) { + sb.append("\n").append(reportedDataSetMember.toString()); + if (reasonCodes != null) { + sb.append(", reason: ").append(reasonCodes.get(index)); + } + index++; + } + + return sb.toString(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ReportEntryData.java b/src/main/java/com/beanit/iec61850bean/ReportEntryData.java new file mode 100644 index 0000000..a2678d1 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ReportEntryData.java @@ -0,0 +1,78 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public class ReportEntryData { + + /** Not specified in IEC61850 but useful for data persistence */ + private long id; + /** Reference to to {@link DataSet}-member */ + private String dataRef; + /** Attribute value to be reported */ + private ModelNode value; + /** Trigger that caused the data to be put into the report */ + // private TriggerConditions reasonCode; + private ReasonCode reasonCode; + /** Backreference to report */ + private Report report; + + public String getDataRef() { + return dataRef; + } + + public void setDataRef(String dataRef) { + this.dataRef = dataRef; + } + + public ModelNode getValue() { + return value; + } + + public void setValue(ModelNode value) { + this.value = value; + } + + public ReasonCode getReasonCode() { + return reasonCode; + } + + public void setReasonCode(ReasonCode reasonCode) { + this.reasonCode = reasonCode; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Report getReport() { + return report; + } + + public void setReport(Report report) { + this.report = report; + } + + public enum ReasonCode { + DCHG, + QCHG, + DUPD, + INTEGRITY, + GI, + APPTRIGGER + } +} diff --git a/src/main/java/com/beanit/iec61850bean/SclParseException.java b/src/main/java/com/beanit/iec61850bean/SclParseException.java new file mode 100644 index 0000000..656d4c1 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/SclParseException.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class SclParseException extends Exception { + + private static final long serialVersionUID = 8499804369026418082L; + + public SclParseException(String string) { + super(string); + } + + public SclParseException(Exception e) { + super(e); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/SclParser.java b/src/main/java/com/beanit/iec61850bean/SclParser.java new file mode 100644 index 0000000..adc5a10 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/SclParser.java @@ -0,0 +1,1110 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.iec61850bean.internal.scl.AbstractDataAttribute; +import com.beanit.iec61850bean.internal.scl.Bda; +import com.beanit.iec61850bean.internal.scl.Da; +import com.beanit.iec61850bean.internal.scl.DaType; +import com.beanit.iec61850bean.internal.scl.Do; +import com.beanit.iec61850bean.internal.scl.DoType; +import com.beanit.iec61850bean.internal.scl.EnumType; +import com.beanit.iec61850bean.internal.scl.EnumVal; +import com.beanit.iec61850bean.internal.scl.LnSubDef; +import com.beanit.iec61850bean.internal.scl.LnType; +import com.beanit.iec61850bean.internal.scl.Sdo; +import com.beanit.iec61850bean.internal.scl.TypeDefinitions; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class SclParser { + + private final Map dataSetsMap = new HashMap<>(); + private final List dataSetDefs = new ArrayList<>(); + private TypeDefinitions typeDefinitions; + private Document doc; + private String iedName; + private List serverModels = new ArrayList<>(); + private boolean useResvTmsAttributes = false; + + private SclParser() {} + + public static List parse(InputStream is) throws SclParseException { + SclParser sclParser = new SclParser(); + sclParser.parseStream(is); + return sclParser.serverModels; + } + + public static List parse(String sclFilePath) throws SclParseException { + try { + return parse(new FileInputStream(sclFilePath)); + } catch (FileNotFoundException e) { + throw new SclParseException(e); + } + } + + private void parseStream(InputStream icdFileStream) throws SclParseException { + + typeDefinitions = new TypeDefinitions(); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setIgnoringComments(true); + + try { + doc = factory.newDocumentBuilder().parse(icdFileStream); + } catch (Exception e) { + throw new SclParseException(e); + } + + Node rootNode = doc.getDocumentElement(); + + if (!"SCL".equals(rootNode.getNodeName())) { + throw new SclParseException("Root node in SCL file is not of type \"SCL\""); + } + + readTypeDefinitions(); + + NodeList iedList = doc.getElementsByTagName("IED"); + if (iedList.getLength() == 0) { + throw new SclParseException("No IED section found!"); + } + + for (int z = 0; z < iedList.getLength(); z++) { + Node iedNode = iedList.item(z); + + useResvTmsAttributes = false; + + Node nameAttribute = iedNode.getAttributes().getNamedItem("name"); + + iedName = nameAttribute.getNodeValue(); + if ((iedName == null) || (iedName.length() == 0)) { + throw new SclParseException("IED must have a name!"); + } + + NodeList iedElements = iedNode.getChildNodes(); + + for (int i = 0; i < iedElements.getLength(); i++) { + Node element = iedElements.item(i); + String nodeName = element.getNodeName(); + if ("AccessPoint".equals(nodeName)) { + ServerSap serverSap = createAccessPoint(element); + if (serverSap != null) { + serverModels.add(serverSap.serverModel); + } + } else if ("Services".equals(nodeName)) { + NodeList servicesElements = element.getChildNodes(); + for (int j = 0; j < servicesElements.getLength(); j++) { + if ("ReportSettings".equals(servicesElements.item(j).getNodeName())) { + Node resvTmsAttribute = + servicesElements.item(j).getAttributes().getNamedItem("resvTms"); + if (resvTmsAttribute != null) { + useResvTmsAttributes = resvTmsAttribute.getNodeValue().equalsIgnoreCase("true"); + } + } + } + } + } + } + } + + private void readTypeDefinitions() throws SclParseException { + + NodeList dttSections = doc.getElementsByTagName("DataTypeTemplates"); + + if (dttSections.getLength() != 1) { + throw new SclParseException("Only one DataTypeSection allowed"); + } + + Node dtt = dttSections.item(0); + + NodeList dataTypes = dtt.getChildNodes(); + + for (int i = 0; i < dataTypes.getLength(); i++) { + Node element = dataTypes.item(i); + + String nodeName = element.getNodeName(); + + if (nodeName.equals("LNodeType")) { + typeDefinitions.putLNodeType(new LnType(element)); + } else if (nodeName.equals("DOType")) { + typeDefinitions.putDOType(new DoType(element)); + } else if (nodeName.equals("DAType")) { + typeDefinitions.putDAType(new DaType(element)); + } else if (nodeName.equals("EnumType")) { + typeDefinitions.putEnumType(new EnumType(element)); + } + } + } + + private ServerSap createAccessPoint(Node iedServer) throws SclParseException { + ServerSap serverSap = null; + + NodeList elements = iedServer.getChildNodes(); + + for (int i = 0; i < elements.getLength(); i++) { + Node element = elements.item(i); + + if (element.getNodeName().equals("Server")) { + + ServerModel server = createServerModel(element); + + Node namedItem = iedServer.getAttributes().getNamedItem("name"); + if (namedItem == null) { + throw new SclParseException("AccessPoint has no name attribute!"); + } + // TODO save this name? + serverSap = new ServerSap(102, 0, null, server, null); + + break; + } + } + + return serverSap; + } + + private ServerModel createServerModel(Node serverXMLNode) throws SclParseException { + + NodeList elements = serverXMLNode.getChildNodes(); + List logicalDevices = new ArrayList<>(elements.getLength()); + + for (int i = 0; i < elements.getLength(); i++) { + Node element = elements.item(i); + + if (element.getNodeName().equals("LDevice")) { + logicalDevices.add(createNewLDevice(element)); + } + } + + ServerModel serverModel = new ServerModel(logicalDevices, null); + + dataSetsMap.clear(); + + for (LnSubDef dataSetDef : dataSetDefs) { + DataSet dataSet = createDataSet(serverModel, dataSetDef.logicalNode, dataSetDef.defXmlNode); + dataSetsMap.put(dataSet.getReferenceStr(), dataSet); + } + + serverModel.addDataSets(dataSetsMap.values()); + + dataSetDefs.clear(); + + return serverModel; + } + + private LogicalDevice createNewLDevice(Node ldXmlNode) throws SclParseException { + + String inst = null; + String ldName = null; + + NamedNodeMap attributes = ldXmlNode.getAttributes(); + + for (int i = 0; i < attributes.getLength(); i++) { + Node node = attributes.item(i); + String nodeName = node.getNodeName(); + + if (nodeName.equals("inst")) { + inst = node.getNodeValue(); + } else if (nodeName.equals("ldName")) { + ldName = node.getNodeValue(); + } + } + + if (inst == null) { + throw new SclParseException("Required attribute \"inst\" in logical device not found!"); + } + + NodeList elements = ldXmlNode.getChildNodes(); + List logicalNodes = new ArrayList<>(); + + String ref; + if ((ldName != null) && (ldName.length() != 0)) { + ref = ldName; + } else { + ref = iedName + inst; + } + + for (int i = 0; i < elements.getLength(); i++) { + Node element = elements.item(i); + + if (element.getNodeName().equals("LN") || element.getNodeName().equals("LN0")) { + logicalNodes.add(createNewLogicalNode(element, ref)); + } + } + + LogicalDevice lDevice = new LogicalDevice(new ObjectReference(ref), logicalNodes); + + return lDevice; + } + + private LogicalNode createNewLogicalNode(Node lnXmlNode, String parentRef) + throws SclParseException { + + // attributes not needed: desc + + String inst = null; + String lnClass = null; + String lnType = null; + String prefix = ""; + + NamedNodeMap attributes = lnXmlNode.getAttributes(); + + for (int i = 0; i < attributes.getLength(); i++) { + Node node = attributes.item(i); + String nodeName = node.getNodeName(); + + if (nodeName.equals("inst")) { + inst = node.getNodeValue(); + } else if (nodeName.equals("lnType")) { + lnType = node.getNodeValue(); + } else if (nodeName.equals("lnClass")) { + lnClass = node.getNodeValue(); + } else if (nodeName.equals("prefix")) { + prefix = node.getNodeValue(); + } + } + + if (inst == null) { + throw new SclParseException("Required attribute \"inst\" not found!"); + } + if (lnType == null) { + throw new SclParseException("Required attribute \"lnType\" not found!"); + } + if (lnClass == null) { + throw new SclParseException("Required attribute \"lnClass\" not found!"); + } + + String ref = parentRef + '/' + prefix + lnClass + inst; + + LnType lnTypeDef = typeDefinitions.getLNodeType(lnType); + + List dataObjects = new ArrayList<>(); + + if (lnTypeDef == null) { + throw new SclParseException("LNType " + lnType + " not defined!"); + } + for (Do dobject : lnTypeDef.dos) { + + // look for DOI node with the name of the DO + Node doiNodeFound = null; + for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { + Node childNode = lnXmlNode.getChildNodes().item(i); + if ("DOI".equals(childNode.getNodeName())) { + + NamedNodeMap doiAttributes = childNode.getAttributes(); + Node nameAttribute = doiAttributes.getNamedItem("name"); + if (nameAttribute != null && nameAttribute.getNodeValue().equals(dobject.getName())) { + doiNodeFound = childNode; + } + } + } + + dataObjects.addAll( + createFcDataObjects(dobject.getName(), ref, dobject.getType(), doiNodeFound)); + } + + // look for ReportControl + for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { + Node childNode = lnXmlNode.getChildNodes().item(i); + if ("ReportControl".equals(childNode.getNodeName())) { + dataObjects.addAll(createReportControlBlocks(childNode, ref)); + } + } + + LogicalNode lNode = new LogicalNode(new ObjectReference(ref), dataObjects); + + // look for DataSet definitions + for (int i = 0; i < lnXmlNode.getChildNodes().getLength(); i++) { + Node childNode = lnXmlNode.getChildNodes().item(i); + if ("DataSet".equals(childNode.getNodeName())) { + dataSetDefs.add(new LnSubDef(childNode, lNode)); + } + } + return lNode; + } + + private DataSet createDataSet(ServerModel serverModel, LogicalNode lNode, Node dsXmlNode) + throws SclParseException { + + Node nameAttribute = dsXmlNode.getAttributes().getNamedItem("name"); + if (nameAttribute == null) { + throw new SclParseException("DataSet must have a name"); + } + + String name = nameAttribute.getNodeValue(); + + List dsMembers = new ArrayList<>(); + + for (int i = 0; i < dsXmlNode.getChildNodes().getLength(); i++) { + Node fcdaXmlNode = dsXmlNode.getChildNodes().item(i); + if ("FCDA".equals(fcdaXmlNode.getNodeName())) { + + // For the definition of FCDA see Table 22 part6 ed2 + + String ldInst = null; + String prefix = ""; + String lnClass = null; + String lnInst = ""; + String doName = ""; + String daName = ""; + Fc fc = null; + + NamedNodeMap attributes = fcdaXmlNode.getAttributes(); + + for (int j = 0; j < attributes.getLength(); j++) { + Node node = attributes.item(j); + String nodeName = node.getNodeName(); + + if (nodeName.equals("ldInst")) { + ldInst = node.getNodeValue(); + } else if (nodeName.equals("lnInst")) { + lnInst = node.getNodeValue(); + } else if (nodeName.equals("lnClass")) { + lnClass = node.getNodeValue(); + } else if (nodeName.equals("prefix")) { + prefix = node.getNodeValue(); + } else if (nodeName.equals("doName")) { + doName = node.getNodeValue(); + } else if (nodeName.equals("daName")) { + if (!node.getNodeValue().isEmpty()) { + daName = "." + node.getNodeValue(); + } + } else if (nodeName.equals("fc")) { + fc = Fc.fromString(node.getNodeValue()); + if (fc == null) { + throw new SclParseException("FCDA contains invalid FC: " + node.getNodeValue()); + } + } + } + + if (ldInst == null) { + throw new SclParseException( + "Required attribute \"ldInst\" not found in FCDA: " + nameAttribute + "!"); + } + + if (lnClass == null) { + throw new SclParseException("Required attribute \"lnClass\" not found in FCDA!"); + } + if (fc == null) { + throw new SclParseException("Required attribute \"fc\" not found in FCDA!"); + } + if (!doName.isEmpty()) { + + String objectReference = + iedName + ldInst + "/" + prefix + lnClass + lnInst + "." + doName + daName; + + ModelNode fcdaNode = serverModel.findModelNode(objectReference, fc); + + if (fcdaNode == null) { + throw new SclParseException( + "Specified FCDA: " + + objectReference + + " in DataSet: " + + nameAttribute + + " not found in Model."); + } + dsMembers.add((FcModelNode) fcdaNode); + } else { + String objectReference = iedName + ldInst + "/" + prefix + lnClass + lnInst; + ModelNode logicalNode = serverModel.findModelNode(objectReference, null); + if (logicalNode == null) { + throw new SclParseException( + "Specified FCDA: " + + objectReference + + " in DataSet: " + + nameAttribute + + " not found in Model."); + } + List fcDataObjects = ((LogicalNode) logicalNode).getChildren(fc); + for (FcDataObject dataObj : fcDataObjects) { + dsMembers.add(dataObj); + } + } + } + } + + DataSet dataSet = new DataSet(lNode.getReference().toString() + '.' + name, dsMembers, false); + return dataSet; + } + + private List createReportControlBlocks(Node xmlNode, String parentRef) + throws SclParseException { + + Fc fc = Fc.RP; + NamedNodeMap rcbNodeAttributes = xmlNode.getAttributes(); + Node attribute = rcbNodeAttributes.getNamedItem("buffered"); + if (attribute != null && "true".equalsIgnoreCase(attribute.getNodeValue())) { + fc = Fc.BR; + } + + Node nameAttribute = rcbNodeAttributes.getNamedItem("name"); + if (nameAttribute == null) { + throw new SclParseException("Report Control Block has no name attribute."); + } + + int maxInstances = 1; + for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++) { + Node childNode = xmlNode.getChildNodes().item(i); + + if ("RptEnabled".equals(childNode.getNodeName())) { + Node rptEnabledMaxAttr = childNode.getAttributes().getNamedItem("max"); + if (rptEnabledMaxAttr != null) { + maxInstances = Integer.parseInt(rptEnabledMaxAttr.getNodeValue()); + if (maxInstances < 1 || maxInstances > 99) { + throw new SclParseException( + "Report Control Block max instances should be between 1 and 99 but is: " + + maxInstances); + } + } + } + } + + List rcbInstances = new ArrayList<>(maxInstances); + + for (int z = 1; z <= maxInstances; z++) { + + ObjectReference reportObjRef; + + if (maxInstances == 1) { + + reportObjRef = new ObjectReference(parentRef + "." + nameAttribute.getNodeValue()); + } else { + reportObjRef = + new ObjectReference( + parentRef + "." + nameAttribute.getNodeValue() + String.format("%02d", z)); + } + + BdaTriggerConditions trigOps = + new BdaTriggerConditions(new ObjectReference(reportObjRef + ".TrgOps"), fc); + BdaOptFlds optFields = new BdaOptFlds(new ObjectReference(reportObjRef + ".OptFlds"), fc); + for (int i = 0; i < xmlNode.getChildNodes().getLength(); i++) { + Node childNode = xmlNode.getChildNodes().item(i); + if (childNode.getNodeName().equals("TrgOps")) { + + NamedNodeMap attributes = childNode.getAttributes(); + + if (attributes != null) { + for (int j = 0; j < attributes.getLength(); j++) { + Node node = attributes.item(j); + String nodeName = node.getNodeName(); + + if ("dchg".equals(nodeName)) { + trigOps.setDataChange(node.getNodeValue().equalsIgnoreCase("true")); + } else if ("qchg".equals(nodeName)) { + trigOps.setQualityChange(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("dupd".equals(nodeName)) { + trigOps.setDataUpdate(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("period".equals(nodeName)) { + trigOps.setIntegrity(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("gi".equals(nodeName)) { + trigOps.setGeneralInterrogation(node.getNodeValue().equalsIgnoreCase("true")); + } + } + } + } else if ("OptFields".equals(childNode.getNodeName())) { + + NamedNodeMap attributes = childNode.getAttributes(); + + if (attributes != null) { + for (int j = 0; j < attributes.getLength(); j++) { + + Node node = attributes.item(j); + String nodeName = node.getNodeName(); + + if ("seqNum".equals(nodeName)) { + optFields.setSequenceNumber(node.getNodeValue().equalsIgnoreCase("true")); + } else if ("timeStamp".equals(nodeName)) { + optFields.setReportTimestamp(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("reasonCode".equals(nodeName)) { + optFields.setReasonForInclusion(node.getNodeValue().equalsIgnoreCase("true")); + + } else if ("dataSet".equals(nodeName)) { + optFields.setDataSetName(node.getNodeValue().equalsIgnoreCase("true")); + + } + // not supported for now + // else if (nodeName.equals("dataRef")) { + // optFields.setDataReference(node.getNodeValue().equals("true")); + // + // } + else if (nodeName.equals("bufOvfl")) { + optFields.setBufferOverflow(node.getNodeValue().equalsIgnoreCase("true")); + + } else if (nodeName.equals("entryID")) { + optFields.setEntryId(node.getNodeValue().equalsIgnoreCase("true")); + } + // not supported for now: + // else if (nodeName.equals("configRef")) { + // optFields.setConfigRevision(node.getNodeValue().equals("true")); + // } + } + } + } else if ("RptEnabled".equals(childNode.getNodeName())) { + Node rptEnabledMaxAttr = childNode.getAttributes().getNamedItem("max"); + if (rptEnabledMaxAttr != null) { + maxInstances = Integer.parseInt(rptEnabledMaxAttr.getNodeValue()); + if (maxInstances < 1 || maxInstances > 99) { + throw new SclParseException( + "Report Control Block max instances should be between 1 and 99 but is: " + + maxInstances); + } + } + } + } + + if (fc == Fc.RP) { + optFields.setEntryId(false); + optFields.setBufferOverflow(false); + } + + List children = new ArrayList<>(); + + BdaVisibleString rptId = + new BdaVisibleString( + new ObjectReference(reportObjRef.toString() + ".RptID"), fc, "", 129, false, false); + attribute = rcbNodeAttributes.getNamedItem("rptID"); + if (attribute != null) { + rptId.setValue(attribute.getNodeValue().getBytes(UTF_8)); + } else { + rptId.setValue(reportObjRef.toString()); + } + + children.add(rptId); + + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef.toString() + ".RptEna"), fc, "", false, false)); + + if (fc == Fc.RP) { + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef.toString() + ".Resv"), fc, "", false, false)); + } + + BdaVisibleString datSet = + new BdaVisibleString( + new ObjectReference(reportObjRef.toString() + ".DatSet"), fc, "", 129, false, false); + + attribute = xmlNode.getAttributes().getNamedItem("datSet"); + if (attribute != null) { + String nodeValue = attribute.getNodeValue(); + String dataSetName = parentRef + "$" + nodeValue; + datSet.setValue(dataSetName.getBytes(UTF_8)); + } + children.add(datSet); + + BdaInt32U confRef = + new BdaInt32U( + new ObjectReference(reportObjRef.toString() + ".ConfRev"), fc, "", false, false); + attribute = xmlNode.getAttributes().getNamedItem("confRev"); + if (attribute == null) { + throw new SclParseException( + "Report Control Block does not contain mandatory attribute confRev"); + } + confRef.setValue(Long.parseLong(attribute.getNodeValue())); + children.add(confRef); + + children.add(optFields); + + BdaInt32U bufTm = + new BdaInt32U( + new ObjectReference(reportObjRef.toString() + ".BufTm"), fc, "", false, false); + attribute = xmlNode.getAttributes().getNamedItem("bufTime"); + if (attribute != null) { + bufTm.setValue(Long.parseLong(attribute.getNodeValue())); + } + children.add(bufTm); + + children.add( + new BdaInt8U( + new ObjectReference(reportObjRef.toString() + ".SqNum"), fc, "", false, false)); + + children.add(trigOps); + + BdaInt32U intgPd = + new BdaInt32U( + new ObjectReference(reportObjRef.toString() + ".IntgPd"), fc, "", false, false); + attribute = xmlNode.getAttributes().getNamedItem("intgPd"); + if (attribute != null) { + intgPd.setValue(Long.parseLong(attribute.getNodeValue())); + } + children.add(intgPd); + + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef.toString() + ".GI"), fc, "", false, false)); + + Rcb rcb = null; + + if (fc == Fc.BR) { + + children.add( + new BdaBoolean( + new ObjectReference(reportObjRef.toString() + ".PurgeBuf"), fc, "", false, false)); + + children.add( + new BdaOctetString( + new ObjectReference(reportObjRef.toString() + ".EntryID"), + fc, + "", + 8, + false, + false)); + + children.add( + new BdaEntryTime( + new ObjectReference(reportObjRef.toString() + ".TimeOfEntry"), + fc, + "", + false, + false)); + + if (useResvTmsAttributes) { + children.add( + new BdaInt16( + new ObjectReference(reportObjRef.toString() + ".ResvTms"), fc, "", false, false)); + } + + children.add( + new BdaOctetString( + new ObjectReference(reportObjRef.toString() + ".Owner"), fc, "", 64, false, false)); + + rcb = new Brcb(reportObjRef, children); + + } else { + children.add( + new BdaOctetString( + new ObjectReference(reportObjRef.toString() + ".Owner"), fc, "", 64, false, false)); + + rcb = new Urcb(reportObjRef, children); + } + + rcbInstances.add(rcb); + } + + return rcbInstances; + } + + private List createFcDataObjects( + String name, String parentRef, String doTypeID, Node doiNode) throws SclParseException { + + DoType doType = typeDefinitions.getDOType(doTypeID); + + if (doType == null) { + throw new SclParseException("DO type " + doTypeID + " not defined!"); + } + + String ref = parentRef + '.' + name; + + List childNodes = new ArrayList<>(); + + for (Da dattr : doType.das) { + + // look for DAI node with the name of the DA + Node iNodeFound = findINode(doiNode, dattr.getName()); + + if (dattr.getCount() >= 1) { + childNodes.add(createArrayOfDataAttributes(ref + '.' + dattr.getName(), dattr, iNodeFound)); + } else { + childNodes.add( + createDataAttribute( + ref + '.' + dattr.getName(), + dattr.getFc(), + dattr, + iNodeFound, + false, + false, + false)); + } + } + + for (Sdo sdo : doType.sdos) { + + // parsing Arrays of SubDataObjects is ignored for now because no SCL file was found to test + // against. The + // only DO that contains an Array of SDOs is Harmonic Value (HMV). The Kalkitech SCL Manager + // handles the + // array of SDOs in HMV as an array of DAs. + + Node iNodeFound = findINode(doiNode, sdo.getName()); + + childNodes.addAll(createFcDataObjects(sdo.getName(), ref, sdo.getType(), iNodeFound)); + } + + Map> subFCDataMap = new LinkedHashMap<>(); + + for (Fc fc : Fc.values()) { + subFCDataMap.put(fc, new ArrayList<>()); + } + + for (ModelNode childNode : childNodes) { + subFCDataMap.get(((FcModelNode) childNode).getFc()).add((FcModelNode) childNode); + } + + List fcDataObjects = new ArrayList<>(); + ObjectReference objectReference = new ObjectReference(ref); + + for (Fc fc : Fc.values()) { + if (subFCDataMap.get(fc).size() > 0) { + fcDataObjects.add(new FcDataObject(objectReference, fc, subFCDataMap.get(fc))); + } + } + + return fcDataObjects; + } + + private Node findINode(Node iNode, String dattrName) { + + if (iNode == null) { + return null; + } + + for (int i = 0; i < iNode.getChildNodes().getLength(); i++) { + Node childNode = iNode.getChildNodes().item(i); + if (childNode.getAttributes() != null) { + Node nameAttribute = childNode.getAttributes().getNamedItem("name"); + if (nameAttribute != null && nameAttribute.getNodeValue().equals(dattrName)) { + return childNode; + } + } + } + return null; + } + + private Array createArrayOfDataAttributes(String ref, Da dataAttribute, Node iXmlNode) + throws SclParseException { + + Fc fc = dataAttribute.getFc(); + int size = dataAttribute.getCount(); + + List arrayItems = new ArrayList<>(); + for (int i = 0; i < size; i++) { + // TODO go down the iXmlNode using the ix attribute? + arrayItems.add( + createDataAttribute( + ref + '(' + i + ')', + fc, + dataAttribute, + iXmlNode, + dataAttribute.isDchg(), + dataAttribute.isDupd(), + dataAttribute.isQchg())); + } + + return new Array(new ObjectReference(ref), fc, arrayItems); + } + + /** returns a ConstructedDataAttribute or BasicDataAttribute */ + private FcModelNode createDataAttribute( + String ref, + Fc fc, + AbstractDataAttribute dattr, + Node iXmlNode, + boolean dchg, + boolean dupd, + boolean qchg) + throws SclParseException { + + if (dattr instanceof Da) { + Da dataAttribute = (Da) dattr; + dchg = dataAttribute.isDchg(); + dupd = dataAttribute.isDupd(); + qchg = dataAttribute.isQchg(); + } + + String bType = dattr.getbType(); + + if (bType.equals("Struct")) { + DaType datype = typeDefinitions.getDaType(dattr.getType()); + + if (datype == null) { + throw new SclParseException("DAType " + dattr.getbType() + " not declared!"); + } + + List subDataAttributes = new ArrayList<>(); + for (Bda bda : datype.bdas) { + + Node iNodeFound = findINode(iXmlNode, bda.getName()); + + subDataAttributes.add( + createDataAttribute(ref + '.' + bda.getName(), fc, bda, iNodeFound, dchg, dupd, qchg)); + } + return new ConstructedDataAttribute(new ObjectReference(ref), fc, subDataAttributes); + } + + String val = null; + String sAddr = null; + if (iXmlNode != null) { + NamedNodeMap attributeMap = iXmlNode.getAttributes(); + Node sAddrAttribute = attributeMap.getNamedItem("sAddr"); + if (sAddrAttribute != null) { + sAddr = sAddrAttribute.getNodeValue(); + } + + NodeList elements = iXmlNode.getChildNodes(); + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + if (node.getNodeName().equals("Val")) { + val = node.getTextContent(); + } + } + if (val == null) { + // insert value from DA element + val = dattr.value; + } + } + + if (bType.equals("BOOLEAN")) { + BdaBoolean bda = new BdaBoolean(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + if (val.equalsIgnoreCase("true") || val.equals("1")) { + bda.setValue(true); + } else if (val.equalsIgnoreCase("false") || val.equals("0")) { + bda.setValue(false); + } else { + throw new SclParseException("invalid boolean configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT8")) { + BdaInt8 bda = new BdaInt8(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Byte.parseByte(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT8 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT16")) { + BdaInt16 bda = new BdaInt16(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Short.parseShort(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT16 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT32")) { + BdaInt32 bda = new BdaInt32(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Integer.parseInt(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT32 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT64")) { + BdaInt64 bda = new BdaInt64(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Long.parseLong(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT64 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT128")) { + BdaInt128 bda = new BdaInt128(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Long.parseLong(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT128 configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT8U")) { + BdaInt8U bda = new BdaInt8U(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Short.parseShort(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT8U configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT16U")) { + BdaInt16U bda = new BdaInt16U(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Integer.parseInt(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT16U configured value: " + val); + } + } + return bda; + } else if (bType.equals("INT32U")) { + BdaInt32U bda = new BdaInt32U(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setValue(Long.parseLong(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid INT32U configured value: " + val); + } + } + return bda; + } else if (bType.equals("FLOAT32")) { + BdaFloat32 bda = new BdaFloat32(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setFloat(Float.parseFloat(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid FLOAT32 configured value: " + val); + } + } + return bda; + } else if (bType.equals("FLOAT64")) { + BdaFloat64 bda = new BdaFloat64(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + try { + bda.setDouble(Double.parseDouble(val)); + } catch (NumberFormatException e) { + throw new SclParseException("invalid FLOAT64 configured value: " + val); + } + } + return bda; + } else if (bType.startsWith("VisString")) { + BdaVisibleString bda = + new BdaVisibleString( + new ObjectReference(ref), + fc, + sAddr, + Integer.parseInt(dattr.getbType().substring(9)), + dchg, + dupd); + if (val != null) { + bda.setValue(val.getBytes(UTF_8)); + } + return bda; + } else if (bType.startsWith("Unicode")) { + BdaUnicodeString bda = + new BdaUnicodeString( + new ObjectReference(ref), + fc, + sAddr, + Integer.parseInt(dattr.getbType().substring(7)), + dchg, + dupd); + if (val != null) { + bda.setValue(val.getBytes(UTF_8)); + } + return bda; + } else if (bType.startsWith("Octet")) { + BdaOctetString bda = + new BdaOctetString( + new ObjectReference(ref), + fc, + sAddr, + Integer.parseInt(dattr.getbType().substring(5)), + dchg, + dupd); + if (val != null) { + // TODO + // throw new SclParseException("parsing configured value for octet string is not supported + // yet."); + } + return bda; + } else if (bType.equals("Quality")) { + return new BdaQuality(new ObjectReference(ref), fc, sAddr, qchg); + } else if (bType.equals("Check")) { + return new BdaCheck(new ObjectReference(ref)); + } else if (bType.equals("Dbpos")) { + return new BdaDoubleBitPos(new ObjectReference(ref), fc, sAddr, dchg, dupd); + } else if (bType.equals("Tcmd")) { + return new BdaTapCommand(new ObjectReference(ref), fc, sAddr, dchg, dupd); + } else if (bType.equals("OptFlds")) { + return new BdaOptFlds(new ObjectReference(ref), fc); + } else if (bType.equals("TrgOps")) { + return new BdaTriggerConditions(new ObjectReference(ref), fc); + } else if (bType.equals("EntryID")) { + return new BdaOctetString(new ObjectReference(ref), fc, sAddr, 8, dchg, dupd); + } else if (bType.equals("EntryTime")) { + return new BdaEntryTime(new ObjectReference(ref), fc, sAddr, dchg, dupd); + } else if (bType.equals("PhyComAddr")) { + // TODO not correct! + return new BdaOctetString(new ObjectReference(ref), fc, sAddr, 6, dchg, dupd); + } else if (bType.equals("Timestamp")) { + BdaTimestamp bda = new BdaTimestamp(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + // TODO + throw new SclParseException("parsing configured value for TIMESTAMP is not supported yet."); + } + return bda; + } else if (bType.equals("Enum")) { + String type = dattr.getType(); + if (type == null) { + throw new SclParseException("The exact type of the enumeration is not set."); + } + EnumType enumType = typeDefinitions.getEnumType(type); + + if (enumType == null) { + throw new SclParseException("Definition of enum type: " + type + " not found."); + } + + if (enumType.max > 127 || enumType.min < -128) { + BdaInt16 bda = new BdaInt16(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + for (EnumVal enumVal : enumType.getValues()) { + if (val.equals(enumVal.getId())) { + bda.setValue((short) enumVal.getOrd()); + return bda; + } + } + throw new SclParseException("unknown enum value: " + val); + } + return bda; + } else { + BdaInt8 bda = new BdaInt8(new ObjectReference(ref), fc, sAddr, dchg, dupd); + if (val != null) { + for (EnumVal enumVal : enumType.getValues()) { + if (val.equals(enumVal.getId())) { + bda.setValue((byte) enumVal.getOrd()); + return bda; + } + } + throw new SclParseException("unknown enum value: " + val); + } + return bda; + } + } else if (bType.equals("ObjRef")) { + BdaVisibleString bda = + new BdaVisibleString(new ObjectReference(ref), fc, sAddr, 129, dchg, dupd); + if (val != null) { + bda.setValue(val.getBytes(UTF_8)); + } + return bda; + } else { + throw new SclParseException("Invalid bType: " + bType); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ServerAssociation.java b/src/main/java/com/beanit/iec61850bean/ServerAssociation.java new file mode 100644 index 0000000..dde88d3 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ServerAssociation.java @@ -0,0 +1,1651 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.asn1bean.ber.types.string.BerVisibleString; +import com.beanit.iec61850bean.internal.BerBoolean; +import com.beanit.iec61850bean.internal.NamedThreadFactory; +import com.beanit.iec61850bean.internal.mms.asn1.AccessResult; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedErrorPDU; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedRequestPDU; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedResponsePDU; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceRequest; +import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceResponse; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.DataAccessError; +import com.beanit.iec61850bean.internal.mms.asn1.DefineNamedVariableListRequest; +import com.beanit.iec61850bean.internal.mms.asn1.DefineNamedVariableListResponse; +import com.beanit.iec61850bean.internal.mms.asn1.DeleteNamedVariableListRequest; +import com.beanit.iec61850bean.internal.mms.asn1.DeleteNamedVariableListResponse; +import com.beanit.iec61850bean.internal.mms.asn1.GetNameListRequest; +import com.beanit.iec61850bean.internal.mms.asn1.GetNameListResponse; +import com.beanit.iec61850bean.internal.mms.asn1.GetNameListResponse.ListOfIdentifier; +import com.beanit.iec61850bean.internal.mms.asn1.GetNamedVariableListAttributesResponse; +import com.beanit.iec61850bean.internal.mms.asn1.GetVariableAccessAttributesRequest; +import com.beanit.iec61850bean.internal.mms.asn1.GetVariableAccessAttributesResponse; +import com.beanit.iec61850bean.internal.mms.asn1.Identifier; +import com.beanit.iec61850bean.internal.mms.asn1.InitiateRequestPDU; +import com.beanit.iec61850bean.internal.mms.asn1.InitiateResponsePDU; +import com.beanit.iec61850bean.internal.mms.asn1.Integer16; +import com.beanit.iec61850bean.internal.mms.asn1.Integer32; +import com.beanit.iec61850bean.internal.mms.asn1.Integer8; +import com.beanit.iec61850bean.internal.mms.asn1.MMSpdu; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectName.DomainSpecific; +import com.beanit.iec61850bean.internal.mms.asn1.ParameterSupportOptions; +import com.beanit.iec61850bean.internal.mms.asn1.ReadRequest; +import com.beanit.iec61850bean.internal.mms.asn1.ReadResponse; +import com.beanit.iec61850bean.internal.mms.asn1.ReadResponse.ListOfAccessResult; +import com.beanit.iec61850bean.internal.mms.asn1.ServiceError.ErrorClass; +import com.beanit.iec61850bean.internal.mms.asn1.ServiceSupportOptions; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure; +import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure.Components; +import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification; +import com.beanit.iec61850bean.internal.mms.asn1.Unsigned32; +import com.beanit.iec61850bean.internal.mms.asn1.VariableAccessSpecification; +import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs; +import com.beanit.iec61850bean.internal.mms.asn1.WriteRequest; +import com.beanit.iec61850bean.internal.mms.asn1.WriteResponse; +import com.beanit.josistack.AcseAssociation; +import com.beanit.josistack.ByteBufferInputStream; +import com.beanit.josistack.DecodingException; +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeoutException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class ServerAssociation { + + private static final Logger logger = LoggerFactory.getLogger(ServerAssociation.class); + + private static final WriteResponse.CHOICE writeSuccess = new WriteResponse.CHOICE(); + private static String[] mmsFcs = { + "MX", "ST", "CO", "CF", "DC", "SP", "SG", "RP", "LG", "BR", "GO", "GS", "SV", "SE", "EX", "SR", + "OR", "BL" + }; + + static { + writeSuccess.setSuccess(new BerNull()); + } + + final ServerModel serverModel; + private final ServerSap serverSap; + private final ReverseByteArrayOutputStream reverseOStream = + new ReverseByteArrayOutputStream(500, true); + ScheduledExecutorService executor = null; + HashMap nonPersistentDataSets = new HashMap<>(); + List selects = new ArrayList<>(); + List rsvdURCBs = new ArrayList<>(); + private AcseAssociation acseAssociation = null; + private int negotiatedMaxPduSize; + private ByteBuffer pduBuffer; + private boolean insertRef; + private String continueAfter; + + public ServerAssociation(ServerSap serverSap) { + this.serverSap = serverSap; + serverModel = serverSap.serverModel; + executor = + Executors.newScheduledThreadPool( + 2, new NamedThreadFactory("iec61850bean-server-connection")); + } + + private static void insertMmsRef(ModelNode node, List mmsRefs, String parentRef) { + String ref = parentRef + '$' + node.getName(); + mmsRefs.add(ref); + if (!(node instanceof Array)) { + for (ModelNode childNode : node) { + insertMmsRef(childNode, mmsRefs, ref); + } + } + } + + private static String convertToDataSetReference(ObjectName mmsObjectName) { + if (mmsObjectName.getDomainSpecific() != null) { + return mmsObjectName.getDomainSpecific().getDomainID().toString() + + "/" + + mmsObjectName.getDomainSpecific().getItemID().toString().replace('$', '.'); + } else if (mmsObjectName.getAaSpecific() != null) { + // format is "@DataSetName" + return mmsObjectName.getAaSpecific().toString(); + } + return null; + } + + public void handleNewAssociation(AcseAssociation acseAssociation, ByteBuffer associationRequest) { + + this.acseAssociation = acseAssociation; + + try { + associate(acseAssociation, associationRequest); + } catch (IOException e) { + logger.warn("Error during association build up", e); + return; + } + + handleConnection(); + } + + private void associate(AcseAssociation acseAssociation, ByteBuffer associationRequest) + throws IOException { + + MMSpdu mmsPdu = new MMSpdu(); + + mmsPdu.decode(new ByteBufferInputStream(associationRequest), null); + + MMSpdu initiateResponseMmsPdu = constructAssociationResponsePdu(mmsPdu.getInitiateRequestPDU()); + + initiateResponseMmsPdu.encode(reverseOStream); + + acseAssociation.accept(reverseOStream.getByteBuffer()); + } + + private MMSpdu constructAssociationResponsePdu(InitiateRequestPDU associationRequestMMSpdu) { + + negotiatedMaxPduSize = serverSap.getMaxMmsPduSize(); + + if (associationRequestMMSpdu.getLocalDetailCalling() != null) { + int proposedMaxMmsPduSize = associationRequestMMSpdu.getLocalDetailCalling().intValue(); + if (negotiatedMaxPduSize > proposedMaxMmsPduSize + && proposedMaxMmsPduSize >= ServerSap.MINIMUM_MMS_PDU_SIZE) { + negotiatedMaxPduSize = proposedMaxMmsPduSize; + } + } + + int negotiatedMaxServOutstandingCalling = serverSap.getProposedMaxServOutstandingCalling(); + int proposedMaxServOutstandingCalling = + associationRequestMMSpdu.getProposedMaxServOutstandingCalling().intValue(); + + if (negotiatedMaxServOutstandingCalling > proposedMaxServOutstandingCalling + && proposedMaxServOutstandingCalling > 0) { + negotiatedMaxServOutstandingCalling = proposedMaxServOutstandingCalling; + } + + int negotiatedMaxServOutstandingCalled = serverSap.getProposedMaxServOutstandingCalled(); + int proposedMaxServOutstandingCalled = + associationRequestMMSpdu.getProposedMaxServOutstandingCalled().intValue(); + + if (negotiatedMaxServOutstandingCalled > proposedMaxServOutstandingCalled + && proposedMaxServOutstandingCalled > 0) { + negotiatedMaxServOutstandingCalled = proposedMaxServOutstandingCalled; + } + + int negotiatedDataStructureNestingLevel = serverSap.getProposedDataStructureNestingLevel(); + + if (associationRequestMMSpdu.getProposedDataStructureNestingLevel() != null) { + int proposedDataStructureNestingLevel = + associationRequestMMSpdu.getProposedDataStructureNestingLevel().intValue(); + if (negotiatedDataStructureNestingLevel > proposedDataStructureNestingLevel) { + negotiatedDataStructureNestingLevel = proposedDataStructureNestingLevel; + } + } + + pduBuffer = ByteBuffer.allocate(negotiatedMaxPduSize + 500); + + byte[] negotiatedParameterCbbBitString = serverSap.cbbBitString; + + byte[] servicesSupportedCalledBitString = serverSap.servicesSupportedCalled; + + InitiateResponsePDU.InitResponseDetail initRespDetail = + new InitiateResponsePDU.InitResponseDetail(); + initRespDetail.setNegotiatedVersionNumber(new Integer16(1)); + initRespDetail.setNegotiatedParameterCBB( + new ParameterSupportOptions( + negotiatedParameterCbbBitString, negotiatedParameterCbbBitString.length * 8 - 5)); + initRespDetail.setServicesSupportedCalled( + new ServiceSupportOptions( + servicesSupportedCalledBitString, servicesSupportedCalledBitString.length * 8 - 3)); + + InitiateResponsePDU initRespPdu = new InitiateResponsePDU(); + initRespPdu.setLocalDetailCalled(new Integer32(negotiatedMaxPduSize)); + initRespPdu.setNegotiatedMaxServOutstandingCalling( + new Integer16(negotiatedMaxServOutstandingCalling)); + initRespPdu.setNegotiatedMaxServOutstandingCalled( + new Integer16(negotiatedMaxServOutstandingCalled)); + initRespPdu.setNegotiatedDataStructureNestingLevel( + new Integer8(negotiatedDataStructureNestingLevel)); + initRespPdu.setInitResponseDetail(initRespDetail); + + MMSpdu initiateResponseMMSpdu = new MMSpdu(); + initiateResponseMMSpdu.setInitiateResponsePDU(initRespPdu); + + return initiateResponseMMSpdu; + } + + private void handleConnection() { + + while (true) { + + MMSpdu mmsRequestPdu = listenForMmsRequest(acseAssociation); + if (mmsRequestPdu == null) { + return; + } + + ConfirmedRequestPDU confirmedRequestPdu = mmsRequestPdu.getConfirmedRequestPDU(); + // Do not have to check whether confirmedRequestPdu is null because that was already done by + // listenForMmsRequest() + + if (confirmedRequestPdu.getInvokeID() == null) { + // cannot respond with ServiceError because no InvokeID was received + logger.warn("Got unexpected MMS PDU or no invokeID"); + continue; + } + int invokeId = confirmedRequestPdu.getInvokeID().intValue(); + + try { + if (confirmedRequestPdu.getService() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Got an invalid MMS packet: confirmedServiceRequest empty"); + } + + ConfirmedServiceRequest confirmedServiceRequest = confirmedRequestPdu.getService(); + + ConfirmedServiceResponse confirmedServiceResponse = new ConfirmedServiceResponse(); + + if (confirmedServiceRequest.getGetNameList() != null) { + + GetNameListRequest getNameListRequest = confirmedServiceRequest.getGetNameList(); + GetNameListResponse response = null; + + if (getNameListRequest.getObjectClass().getBasicObjectClass() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Got an invalid MMS packet: ObjectClass was not selected in GetNameList request"); + } + + long basicObjectClass = + getNameListRequest.getObjectClass().getBasicObjectClass().longValue(); + if (basicObjectClass == 9) { + logger.debug("Got a GetServerDirectory (MMS GetNameList[DOMAIN]) request"); + response = handleGetServerDirectoryRequest(); + } else if (basicObjectClass == 0) { + logger.debug("Got a Get{LD|LN}Directory (MMS GetNameList[NAMED_VARIABLE]) request"); + response = handleGetDirectoryRequest(getNameListRequest); + } else if (basicObjectClass == 2) { + logger.debug( + "Got a GetLogicalNodeDirectory[DataSet] (MMS GetNameList[NAMED_VARIABLE_LIST]) request"); + response = handleGetDataSetNamesRequest(getNameListRequest); + } else { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_SERVER_CONSTRAINT, + "Unable to handle Get directory request for basic object class: " + + basicObjectClass); + } + // else if (basicObjectClass == 8) { + // logger.debug("Got a GetLogicalNodeDirectory[Log] (MMS GetNameList[JOURNAL]) request"); + // response = + // handleGetNameListJournalRequest(getNameListRequest); + // } + + confirmedServiceResponse.setGetNameList(response); + + } else if (confirmedServiceRequest.getGetVariableAccessAttributes() != null) { + logger.debug( + "Got a GetDataDirectory/GetDataDefinition (MMS GetVariableAccessAttributes) request"); + GetVariableAccessAttributesResponse response = + handleGetVariableAccessAttributesRequest( + confirmedServiceRequest.getGetVariableAccessAttributes()); + + confirmedServiceResponse.setGetVariableAccessAttributes(response); + + } else if (confirmedServiceRequest.getRead() != null) { + // GetDataValues, GetDataSetValues, GetBRCBValues and GetURCBValues map to this + ReadResponse response = handleGetDataValuesRequest(confirmedServiceRequest.getRead()); + + confirmedServiceResponse.setRead(response); + } else if (confirmedServiceRequest.getWrite() != null) { + logger.debug("Got a Write request"); + + WriteResponse response = handleSetDataValuesRequest(confirmedServiceRequest.getWrite()); + + confirmedServiceResponse.setWrite(response); + + } + // for Data Sets + else if (confirmedServiceRequest.getDefineNamedVariableList() != null) { + logger.debug("Got a CreateDataSet request"); + + DefineNamedVariableListResponse response = + handleCreateDataSetRequest(confirmedServiceRequest.getDefineNamedVariableList()); + + confirmedServiceResponse.setDefineNamedVariableList(response); + } else if (confirmedServiceRequest.getGetNamedVariableListAttributes() != null) { + logger.debug("Got a GetDataSetDirectory request"); + GetNamedVariableListAttributesResponse response = + handleGetDataSetDirectoryRequest( + confirmedServiceRequest.getGetNamedVariableListAttributes()); + + confirmedServiceResponse.setGetNamedVariableListAttributes(response); + + } else if (confirmedServiceRequest.getDeleteNamedVariableList() != null) { + logger.debug("Got a DeleteDataSet request"); + DeleteNamedVariableListResponse response = + handleDeleteDataSetRequest(confirmedServiceRequest.getDeleteNamedVariableList()); + + confirmedServiceResponse.setDeleteNamedVariableList(response); + } else { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "invalid MMS packet: unknown request type."); + } + + ConfirmedResponsePDU confirmedResponsePdu = new ConfirmedResponsePDU(); + confirmedResponsePdu.setInvokeID(confirmedRequestPdu.getInvokeID()); + confirmedResponsePdu.setService(confirmedServiceResponse); + + MMSpdu mmsResponsePdu = new MMSpdu(); + mmsResponsePdu.setConfirmedResponsePDU(confirmedResponsePdu); + + if (!sendAnMmsPdu(mmsResponsePdu)) { + return; + } + } catch (ServiceError e) { + logger.warn(e.getMessage()); + if (!sendAnMmsPdu(createServiceErrorResponse(e, invokeId))) { + return; + } + } + } + } + + void cleanUpConnection() { + synchronized (serverModel) { + for (FcModelNode selectedCdo : selects) { + selectedCdo.deselect(); + } + for (Urcb rsvdUrcb : rsvdURCBs) { + synchronized (rsvdUrcb) { + if (rsvdUrcb.enabled) { + rsvdUrcb.disable(); + } + rsvdUrcb.reserved = null; + rsvdUrcb.getResv().setValue(false); + } + } + } + } + + boolean sendAnMmsPdu(MMSpdu mmsResponsePdu) { + + synchronized (reverseOStream) { + reverseOStream.reset(); + try { + mmsResponsePdu.encode(reverseOStream); + } catch (IOException e1) { + logger.error("IOException while encoding MMS PDU. Closing association.", e1); + return false; + } + try { + acseAssociation.send(reverseOStream.getByteBuffer()); + } catch (IOException e) { + logger.warn("IOException while sending MMS PDU. Closing association.", e); + return false; + } + } + return true; + } + + private MMSpdu listenForMmsRequest(AcseAssociation acseAssociation) { + + while (true) { + MMSpdu mmsRequestPdu; + byte[] buffer; + pduBuffer.clear(); + try { + buffer = acseAssociation.receive(pduBuffer); + } catch (EOFException e) { + logger.debug("Connection was closed by client."); + return null; + } catch (SocketTimeoutException e) { + logger.warn( + "Message fragment timeout occured while receiving request. Closing association.", e); + return null; + } catch (IOException e) { + logger.warn( + "IOException at lower layers while listening for incoming request. Closing association.", + e); + return null; + } catch (DecodingException e) { + logger.error("Error decoding request at OSI layers.", e); + continue; + } catch (TimeoutException e) { + logger.error( + "Illegal state: message timeout while receiving request though this timeout should 0 and never be thrown", + e); + return null; + } + mmsRequestPdu = new MMSpdu(); + + try { + mmsRequestPdu.decode(new ByteArrayInputStream(buffer), null); + } catch (IOException e) { + logger.warn("IOException decoding received MMS request PDU.", e); + continue; + } + + if (mmsRequestPdu.getConfirmedRequestPDU() == null) { + if (mmsRequestPdu.getConcludeRequestPDU() != null) { + logger.debug("Got Conclude request, will close connection"); + return null; + } else { + logger.warn("Got unexpected MMS PDU, will ignore it"); + continue; + } + } + + return mmsRequestPdu; + } + } + + private MMSpdu createServiceErrorResponse(ServiceError e, int invokeId) { + + ErrorClass errClass = new ErrorClass(); + + switch (e.getErrorCode()) { + case ServiceError.NO_ERROR: + break; + case ServiceError.INSTANCE_NOT_AVAILABLE: + errClass.setAccess(new BerInteger(e.getErrorCode())); + break; + case ServiceError.INSTANCE_IN_USE: + errClass.setDefinition(new BerInteger(e.getErrorCode())); + break; + case ServiceError.ACCESS_VIOLATION: + errClass.setAccess(new BerInteger(e.getErrorCode())); + break; + case ServiceError.ACCESS_NOT_ALLOWED_IN_CURRENT_STATE: + errClass.setOthers(new BerInteger(e.getErrorCode())); + break; + case ServiceError.INSTANCE_LOCKED_BY_OTHER_CLIENT: + errClass.setFile(new BerInteger(2)); + break; + case ServiceError.TYPE_CONFLICT: + errClass.setFile(new BerInteger(4)); + break; + default: + errClass.setOthers(new BerInteger(e.getErrorCode())); + } + com.beanit.iec61850bean.internal.mms.asn1.ServiceError asn1ServiceError; + + asn1ServiceError = new com.beanit.iec61850bean.internal.mms.asn1.ServiceError(); + asn1ServiceError.setErrorClass(errClass); + asn1ServiceError.setAdditionalDescription(new BerVisibleString(e.getMessage())); + + ConfirmedErrorPDU confirmedErrorPDU = new ConfirmedErrorPDU(); + confirmedErrorPDU.setInvokeID(new Unsigned32(invokeId)); + confirmedErrorPDU.setServiceError(asn1ServiceError); + + MMSpdu mmsPdu = new MMSpdu(); + mmsPdu.setConfirmedErrorPDU(confirmedErrorPDU); + + return mmsPdu; + } + + private GetNameListResponse handleGetServerDirectoryRequest() throws ServiceError { + + ListOfIdentifier listOfIdentifier = new ListOfIdentifier(); + List identifiers = listOfIdentifier.getIdentifier(); + + for (ModelNode ld : serverModel) { + identifiers.add(new Identifier(ld.getName().getBytes(UTF_8))); + } + + GetNameListResponse getNameListResponse = new GetNameListResponse(); + getNameListResponse.setListOfIdentifier(listOfIdentifier); + getNameListResponse.setMoreFollows(new BerBoolean(false)); + + return getNameListResponse; + } + + private GetNameListResponse handleGetDirectoryRequest(GetNameListRequest getNameListRequest) + throws ServiceError { + + // the ObjectScope can be vmdSpecific,domainSpecific, or aaSpecific. vmdSpecific and aaSpecific + // are not part of + // 61850-8-1 but are used by some IEC 61850 clients anyways. This stack will return an empty + // list on vmdSpecific + // and aaSpecific requests. + if (getNameListRequest.getObjectScope().getAaSpecific() != null + || getNameListRequest.getObjectScope().getVmdSpecific() != null) { + ListOfIdentifier listOfIden = new ListOfIdentifier(); + listOfIden.getIdentifier(); + GetNameListResponse getNameListResponse = new GetNameListResponse(); + getNameListResponse.setListOfIdentifier(listOfIden); + getNameListResponse.setMoreFollows(new BerBoolean(false)); + return getNameListResponse; + } + + String mmsDomainId = getNameListRequest.getObjectScope().getDomainSpecific().toString(); + + ModelNode logicalDeviceMn = serverModel.getChild(mmsDomainId); + + if (logicalDeviceMn == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "Got an invalid MMS request: given Domain name in GetNameList request is not a Logical Device name"); + } + + LogicalDevice logicalDevice = (LogicalDevice) logicalDeviceMn; + + insertRef = true; + + if (getNameListRequest.getContinueAfter() != null) { + continueAfter = getNameListRequest.getContinueAfter().toString(); + insertRef = false; + } + + List mmsReferences = new ArrayList<>(); + + for (ModelNode logicalNodeMn : logicalDevice) { + LogicalNode logicalNode = (LogicalNode) logicalNodeMn; + mmsReferences.add(logicalNode.getName()); + + for (String mmsFC : mmsFcs) { + Fc fc = Fc.fromString(mmsFC); + if (fc != null) { + + List fcDataObjects = logicalNode.getChildren(fc); + if (fcDataObjects != null) { + mmsReferences.add(logicalNode.getName() + "$" + mmsFC); + for (FcDataObject dataObject : fcDataObjects) { + insertMmsRef(dataObject, mmsReferences, logicalNode.getName() + "$" + mmsFC); + } + } + } + } + } + + ListOfIdentifier listOfIden = new ListOfIdentifier(); + List identifiers = listOfIden.getIdentifier(); + + int identifierSize = 0; + boolean moreFollows = false; + for (String mmsReference : mmsReferences) { + if (insertRef == true) { + if (identifierSize > negotiatedMaxPduSize - 200) { + moreFollows = true; + logger.debug(" ->maxMMSPduSize of " + negotiatedMaxPduSize + " Bytes reached"); + break; + } + + Identifier identifier; + + identifier = new Identifier(mmsReference.getBytes(UTF_8)); + + identifiers.add(identifier); + identifierSize += mmsReference.length() + 2; + } else { + if (mmsReference.equals(continueAfter)) { + insertRef = true; + } + } + } + + GetNameListResponse getNameListResponse = new GetNameListResponse(); + getNameListResponse.setListOfIdentifier(listOfIden); + getNameListResponse.setMoreFollows(new BerBoolean(moreFollows)); + + return getNameListResponse; + } + + /** + * GetVariableAccessAttributes (GetDataDefinition/GetDataDirectory) can be called with different + * kinds of references. Examples: 1. DGEN1 2. DGEN1$CF 3. DGEN1$CF$GnBlk + */ + private GetVariableAccessAttributesResponse handleGetVariableAccessAttributesRequest( + GetVariableAccessAttributesRequest getVariableAccessAttributesRequest) throws ServiceError { + if (getVariableAccessAttributesRequest.getName() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Got an invalid MMS packet: name is not selected in GetVariableAccessAttributesRequest"); + } + + DomainSpecific domainSpecific = + getVariableAccessAttributesRequest.getName().getDomainSpecific(); + + if (domainSpecific == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Got an invalid MMS packet: Domain specific is not selected in GetVariableAccessAttributesRequest"); + } + + ModelNode modelNode = serverModel.getChild(domainSpecific.getDomainID().toString()); + + if (modelNode == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + + String itemIdString = domainSpecific.getItemID().toString(); + + int index1 = itemIdString.indexOf('$'); + + LogicalNode logicalNode = null; + + if (index1 != -1) { + logicalNode = (LogicalNode) modelNode.getChild(itemIdString.substring(0, index1)); + if (logicalNode == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + int index2 = itemIdString.indexOf('$', index1 + 2); + if (index2 != -1) { + Fc fc = Fc.fromString(itemIdString.substring(index1 + 1, index2)); + if (fc == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + index1 = itemIdString.indexOf('$', index2 + 2); + ModelNode subNode; + if (index1 == -1) { + subNode = logicalNode.getChild(itemIdString.substring(index2 + 1), fc); + if (subNode == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + } else { + subNode = logicalNode.getChild(itemIdString.substring(index2 + 1, index1), fc); + if (subNode == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + index2 = itemIdString.indexOf('$', index1 + 2); + while (index2 != -1) { + subNode = subNode.getChild(itemIdString.substring(index1 + 1, index2)); + if (subNode == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest + .getName() + .getDomainSpecific() + .getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + index1 = index2; + index2 = itemIdString.indexOf('$', index1 + 2); + } + subNode = subNode.getChild(itemIdString.substring(index1 + 1)); + if (subNode == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + } + + GetVariableAccessAttributesResponse getVariableAccessAttributesResponse = + new GetVariableAccessAttributesResponse(); + getVariableAccessAttributesResponse.setMmsDeletable(new BerBoolean(false)); + getVariableAccessAttributesResponse.setTypeDescription(subNode.getMmsTypeSpec()); + + return getVariableAccessAttributesResponse; + } else { + Fc fc = Fc.fromString(itemIdString.substring(index1 + 1)); + + if (fc == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + + List fcDataObjects = logicalNode.getChildren(fc); + + if (fcDataObjects == null || fcDataObjects.size() == 0) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + + Components comp = new Components(); + List doStructComponents = comp.getSEQUENCE(); + for (ModelNode child : fcDataObjects) { + TypeSpecification typeSpecification = new TypeSpecification(); + typeSpecification.setTypeDescription(child.getMmsTypeSpec()); + + TypeDescription.Structure.Components.SEQUENCE structComponent = + new TypeDescription.Structure.Components.SEQUENCE(); + structComponent.setComponentName(new Identifier(child.getName().getBytes(UTF_8))); + structComponent.setComponentType(typeSpecification); + doStructComponents.add(structComponent); + } + + Structure struct = new Structure(); + struct.setComponents(comp); + + TypeDescription typeDescription = new TypeDescription(); + typeDescription.setStructure(struct); + + GetVariableAccessAttributesResponse getVariableAccessAttributesResponse = + new GetVariableAccessAttributesResponse(); + getVariableAccessAttributesResponse.setMmsDeletable(new BerBoolean(false)); + getVariableAccessAttributesResponse.setTypeDescription(typeDescription); + + return getVariableAccessAttributesResponse; + } + } + + logicalNode = (LogicalNode) modelNode.getChild(itemIdString); + if (logicalNode == null) { + throw new ServiceError( + ServiceError.INSTANCE_NOT_AVAILABLE, + "GetVariableAccessAttributes (GetDataDefinition): no object with domainId " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getDomainID() + + " and ItemID " + + getVariableAccessAttributesRequest.getName().getDomainSpecific().getItemID() + + " was found."); + } + + Components components = new Components(); + List structComponents = components.getSEQUENCE(); + + for (String mmsFc : mmsFcs) { + Fc fc = Fc.fromString(mmsFc); + if (fc != null) { + + Collection fcDataObjects = logicalNode.getChildren(fc); + if (fcDataObjects == null) { + continue; + } + + Components comp = new Components(); + List doStructComponents = comp.getSEQUENCE(); + + for (ModelNode child : fcDataObjects) { + TypeSpecification typeSpecification = new TypeSpecification(); + typeSpecification.setTypeDescription(child.getMmsTypeSpec()); + + TypeDescription.Structure.Components.SEQUENCE doStructComponent = + new TypeDescription.Structure.Components.SEQUENCE(); + doStructComponent.setComponentName(new Identifier(child.getName().getBytes(UTF_8))); + doStructComponent.setComponentType(typeSpecification); + + doStructComponents.add(doStructComponent); + } + + Structure struct = new Structure(); + struct.setComponents(comp); + + TypeDescription fcTypeSpec = new TypeDescription(); + fcTypeSpec.setStructure(struct); + + TypeSpecification typeSpecification = new TypeSpecification(); + typeSpecification.setTypeDescription(fcTypeSpec); + + TypeDescription.Structure.Components.SEQUENCE structCom = + new TypeDescription.Structure.Components.SEQUENCE(); + structCom.setComponentName(new Identifier(mmsFc.getBytes(UTF_8))); + structCom.setComponentType(typeSpecification); + + structComponents.add(structCom); + } + } + + Structure struct = new Structure(); + struct.setComponents(components); + + TypeDescription typeSpec = new TypeDescription(); + typeSpec.setStructure(struct); + + GetVariableAccessAttributesResponse getVariableAccessAttributesResponse = + new GetVariableAccessAttributesResponse(); + getVariableAccessAttributesResponse.setMmsDeletable(new BerBoolean(false)); + getVariableAccessAttributesResponse.setTypeDescription(typeSpec); + + return getVariableAccessAttributesResponse; + } + + private ReadResponse handleGetDataValuesRequest(ReadRequest mmsReadRequest) throws ServiceError { + + VariableAccessSpecification variableAccessSpecification = + mmsReadRequest.getVariableAccessSpecification(); + + if (mmsReadRequest.getSpecificationWithResult() == null + || mmsReadRequest.getSpecificationWithResult().value == false) { + + if (variableAccessSpecification.getListOfVariable() == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "handleGetDataValuesRequest: Got an invalid MMS packet"); + } + + List listOfVariable = + variableAccessSpecification.getListOfVariable().getSEQUENCE(); + + if (listOfVariable.size() < 1) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, + "handleGetDataValuesRequest: less than one variableAccessSpecification is not allowed"); + } + + ListOfAccessResult listOfAccessResult = new ListOfAccessResult(); + List accessResults = listOfAccessResult.getAccessResult(); + + synchronized (serverModel) { + for (VariableDefs.SEQUENCE variableDef : listOfVariable) { + + FcModelNode modelNode = serverModel.getNodeFromVariableDef(variableDef); + + if (modelNode == null) { + logger.debug("Got a GetDataValues request for a non existent model node."); + // 10 indicates error "object-non-existent" + AccessResult accessResult = new AccessResult(); + accessResult.setFailure(new DataAccessError(10L)); + accessResults.add(accessResult); + } else { + if (logger.isDebugEnabled()) { + logger.debug("Got a GetDataValues request for node: " + modelNode); + if (!(modelNode instanceof BasicDataAttribute)) { + for (BasicDataAttribute bda : modelNode.getBasicDataAttributes()) { + logger.debug("sub BDA is:" + bda); + } + } + } + accessResults.add(getReadResult(modelNode)); + } + } + } + + ReadResponse readResponse = new ReadResponse(); + readResponse.setListOfAccessResult(listOfAccessResult); + return readResponse; + } else { + logger.debug("Got a GetDataSetValues request."); + + String dataSetReference = + convertToDataSetReference(variableAccessSpecification.getVariableListName()); + + if (dataSetReference == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, + "handleGetDataSetValuesRequest: DataSet name incorrect"); + } + + ListOfAccessResult listOfAccessResult = new ListOfAccessResult(); + List accessResults = listOfAccessResult.getAccessResult(); + + if (dataSetReference.startsWith("@")) { + DataSet dataSet = nonPersistentDataSets.get(dataSetReference); + if (dataSet == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, + "handleGetDataSetValuesRequest: a DataSet with the given reference does not exist"); + } + + for (FcModelNode dsMember : dataSet) { + accessResults.add(getReadResult(dsMember)); + } + } else { + synchronized (serverModel) { + DataSet dataSet = serverModel.getDataSet(dataSetReference); + + if (dataSet == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, + "handleGetDataSetValuesRequest: a DataSet with the given reference does not exist"); + } + + for (FcModelNode dsMember : dataSet) { + accessResults.add(getReadResult(dsMember)); + } + } + } + ReadResponse readResponse = new ReadResponse(); + readResponse.setListOfAccessResult(listOfAccessResult); + return readResponse; + } + } + + private AccessResult getReadResult(FcModelNode modelNode) { + + AccessResult accessResult = new AccessResult(); + + if (modelNode.getFc() == Fc.CO && modelNode.getName().equals("SBO")) { + // if (modelNode.getName().equals("SBO")) { + FcModelNode cdcParent = (FcModelNode) modelNode.getParent(); + ModelNode ctlModelNode = + serverModel.findModelNode(cdcParent.getReference(), Fc.CF).getChild("ctlModel"); + if (ctlModelNode == null + || !(ctlModelNode instanceof BdaInt8) + || ((BdaInt8) ctlModelNode).getValue() != 2) { + logger.warn( + "Selecting controle DO fails because ctlModel is not set to \"sbo-with-normal-security\""); + // 3 indicates error "object_access_denied" + accessResult.setFailure(new DataAccessError(3L)); + return accessResult; + } + if (!cdcParent.select(this, serverSap.timer)) { + Data data = new Data(); + data.setVisibleString(new BerVisibleString("")); + accessResult.setSuccess(data); + return accessResult; + } + Data data = new Data(); + data.setVisibleString(new BerVisibleString("success")); + accessResult.setSuccess(data); + return accessResult; + + // } + // else { + // logger.warn("A client tried to read a control variable other than SBO. This is not + // allowed."); + // // 3 indicates error "object_access_denied" + // return new AccessResult(new BerInteger(3L), null); + // } + + } + + Data data = modelNode.getMmsDataObj(); + + if (data == null) { + // 11 indicates error "object_value_invalid" + accessResult.setFailure(new DataAccessError(11L)); + return accessResult; + } + + accessResult.setSuccess(data); + return accessResult; + } + + private WriteResponse handleSetDataValuesRequest(WriteRequest mmsWriteRequest) + throws ServiceError { + + VariableAccessSpecification variableAccessSpecification = + mmsWriteRequest.getVariableAccessSpecification(); + + List listOfData = mmsWriteRequest.getListOfData().getData(); + + WriteResponse writeResponse = new WriteResponse(); + List mmsResponseValues = writeResponse.getCHOICE(); + + if (variableAccessSpecification.getListOfVariable() != null) { + logger.debug("Got a SetDataValues request."); + + List listOfVariable = + variableAccessSpecification.getListOfVariable().getSEQUENCE(); + + if (listOfVariable.size() < 1 + || listOfData.size() < 1 + || listOfVariable.size() != listOfData.size()) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, + "handleSetDataValuesRequest: less than one variableAccessSpecification or data element is not allowed, or listOfData ne listOfVar"); + } + + Iterator mmsDataIterator = listOfData.iterator(); + + List totalBdasToBeWritten = new ArrayList<>(); + int[] numBdas = new int[listOfData.size()]; + + int i = -1; + synchronized (serverModel) { + for (VariableDefs.SEQUENCE variableDef : listOfVariable) { + i++; + Data mmsData = mmsDataIterator.next(); + + FcModelNode modelNode = serverModel.getNodeFromVariableDef(variableDef); + + if (modelNode == null) { + // 10 indicates error "object-non-existent" + WriteResponse.CHOICE writeResponseChoice = new WriteResponse.CHOICE(); + writeResponseChoice.setFailure(new DataAccessError(10L)); + mmsResponseValues.add(writeResponseChoice); + } else { + + getFirstWriteResults( + mmsResponseValues, totalBdasToBeWritten, numBdas, i, modelNode, mmsData); + } + } + + writeAndFillMissingWriteResults(mmsResponseValues, totalBdasToBeWritten, numBdas); + } + + } else if (variableAccessSpecification.getVariableListName() != null) { + logger.debug("Got a SetDataSetValues request."); + + String dataSetRef = + convertToDataSetReference(variableAccessSpecification.getVariableListName()); + + // TODO handle non-persisten DataSets too + + DataSet dataSet = serverModel.getDataSet(dataSetRef); + + Iterator mmsDataIterator = listOfData.iterator(); + + List totalBdasToBeWritten = new ArrayList<>(); + int[] numBdas = new int[listOfData.size()]; + + int i = -1; + synchronized (serverModel) { + for (FcModelNode dataSetMember : dataSet) { + i++; + Data mmsData = mmsDataIterator.next(); + + getFirstWriteResults( + mmsResponseValues, totalBdasToBeWritten, numBdas, i, dataSetMember, mmsData); + } + + writeAndFillMissingWriteResults(mmsResponseValues, totalBdasToBeWritten, numBdas); + } + + } else { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "handleSetDataValuesRequest: invalid MMS request"); + } + + return writeResponse; + } + + private void writeAndFillMissingWriteResults( + List mmsResponseValues, + List totalBdasToBeWritten, + int[] numBdas) { + int i; + if (totalBdasToBeWritten.size() != 0) { + List serviceErrors = serverSap.serverEventListener.write(totalBdasToBeWritten); + ListIterator mmsResponseIterator = mmsResponseValues.listIterator(); + if (serviceErrors == null || serviceErrors.size() != totalBdasToBeWritten.size()) { + while (mmsResponseIterator.hasNext()) { + if (mmsResponseIterator.next() == null) { + mmsResponseIterator.set(writeSuccess); + } + } + for (BasicDataAttribute bda : totalBdasToBeWritten) { + bda.mirror.setValueFrom(bda); + } + } else { + i = -1; + Iterator serviceErrorIterator = serviceErrors.iterator(); + Iterator bdaToBeWrittenIterator = totalBdasToBeWritten.iterator(); + while (mmsResponseIterator.hasNext()) { + i++; + if (mmsResponseIterator.next() == null) { + for (int j = 0; j < numBdas[i]; j++) { + ServiceError serviceError = serviceErrorIterator.next(); + BasicDataAttribute bda = bdaToBeWrittenIterator.next(); + if (serviceError != null) { + WriteResponse.CHOICE writeResponseChoice = new WriteResponse.CHOICE(); + writeResponseChoice.setFailure( + new DataAccessError(serviceErrorToMmsError(serviceError))); + mmsResponseIterator.set(writeResponseChoice); + } else { + bda.mirror.setValueFrom(bda); + } + } + } + } + } + } + } + + private void getFirstWriteResults( + List mmsResponseValues, + List totalBdasToBeWritten, + int[] numBdas, + int i, + FcModelNode fcModelNode, + Data mmsData) { + WriteResponse.CHOICE writeResult = getWriteResult(fcModelNode, mmsData); + if (writeResult == null) { + FcModelNode fcModelNodeCopy = (FcModelNode) fcModelNode.copy(); + try { + fcModelNodeCopy.setValueFromMmsDataObj(mmsData); + } catch (ServiceError e) { + logger.warn("SetDataValues failed because of data missmatch.", e); + WriteResponse.CHOICE writeResponseChoice = new WriteResponse.CHOICE(); + writeResponseChoice.setFailure(new DataAccessError(serviceErrorToMmsError(e))); + mmsResponseValues.add(writeResponseChoice); + return; + } + + if (fcModelNodeCopy.fc == Fc.CO) { + // TODO timeactivate operate + fcModelNodeCopy = (FcModelNode) fcModelNodeCopy.getChild("ctlVal"); + // TODO write origin and ctlNum if they exist + } else { + + } + + List bdas = fcModelNodeCopy.getBasicDataAttributes(); + totalBdasToBeWritten.addAll(bdas); + numBdas[i] = bdas.size(); + mmsResponseValues.add(null); + + } else { + mmsResponseValues.add(writeResult); + } + } + + // private WriteResponse.SubChoice operate(FcModelNode modelNode, Data mmsData) { + // FcModelNode fcModelNodeCopy = (FcModelNode) modelNode.copy(); + // try { + // fcModelNodeCopy.setValueFromMmsDataObj(mmsData); + // } catch (ServiceError e) { + // logger.warn("SetDataValues failed because of data missmatch.", e); + // return new WriteResponse.SubChoice(new BerInteger(serviceErrorToMmsError(e)), null); + // } + // + // // TODO timeactivate operate + // + // BasicDataAttribute ctlValBda = (BasicDataAttribute) fcModelNodeCopy.getChild("ctlVal"); + // List bdas = new ArrayList(1); + // bdas.add(ctlValBda); + // List serviceErrors; + // try { + // serviceErrors = serverSap.serverEventListener.write(bdas); + // } catch (ServiceError e) { + // return new WriteResponse.SubChoice(new BerInteger(serviceErrorToMmsError(e)), null); + // } + // if (serviceErrors != null && serviceErrors.size() == bdas.size() && serviceErrors.get(1) != + // null) { + // return new WriteResponse.SubChoice(new + // BerInteger(serviceErrorToMmsError(serviceErrors.get(1))), null); + // } + // + // ctlValBda.mirror.setValueFrom(ctlValBda); + // // TODO write origin and ctlNum if they exist + // + // return writeSuccess; + // } + + private WriteResponse.CHOICE getWriteResult(FcModelNode modelNode, Data mmsData) { + + WriteResponse.CHOICE writeResponse = new WriteResponse.CHOICE(); + + Fc fc = modelNode.getFc(); + if (fc == Fc.ST || fc == Fc.MX || fc == Fc.OR || fc == Fc.EX) { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + if (fc == Fc.CO) { + String nodeName = modelNode.getName(); + + if (nodeName.equals("Oper")) { + FcModelNode cdcParent = (FcModelNode) modelNode.getParent(); + ModelNode ctlModelNode = + serverModel.findModelNode(cdcParent.getReference(), Fc.CF).getChild("ctlModel"); + if (ctlModelNode == null || !(ctlModelNode instanceof BdaInt8)) { + logger.warn("Operatring controle DO failed because ctlModel is not set."); + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + int ctlModel = ((BdaInt8) ctlModelNode).getValue(); + + /* Direct control with normal security (direct-operate) */ + if (ctlModel == 1) { + return null; + } + /* SBO control with normal security (operate-once or operate-many) */ + else if (ctlModel == 2) { + if (cdcParent.isSelectedBy(this)) { + return null; + } else { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + } else { + logger.warn("SetDataValues failed because of unsupported ctlModel: " + ctlModel); + // 9 indicates error "object_access_unsupported" + writeResponse.setFailure(new DataAccessError(9L)); + return writeResponse; + } + } else { + logger.warn( + "SetDataValues failed because of the operation is not allowed yet: " + + modelNode.getName()); + // 9 indicates error "object_access_unsupported" + writeResponse.setFailure(new DataAccessError(9L)); + return writeResponse; + } + } else if (fc == Fc.RP) { + + if (modelNode instanceof Rcb) { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + FcModelNode fcModelNodeCopy = (FcModelNode) modelNode.copy(); + + try { + fcModelNodeCopy.setValueFromMmsDataObj(mmsData); + } catch (ServiceError e) { + WriteResponse.CHOICE writeResponseChoice = new WriteResponse.CHOICE(); + writeResponseChoice.setFailure(new DataAccessError(serviceErrorToMmsError(e))); + return writeResponseChoice; + } + + Urcb urcb = (Urcb) modelNode.getParent(); + + String nodeName = modelNode.getName(); + + synchronized (urcb) { + if (nodeName.equals("RptEna")) { + BdaBoolean rptEnaNode = (BdaBoolean) fcModelNodeCopy; + if (rptEnaNode.getValue()) { + if (urcb.dataSet == null) { + logger.info("client tried to enable RCB even though there is no configured data set"); + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + if (urcb.reserved == null) { + urcb.reserved = this; + urcb.enable(); + rsvdURCBs.add(urcb); + ((BdaBoolean) modelNode).setValue(true); + return writeSuccess; + } else if (urcb.reserved == this) { + urcb.enable(); + ((BdaBoolean) modelNode).setValue(true); + return writeSuccess; + } else { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + } else { + // disable reporting + if (urcb.reserved == this) { + urcb.disable(); + ((BdaBoolean) modelNode).setValue(false); + return writeSuccess; + } else { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + } + } else if (nodeName.equals("Resv")) { + BdaBoolean rptResvNode = (BdaBoolean) fcModelNodeCopy; + if (rptResvNode.getValue()) { + + if (urcb.reserved == null) { + urcb.reserved = this; + urcb.getResv().setValue(true); + rsvdURCBs.add(urcb); + return writeSuccess; + } else if (urcb.reserved == this) { + return writeSuccess; + } else { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + } else { + if (urcb.reserved == this) { + urcb.reserved = null; + urcb.getResv().setValue(false); + rsvdURCBs.remove(urcb); + return writeSuccess; + } else { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + } + + } else if (nodeName.equals("DatSet")) { + if ((urcb.reserved == null || urcb.reserved == this) && !urcb.enabled) { + String dataSetRef = + ((BdaVisibleString) fcModelNodeCopy).getStringValue().replace('$', '.'); + if (dataSetRef.isEmpty()) { + urcb.dataSet = null; + ((BasicDataAttribute) modelNode).setValueFrom((BasicDataAttribute) fcModelNodeCopy); + return writeSuccess; + + } else { + DataSet dataSet = serverModel.getDataSet(dataSetRef); + if (dataSet == null) { + dataSet = nonPersistentDataSets.get(dataSetRef); + } + if (dataSet != null) { + urcb.dataSet = dataSet; + ((BasicDataAttribute) modelNode).setValueFrom((BasicDataAttribute) fcModelNodeCopy); + return writeSuccess; + } else { + logger.info( + "Client tried to set dataSetReference of URCB to non existant data set."); + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + } + } else { + logger.info( + "Client tried to write RCB parameter even though URCB is reserved by other client or already enabled."); + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + } else if (nodeName.equals("OptFlds")) { + if ((urcb.reserved == null || urcb.reserved == this) && !urcb.enabled) { + if (!((BdaOptFlds) modelNode).isBufferOverflow() + && !((BdaOptFlds) modelNode).isConfigRevision() + && !((BdaOptFlds) modelNode).isDataReference() + && !((BdaOptFlds) modelNode).isEntryId()) { + ((BasicDataAttribute) modelNode).setValueFrom((BasicDataAttribute) fcModelNodeCopy); + return writeSuccess; + } else { + logger.info("Client tried to write OptFlds with usupported field set to true."); + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + } else { + logger.info( + "Client tried to write RCB parameter even though URCB is reserved by other client or already enabled."); + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + } else if (nodeName.equals("GI")) { + + if ((urcb.reserved == this) + && urcb.enabled + && ((BdaTriggerConditions) urcb.getChild("TrgOps")).isGeneralInterrogation()) { + urcb.generalInterrogation(); + return writeSuccess; + } else { + logger.info( + "Client tried to initiate a general interrogation even though URCB is not enabled by this client or general interrogation is not enabled in the trigger options."); + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + } else if (nodeName.equals("RptID") + || nodeName.equals("BufTm") + || nodeName.equals("TrgOps") + || nodeName.equals("IntgPd")) { + if ((urcb.reserved == null || urcb.reserved == this) && !urcb.enabled) { + ((BasicDataAttribute) modelNode).setValueFrom((BasicDataAttribute) fcModelNodeCopy); + return writeSuccess; + } else { + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + + } else { + // nodes sqnum, ConfRev, and owner may not be read + // 3 indicates error "object_access_denied" + writeResponse.setFailure(new DataAccessError(3L)); + return writeResponse; + } + } + + } else { + + return null; + } + } + + private int serviceErrorToMmsError(ServiceError e) { + + switch (e.getErrorCode()) { + case ServiceError.FAILED_DUE_TO_SERVER_CONSTRAINT: + return 1; + case ServiceError.INSTANCE_LOCKED_BY_OTHER_CLIENT: + return 2; + case ServiceError.ACCESS_VIOLATION: + return 3; + case ServiceError.TYPE_CONFLICT: + return 7; + case ServiceError.INSTANCE_NOT_AVAILABLE: + return 10; + case ServiceError.PARAMETER_VALUE_INCONSISTENT: + return 11; + default: + return 9; + } + } + + private GetNameListResponse handleGetDataSetNamesRequest(GetNameListRequest getNameListRequest) + throws ServiceError { + + BerVisibleString domainSpecific = getNameListRequest.getObjectScope().getDomainSpecific(); + + List dsList = null; + if (domainSpecific == null) { + dsList = new ArrayList<>(nonPersistentDataSets.size()); + for (String dataSet : nonPersistentDataSets.keySet()) { + dsList.add(dataSet); + } + } else { + dsList = serverModel.getDataSetNames(domainSpecific.toString()); + } + + insertRef = true; + if (getNameListRequest.getContinueAfter() != null) { + continueAfter = getNameListRequest.getContinueAfter().toString(); + insertRef = false; + } + + ListOfIdentifier listOf = new ListOfIdentifier(); + List identifiers = listOf.getIdentifier(); + + int identifierSize = 0; + boolean moreFollows = false; + + if (dsList != null) { + for (String dsRef : dsList) { + if (insertRef == true) { + if (identifierSize > negotiatedMaxPduSize - 200) { + moreFollows = true; + logger.info("maxMMSPduSize reached"); + break; + } + identifiers.add(new Identifier(dsRef.getBytes(UTF_8))); + identifierSize += dsRef.length() + 2; + } else { + if (dsRef.equals(continueAfter)) { + insertRef = true; + } + } + } + } + + GetNameListResponse getNameListResponse = new GetNameListResponse(); + getNameListResponse.setListOfIdentifier(listOf); + getNameListResponse.setMoreFollows(new BerBoolean(moreFollows)); + + return getNameListResponse; + } + + private GetNamedVariableListAttributesResponse handleGetDataSetDirectoryRequest( + ObjectName mmsGetNamedVarListAttReq) throws ServiceError { + + String dataSetReference = convertToDataSetReference(mmsGetNamedVarListAttReq); + + DataSet dataSet; + + if (dataSetReference.startsWith("@")) { + dataSet = nonPersistentDataSets.get(dataSetReference); + } else { + dataSet = serverModel.getDataSet(dataSetReference); + } + + if (dataSet == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, + "DataSet with that reference is does not exist."); + } + + VariableDefs variableDefs = new VariableDefs(); + + List listOfVariable = variableDefs.getSEQUENCE(); + + for (FcModelNode member : dataSet) { + listOfVariable.add(member.getMmsVariableDef()); + } + + GetNamedVariableListAttributesResponse getNamedVariableListAttributesResponse = + new GetNamedVariableListAttributesResponse(); + getNamedVariableListAttributesResponse.setListOfVariable(variableDefs); + getNamedVariableListAttributesResponse.setMmsDeletable(new BerBoolean(dataSet.isDeletable())); + + return getNamedVariableListAttributesResponse; + } + + private DefineNamedVariableListResponse handleCreateDataSetRequest( + DefineNamedVariableListRequest mmsDefineNamedVariableListRequest) throws ServiceError { + String dataSetReference = + convertToDataSetReference(mmsDefineNamedVariableListRequest.getVariableListName()); + if (dataSetReference == null) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INCONSISTENT, + "handleCreateDataSetRequest: invalid MMS request (No DataSet Name Specified)"); + } + + List nameList = + mmsDefineNamedVariableListRequest.getListOfVariable().getSEQUENCE(); + + List dataSetMembers = new ArrayList<>(nameList.size()); + + for (VariableDefs.SEQUENCE variableDef : nameList) { + dataSetMembers.add(serverModel.getNodeFromVariableDef(variableDef)); + } + + DataSet dataSet = new DataSet(dataSetReference, dataSetMembers, true); + + if (dataSetReference.startsWith("@")) { + if (nonPersistentDataSets.containsKey(dataSetReference)) { + throw new ServiceError( + ServiceError.PARAMETER_VALUE_INAPPROPRIATE, "data set with that name exists already"); + } + nonPersistentDataSets.put(dataSetReference, dataSet); + } else { + serverModel.addDataSet(dataSet); + } + + return new DefineNamedVariableListResponse(); + } + + private DeleteNamedVariableListResponse handleDeleteDataSetRequest( + DeleteNamedVariableListRequest mmsDelNamVarListReq) throws ServiceError { + String dataSetReference = + convertToDataSetReference( + mmsDelNamVarListReq.getListOfVariableListName().getObjectName().get(0)); + + DeleteNamedVariableListResponse deleteNamedVariableListResponse = + new DeleteNamedVariableListResponse(); + + if (dataSetReference.startsWith("@")) { + if (nonPersistentDataSets.remove(dataSetReference) == null) { + deleteNamedVariableListResponse.setNumberMatched(new Unsigned32(0)); + deleteNamedVariableListResponse.setNumberDeleted(new Unsigned32(0)); + return deleteNamedVariableListResponse; + } else { + deleteNamedVariableListResponse.setNumberMatched(new Unsigned32(1)); + deleteNamedVariableListResponse.setNumberDeleted(new Unsigned32(1)); + return deleteNamedVariableListResponse; + } + } else { + synchronized (serverModel) { + if (serverModel.removeDataSet(dataSetReference) == null) { + if (serverModel.getDataSet(dataSetReference) == null) { + // DataSet with the name does not exist. + deleteNamedVariableListResponse.setNumberMatched(new Unsigned32(0)); + deleteNamedVariableListResponse.setNumberDeleted(new Unsigned32(0)); + return deleteNamedVariableListResponse; + } else { + // DataSet exists but is not deletable + deleteNamedVariableListResponse.setNumberMatched(new Unsigned32(1)); + deleteNamedVariableListResponse.setNumberDeleted(new Unsigned32(0)); + return deleteNamedVariableListResponse; + } + } else { + deleteNamedVariableListResponse.setNumberMatched(new Unsigned32(1)); + deleteNamedVariableListResponse.setNumberDeleted(new Unsigned32(1)); + return deleteNamedVariableListResponse; + } + } + } + } + + void close() { + cleanUpConnection(); + executor.shutdown(); + if (acseAssociation != null) { + acseAssociation.disconnect(); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ServerEventListener.java b/src/main/java/com/beanit/iec61850bean/ServerEventListener.java new file mode 100644 index 0000000..7cc104d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ServerEventListener.java @@ -0,0 +1,35 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import java.util.List; + +public interface ServerEventListener { + + /** + * The write callback function is called if one of more basic data attributes are written using + * either the setDataValue, setDataSetValues or control services. If the complete write process + * was successful write returns either an empty list or null. If an error occurs writing one or + * more attributes then a list shall be returned that is of equal size as the list of basic data + * attributes. The returned list's element shall be null if writing the corresponding BDA was + * successful and a service error otherwise. + * + * @param bdas the list of basic data attributes that are to be set. + * @return a list of service errors indicating errors writing the corresponding basic data + * attributes. + */ + List write(List bdas); + + void serverStoppedListening(ServerSap serverSAP); +} diff --git a/src/main/java/com/beanit/iec61850bean/ServerModel.java b/src/main/java/com/beanit/iec61850bean/ServerModel.java new file mode 100644 index 0000000..9a4f59f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ServerModel.java @@ -0,0 +1,400 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectName.DomainSpecific; +import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs; +import java.util.ArrayList; +import java.util.Collection; +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 { + + private final Map dataSets = new LinkedHashMap<>(); + + private final Map urcbs = new HashMap<>(); + private final Map brcbs = new HashMap<>(); + + public ServerModel(List logicalDevices, Collection 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('$', '.')); + } + } + } + } + + @Override + public ServerModel copy() { + List childCopies = new ArrayList<>(children.size()); + for (ModelNode childNode : children.values()) { + childCopies.add((LogicalDevice) childNode.copy()); + } + + List 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 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('$', '.')); + } + } + } + } + + List getDataSetNames(String ldName) { + // TODO make thread save + List 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 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('$', '.')); + } + } + } + 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 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 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(); + } + + /** + * 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 null. + * + * @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 searchedNodeReferenceIterator = objectReference.iterator(); + + while (searchedNodeReferenceIterator.hasNext()) { + currentNode = currentNode.getChild(searchedNodeReferenceIterator.next(), fc); + if (currentNode == null) { + return null; + } + } + return currentNode; + } + + /** + * 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 null. + * + * @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); + } + + /** + * 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 (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"); + } + + 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) { + return null; + } + + int index2 = mmsItemId.indexOf('$', index1 + 1); + + if (index2 == -1) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "invalid mms item id"); + } + + Fc fc = Fc.fromString(mmsItemId.substring(index1 + 1, index2)); + + if (fc == null) { + throw new ServiceError( + ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "unknown functional constraint: " + mmsItemId.substring(index1 + 1, index2)); + } + + index1 = index2; + + index2 = mmsItemId.indexOf('$', index1 + 1); + + if (index2 == -1) { + if (fc == Fc.RP) { + 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) { + 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)); + + if (variableDef.getAlternateAccess() == null) { + // no array is in this node path + return (FcModelNode) modelNode; + } + + AlternateAccessSelection altAccIt = + variableDef.getAlternateAccess().getCHOICE().get(0).getUnnamed(); + + 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()); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ServerSap.java b/src/main/java/com/beanit/iec61850bean/ServerSap.java new file mode 100644 index 0000000..722de00 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ServerSap.java @@ -0,0 +1,370 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import com.beanit.josistack.AcseAssociation; +import com.beanit.josistack.ServerAcseSap; +import java.io.IOException; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import javax.net.ServerSocketFactory; + +/** + * The ServerSap class represents the IEC 61850 service access point for server + * applications. It corresponds to the AccessPoint defined in the ICD/SCL file. A server application + * that is to listen for client connections should first get an instance of ServerSap + * using the static function ServerSap.getSapsFromSclFile(). Next all the necessary configuration + * parameters can be set. Finally the startListening function is called to listen for + * client associations. Changing properties of a ServerSap after starting to listen is not + * recommended and has unknown effects. + */ +public final class ServerSap { + + static final int MINIMUM_MMS_PDU_SIZE = 64; + private static final int MAXIMUM_MMS_PDU_SIZE = 65000; + final ServerModel serverModel; + final List associations = new ArrayList<>(); + byte[] servicesSupportedCalled = + new byte[] {(byte) 0xee, 0x1c, 0, 0, 0x04, 0x08, 0, 0, 0x79, (byte) 0xef, 0x18}; + byte[] cbbBitString = {(byte) 0xfb, 0x00}; + ServerEventListener serverEventListener; + Timer timer; + boolean listening = false; + private int proposedMaxMmsPduSize = 65000; + private int proposedMaxServOutstandingCalling = 5; + private int proposedMaxServOutstandingCalled = 5; + private int proposedDataStructureNestingLevel = 10; + private int maxAssociations = 100; + private ServerAcseSap acseSap; + private int port = 102; + private int backlog = 0; + private InetAddress bindAddr = null; + private ServerSocketFactory serverSocketFactory = null; + + /** + * Creates a ServerSap. + * + * @param port local port to listen on for new connections + * @param backlog The maximum queue length for incoming connection indications (a request to + * connect) is set to the backlog parameter. If a connection indication arrives when the queue + * is full, the connection is refused. Set to 0 or less for the default value. + * @param bindAddr local IP address to bind to, pass null to bind to all + * @param serverModel the server model + * @param serverSocketFactory the factory class to generate the ServerSocket. Could be used to + * create SSLServerSockets. null = default + */ + public ServerSap( + int port, + int backlog, + InetAddress bindAddr, + ServerModel serverModel, + ServerSocketFactory serverSocketFactory) { + this.port = port; + this.backlog = backlog; + this.bindAddr = bindAddr; + this.serverSocketFactory = serverSocketFactory; + this.serverModel = serverModel; + } + + public int getPort() { + return port; + } + + /** + * Sets local port to listen on for new connections. + * + * @param port local port to listen on for new connections + */ + public void setPort(int port) { + this.port = port; + } + + public int getBacklog() { + return backlog; + } + + /** + * Sets the maximum queue length for incoming connection indications (a request to connect) is set + * to the backlog parameter. If a connection indication arrives when the queue is full, the + * connection is refused. Set to 0 or less for the default value. + * + * @param backlog the maximum queue length for incoming connections. + */ + public void setBacklog(int backlog) { + this.backlog = backlog; + } + + public InetAddress getBindAddress() { + return bindAddr; + } + + /** + * Sets the local IP address to bind to, pass null to bind to all + * + * @param bindAddr the local IP address to bind to + */ + public void setBindAddress(InetAddress bindAddr) { + this.bindAddr = bindAddr; + } + + /** + * Sets the factory class to generate the ServerSocket. The ServerSocketFactory could be used to + * create SSLServerSockets. Set to null to use ServerSocketFactory.getDefault() + * . + * + * @param serverSocketFactory the factory class to generate the ServerSocket. + */ + public void setServerSocketFactory(ServerSocketFactory serverSocketFactory) { + this.serverSocketFactory = serverSocketFactory; + } + + /** + * Gets the maximum MMS PDU size. + * + * @return the maximum MMS PDU size. + */ + public int getMaxMmsPduSize() { + return proposedMaxMmsPduSize; + } + + /** + * Sets the maximum MMS PDU size in bytes that the server will support. If the client requires the + * use of a smaller maximum MMS PDU size, then the smaller size will be accepted by the server. + * The default size is 65000. + * + * @param size cannot be less than 64. The upper limit is 65000 so that segmentation at the lower + * transport layer is avoided. The Transport Layer's maximum PDU size is 65531. + */ + public void setMaxMmsPduSize(int size) { + if (size >= MINIMUM_MMS_PDU_SIZE && size <= MAXIMUM_MMS_PDU_SIZE) { + proposedMaxMmsPduSize = size; + } else { + throw new IllegalArgumentException("maximum size is out of bound"); + } + } + + /** + * Set the maximum number of associations that are allowed in parallel by the server. + * + * @param maxAssociations the number of associations allowed (default is 100) + */ + public void setMaxAssociations(int maxAssociations) { + this.maxAssociations = maxAssociations; + } + + /** + * Sets the message fragment timeout. This is the timeout that the socket timeout is set to after + * the first byte of a message has been received. If such a timeout is thrown, the + * association/socket is closed. + * + * @param timeout the message fragment timeout in milliseconds. The default is 60000. + */ + public void setMessageFragmentTimeout(int timeout) { + acseSap.serverTSap.setMessageFragmentTimeout(timeout); + } + + /** + * Gets the ProposedMaxServOutstandingCalling parameter. + * + * @return the ProposedMaxServOutstandingCalling parameter. + */ + public int getProposedMaxServOutstandingCalling() { + return proposedMaxServOutstandingCalling; + } + + /** + * Sets the ProposedMaxServOutstandingCalling parameter. The given parameter has no affect on the + * functionality of this server. + * + * @param maxCalling the ProposedMaxServOutstandingCalling parameter. The default is 5. + */ + public void setProposedMaxServOutstandingCalling(int maxCalling) { + proposedMaxServOutstandingCalling = maxCalling; + } + + /** + * Gets the ProposedMaxServOutstandingCalled parameter. + * + * @return the ProposedMaxServOutstandingCalled parameter. + */ + public int getProposedMaxServOutstandingCalled() { + return proposedMaxServOutstandingCalled; + } + + /** + * Sets the ProposedMaxServOutstandingCalled parameter.The given parameter has no affect on the + * functionality of this server. + * + * @param maxCalled the ProposedMaxServOutstandingCalled parameter. The default is 5. + */ + public void setProposedMaxServOutstandingCalled(int maxCalled) { + proposedMaxServOutstandingCalled = maxCalled; + } + + /** + * Gets the ProposedDataStructureNestingLevel parameter. + * + * @return the ProposedDataStructureNestingLevel parameter. + */ + public int getProposedDataStructureNestingLevel() { + return proposedDataStructureNestingLevel; + } + + /** + * Sets the ProposedDataStructureNestingLevel parameter. The given parameter has no affect on the + * functionality of this server.runServer + * + * @param nestingLevel the ProposedDataStructureNestingLevel parameter. The default is 10. + */ + public void setProposedDataStructureNestingLevel(int nestingLevel) { + proposedDataStructureNestingLevel = nestingLevel; + } + + /** + * Gets the ServicesSupportedCalled parameter. + * + * @return the ServicesSupportedCalled parameter. + */ + public byte[] getServicesSupportedCalled() { + return servicesSupportedCalled; + } + + /** + * Sets the SevicesSupportedCalled parameter. The given parameter has no affect on the + * functionality of this server. + * + * @param services the ServicesSupportedCalled parameter + */ + public void setServicesSupportedCalled(byte[] services) { + if (services.length != 11) { + throw new IllegalArgumentException("The services parameter needs to be of lenth 11"); + } + servicesSupportedCalled = services; + } + + /** + * Creates a server socket waiting on the configured port for incoming association requests. + * + * @param serverEventListener the listener that is notified of incoming writes and when the server + * stopped listening for new connections. + * @throws IOException if an error occurs binding to the port. + */ + public void startListening(ServerEventListener serverEventListener) throws IOException { + timer = new Timer(); + if (serverSocketFactory == null) { + serverSocketFactory = ServerSocketFactory.getDefault(); + } + acseSap = + new ServerAcseSap(port, backlog, bindAddr, new AcseListener(this), serverSocketFactory); + acseSap.serverTSap.setMaxConnections(maxAssociations); + this.serverEventListener = serverEventListener; + listening = true; + acseSap.startListening(); + } + + /** Stops listening for new connections and closes all existing connections/associations. */ + public void stop() { + acseSap.stopListening(); + synchronized (associations) { + listening = false; + for (ServerAssociation association : associations) { + association.close(); + } + associations.clear(); + } + timer.cancel(); + timer.purge(); + } + + void connectionIndication(AcseAssociation acseAssociation, ByteBuffer psdu) { + + ServerAssociation association; + synchronized (associations) { + if (listening) { + association = new ServerAssociation(this); + associations.add(association); + } else { + acseAssociation.close(); + return; + } + } + + try { + association.handleNewAssociation(acseAssociation, psdu); + } catch (Exception e) { + // Association closed because of an unexpected exception. + } + + association.close(); + synchronized (associations) { + associations.remove(association); + } + } + + void serverStoppedListeningIndication(IOException e) { + if (serverEventListener != null) { + serverEventListener.serverStoppedListening(this); + } + } + + public ServerModel getModelCopy() { + return serverModel.copy(); + } + + public void setValues(List bdas) { + synchronized (serverModel) { + for (BasicDataAttribute bda : bdas) { + // if (bda.getFunctionalConstraint() != FunctionalConstraint.ST) { + // logger.debug("fc:" + bda.getFunctionalConstraint()); + // throw new IllegalArgumentException( + // "One can only set values of BDAs with Functional Constraint ST(status)"); + // } + + BasicDataAttribute bdaMirror = bda.mirror; + + if (bdaMirror.dchg && bdaMirror.chgRcbs.size() != 0 && !bda.equals(bdaMirror)) { + bdaMirror.setValueFrom(bda); + synchronized (bdaMirror.chgRcbs) { + for (Urcb urcb : bdaMirror.chgRcbs) { + if (bdaMirror.dupd && urcb.getTrgOps().isDataUpdate()) { + urcb.report(bdaMirror, true, false, true); + } else { + urcb.report(bdaMirror, true, false, false); + } + } + } + } else if (bdaMirror.dupd && bdaMirror.dupdRcbs.size() != 0) { + bdaMirror.setValueFrom(bda); + synchronized (bdaMirror.dupdRcbs) { + for (Urcb urcb : bdaMirror.dupdRcbs) { + urcb.report(bdaMirror, false, false, true); + } + } + } else if (bdaMirror.qchg && bdaMirror.chgRcbs.size() != 0 && !bda.equals(bdaMirror)) { + bdaMirror.setValueFrom(bda); + synchronized (bdaMirror.chgRcbs) { + for (Urcb urcb : bdaMirror.chgRcbs) { + urcb.report(bdaMirror, false, true, false); + } + } + } else { + bdaMirror.setValueFrom(bda); + } + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ServiceError.java b/src/main/java/com/beanit/iec61850bean/ServiceError.java new file mode 100644 index 0000000..2f99d7f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ServiceError.java @@ -0,0 +1,122 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class ServiceError extends Exception { + + public static final int NO_ERROR = 0; + public static final int INSTANCE_NOT_AVAILABLE = 1; + public static final int INSTANCE_IN_USE = 2; + public static final int ACCESS_VIOLATION = 3; + public static final int ACCESS_NOT_ALLOWED_IN_CURRENT_STATE = 4; + public static final int PARAMETER_VALUE_INAPPROPRIATE = 5; + public static final int PARAMETER_VALUE_INCONSISTENT = 6; + public static final int CLASS_NOT_SUPPORTED = 7; + public static final int INSTANCE_LOCKED_BY_OTHER_CLIENT = 8; + public static final int CONTROL_MUST_BE_SELECTED = 9; + public static final int TYPE_CONFLICT = 10; + public static final int FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT = 11; + public static final int FAILED_DUE_TO_SERVER_CONSTRAINT = 12; + public static final int APPLICATION_UNREACHABLE = 13; + public static final int CONNECTION_LOST = 14; + public static final int MEMORY_UNAVAILABLE = 15; + public static final int PROCESSOR_RESOURCE_UNAVAILABLE = 16; + public static final int FILE_NONE_EXISTENT = 17; + public static final int FATAL = 20; + // added to handle data access errors mentioned in iec61850-8-1 + // public static final int DATA_ACCESS_ERROR = 21; + // added to report timeouts + public static final int TIMEOUT = 22; + public static final int UNKNOWN = 23; + + private static final long serialVersionUID = 4290107163231828564L; + private final int errorCode; + + public ServiceError(int errorCode) { + this(errorCode, "", null); + } + + public ServiceError(int errorCode, String s) { + this(errorCode, s, null); + } + + public ServiceError(int errorCode, Throwable cause) { + this(errorCode, "", cause); + } + + public ServiceError(int errorCode, String s, Throwable cause) { + super( + "Service error: " + + getErrorName(errorCode) + + "(" + + errorCode + + ")" + + (s.isEmpty() ? "" : (" " + s)), + cause); + this.errorCode = errorCode; + } + + private static String getErrorName(int code) { + switch (code) { + case NO_ERROR: + return "NO_ERROR"; + case INSTANCE_NOT_AVAILABLE: + return "INSTANCE_NOT_AVAILABLE"; + case INSTANCE_IN_USE: + return "INSTANCE_IN_USE"; + case ACCESS_VIOLATION: + return "ACCESS_VIOLATION"; + case ACCESS_NOT_ALLOWED_IN_CURRENT_STATE: + return "ACCESS_NOT_ALLOWED_IN_CURRENT_STATE"; + case PARAMETER_VALUE_INAPPROPRIATE: + return "PARAMETER_VALUE_INAPPROPRIATE"; + case PARAMETER_VALUE_INCONSISTENT: + return "PARAMETER_VALUE_INCONSISTENT"; + case CLASS_NOT_SUPPORTED: + return "CLASS_NOT_SUPPORTED"; + case INSTANCE_LOCKED_BY_OTHER_CLIENT: + return "INSTANCE_LOCKED_BY_OTHER_CLIENT"; + case CONTROL_MUST_BE_SELECTED: + return "CONTROL_MUST_BE_SELECTED"; + case TYPE_CONFLICT: + return "TYPE_CONFLICT"; + case FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT: + return "FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT"; + case FAILED_DUE_TO_SERVER_CONSTRAINT: + return "FAILED_DUE_TO_SERVER_CONSTRAINT"; + case APPLICATION_UNREACHABLE: + return "APPLICATION_UNREACHABLE"; + case CONNECTION_LOST: + return "CONNECTION_LOST"; + case MEMORY_UNAVAILABLE: + return "MEMORY_UNAVAILABLE"; + case PROCESSOR_RESOURCE_UNAVAILABLE: + return "PROCESSOR_RESOURCE_UNAVAILABLE"; + case FILE_NONE_EXISTENT: + return "FILE_NONE_EXISTENT"; + case FATAL: + return "FATAL"; + case TIMEOUT: + return "TIMEOUT_ERROR"; + case UNKNOWN: + return "UNKNOWN"; + default: + return "Unknown ServiceError code"; + } + } + + public int getErrorCode() { + return errorCode; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/ServiceSupport.java b/src/main/java/com/beanit/iec61850bean/ServiceSupport.java new file mode 100644 index 0000000..54ef47d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/ServiceSupport.java @@ -0,0 +1,27 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +public final class ServiceSupport { + + public boolean dynAssociation = false; + public boolean getDirectory = false; + public boolean getDataObjectDefinition = false; + public boolean getDataSetValue = false; + public boolean dataSetDirectory = false; + public boolean readWrite = false; + public boolean getCBValues = false; + public boolean goose = false; + public int gooseMax = 0; +} diff --git a/src/main/java/com/beanit/iec61850bean/Urcb.java b/src/main/java/com/beanit/iec61850bean/Urcb.java new file mode 100644 index 0000000..9d00e4c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/Urcb.java @@ -0,0 +1,388 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.iec61850bean.internal.mms.asn1.AccessResult; +import com.beanit.iec61850bean.internal.mms.asn1.Data; +import com.beanit.iec61850bean.internal.mms.asn1.Identifier; +import com.beanit.iec61850bean.internal.mms.asn1.InformationReport; +import com.beanit.iec61850bean.internal.mms.asn1.MMSpdu; +import com.beanit.iec61850bean.internal.mms.asn1.ObjectName; +import com.beanit.iec61850bean.internal.mms.asn1.UnconfirmedPDU; +import com.beanit.iec61850bean.internal.mms.asn1.UnconfirmedService; +import com.beanit.iec61850bean.internal.mms.asn1.VariableAccessSpecification; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class Urcb extends Rcb { + + final HashMap membersToBeReported = new LinkedHashMap<>(); + ServerAssociation reserved = null; + boolean enabled = false; + private Timer integrityTimer; + // private ScheduledFuture integrityFuture = null; + private ScheduledFuture bufTmFuture = null; + + public Urcb(ObjectReference objectReference, List children) { + super(objectReference, Fc.RP, children); + } + + /** + * Reserve URCB - The attribute Resv (if set to TRUE) shall indicate that the URCB is currently + * exclusively reserved for the client that has set the value to TRUE. Other clients shall not be + * allowed to set any attribute of that URCB. + * + * @return the Resv child + */ + public BdaBoolean getResv() { + return (BdaBoolean) children.get("Resv"); + } + + void enable() { + + for (FcModelNode dataSetMember : dataSet) { + for (BasicDataAttribute bda : dataSetMember.getBasicDataAttributes()) { + if (bda.dchg) { + if (getTrgOps().isDataChange()) { + synchronized (bda.chgRcbs) { + bda.chgRcbs.add(this); + } + } + } else if (bda.qchg) { + if (getTrgOps().isQualityChange()) { + synchronized (bda.chgRcbs) { + bda.chgRcbs.add(this); + } + } + } + if (bda.dupd) { + if (getTrgOps().isDataUpdate()) { + synchronized (bda.dupdRcbs) { + bda.dupdRcbs.add(this); + } + } + } + } + } + + if (getTrgOps().isIntegrity() && !(getIntgPd().getValue() < 10l)) { + integrityTimer = new Timer(); + + integrityTimer.schedule( + new TimerTask() { + // integrityFuture = reserved.executor.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + synchronized (Urcb.this) { + if (!enabled) { + return; + } + reserved.sendAnMmsPdu(getMmsReport(true, false)); + } + } + // }, getIntgPd().getValue(), getIntgPd().getValue(), TimeUnit.MILLISECONDS); + }, + getIntgPd().getValue(), + getIntgPd().getValue()); + } + + enabled = true; + } + + void disable() { + + for (FcModelNode dataSetMember : dataSet) { + for (BasicDataAttribute bda : dataSetMember.getBasicDataAttributes()) { + if (bda.dchg) { + if (getTrgOps().isDataChange()) { + synchronized (bda.chgRcbs) { + bda.chgRcbs.remove(this); + } + } + } else if (bda.qchg) { + if (getTrgOps().isQualityChange()) { + synchronized (bda.chgRcbs) { + bda.chgRcbs.remove(this); + } + } + } + if (bda.dupd) { + if (getTrgOps().isDataUpdate()) { + synchronized (bda.dupdRcbs) { + bda.dupdRcbs.remove(this); + } + } + } + } + } + + // if (integrityFuture != null) { + // integrityFuture.cancel(false); + // } + if (integrityTimer != null) { + integrityTimer.cancel(); + } + + enabled = false; + } + + void generalInterrogation() { + reserved.executor.execute( + new Runnable() { + @Override + public void run() { + synchronized (Urcb.this) { + if (!enabled) { + return; + } + reserved.sendAnMmsPdu(getMmsReport(false, true)); + } + } + }); + } + + private MMSpdu getMmsReport(boolean integrity, boolean gi) { + + InformationReport.ListOfAccessResult listOfAccessResult = + new InformationReport.ListOfAccessResult(); + + List accessResults = listOfAccessResult.getAccessResult(); + + AccessResult accessResult = new AccessResult(); + accessResult.setSuccess(getRptId().getMmsDataObj()); + accessResults.add(accessResult); + + accessResult = new AccessResult(); + accessResult.setSuccess(getOptFlds().getMmsDataObj()); + accessResults.add(accessResult); + + if (getOptFlds().isSequenceNumber()) { + accessResult = new AccessResult(); + accessResult.setSuccess(getSqNum().getMmsDataObj()); + accessResults.add(accessResult); + } + getSqNum().setValue((short) (getSqNum().getValue() + 1)); + + if (getOptFlds().isReportTimestamp()) { + BdaEntryTime entryTime = new BdaEntryTime(null, null, null, false, false); + entryTime.setTimestamp(System.currentTimeMillis()); + + accessResult = new AccessResult(); + accessResult.setSuccess(entryTime.getMmsDataObj()); + accessResults.add(accessResult); + } + + if (getOptFlds().isDataSetName()) { + accessResult = new AccessResult(); + accessResult.setSuccess(getDatSet().getMmsDataObj()); + accessResults.add(accessResult); + } + + if (getOptFlds().isConfigRevision()) { + accessResult = new AccessResult(); + accessResult.setSuccess(getConfRev().getMmsDataObj()); + accessResults.add(accessResult); + } + + // segmentation not supported + + List dataSetMembers = dataSet.getMembers(); + int dataSetSize = dataSetMembers.size(); + + // inclusion bitstring + byte[] inclusionStringArray = new byte[(dataSetSize - 1) / 8 + 1]; + + if (integrity || gi) { + + for (int i = 0; i < dataSetSize; i++) { + inclusionStringArray[i / 8] = (byte) (inclusionStringArray[i / 8] | 1 << (7 - i % 8)); + } + BerBitString inclusionString = new BerBitString(inclusionStringArray, dataSetSize); + + Data data = new Data(); + data.setBitString(inclusionString); + accessResult = new AccessResult(); + accessResult.setSuccess(data); + accessResults.add(accessResult); + + // data reference sending not supported for now + + for (FcModelNode dataSetMember : dataSetMembers) { + accessResult = new AccessResult(); + accessResult.setSuccess(dataSetMember.getMmsDataObj()); + accessResults.add(accessResult); + } + + BdaReasonForInclusion reasonForInclusion = new BdaReasonForInclusion(null); + if (integrity) { + reasonForInclusion.setIntegrity(true); + } else { + reasonForInclusion.setGeneralInterrogation(true); + } + + if (getOptFlds().isReasonForInclusion()) { + for (int i = 0; i < dataSetMembers.size(); i++) { + accessResult = new AccessResult(); + accessResult.setSuccess(reasonForInclusion.getMmsDataObj()); + accessResults.add(accessResult); + } + } + + } else { + + int index = 0; + for (FcModelNode dataSetMember : dataSet) { + if (membersToBeReported.get(dataSetMember) != null) { + inclusionStringArray[index / 8] = + (byte) (inclusionStringArray[index / 8] | 1 << (7 - index % 8)); + } + index++; + } + BerBitString inclusionString = new BerBitString(inclusionStringArray, dataSetSize); + + Data data = new Data(); + data.setBitString(inclusionString); + accessResult = new AccessResult(); + accessResult.setSuccess(data); + accessResults.add(accessResult); + + // data reference sending not supported for now + + for (FcModelNode dataSetMember : dataSetMembers) { + if (membersToBeReported.get(dataSetMember) != null) { + accessResult = new AccessResult(); + accessResult.setSuccess(dataSetMember.getMmsDataObj()); + accessResults.add(accessResult); + } + } + + if (getOptFlds().isReasonForInclusion()) { + for (FcModelNode dataSetMember : dataSetMembers) { + BdaReasonForInclusion reasonForInclusion = membersToBeReported.get(dataSetMember); + if (reasonForInclusion != null) { + accessResult = new AccessResult(); + accessResult.setSuccess(reasonForInclusion.getMmsDataObj()); + accessResults.add(accessResult); + } + } + } + + membersToBeReported.clear(); + bufTmFuture = null; + } + + ObjectName objectName = new ObjectName(); + objectName.setVmdSpecific(new Identifier("RPT".getBytes(UTF_8))); + + VariableAccessSpecification varAccSpec = new VariableAccessSpecification(); + varAccSpec.setVariableListName(objectName); + + InformationReport infoReport = new InformationReport(); + infoReport.setVariableAccessSpecification(varAccSpec); + infoReport.setListOfAccessResult(listOfAccessResult); + + UnconfirmedService unconfirmedService = new UnconfirmedService(); + unconfirmedService.setInformationReport(infoReport); + + UnconfirmedPDU unconfirmedPDU = new UnconfirmedPDU(); + unconfirmedPDU.setService(unconfirmedService); + + MMSpdu mmsPdu = new MMSpdu(); + mmsPdu.setUnconfirmedPDU(unconfirmedPDU); + + return mmsPdu; + } + + @Override + public FcDataObject copy() { + List childCopies = new ArrayList<>(children.size()); + for (ModelNode childNode : children.values()) { + childCopies.add((FcModelNode) childNode.copy()); + } + Urcb urcb = new Urcb(objectReference, childCopies); + urcb.dataSet = dataSet; + return urcb; + } + + void report(BasicDataAttribute bda, boolean dchg, boolean qchg, boolean dupd) { + + synchronized (this) { + if (!enabled) { + return; + } + + FcModelNode memberFound = null; + FcModelNode fcModelNode = bda; + while (memberFound == null) { + for (FcModelNode member : dataSet) { + if (member == fcModelNode) { + memberFound = fcModelNode; + break; + } + } + if (memberFound != null) { + break; + } + if (!(fcModelNode.parent instanceof FcModelNode)) { + // Unable to report Basic Data Attribute because it is not part of the referenced data set + return; + } + fcModelNode = (FcModelNode) fcModelNode.parent; + } + + BdaReasonForInclusion reasonForInclusion = membersToBeReported.get(fcModelNode); + if (reasonForInclusion == null) { + reasonForInclusion = new BdaReasonForInclusion(null); + membersToBeReported.put(fcModelNode, reasonForInclusion); + } + + if (dchg) { + reasonForInclusion.setDataChange(true); + } + if (dupd) { + reasonForInclusion.setDataUpdate(true); + } else if (qchg) { + reasonForInclusion.setQualityChange(true); + } + + // if bufTmFuture is not null then it is already scheduled and will send the combined report + if (bufTmFuture == null) { + bufTmFuture = + reserved.executor.schedule( + new Runnable() { + @Override + public void run() { + synchronized (Urcb.this) { + if (!enabled) { + return; + } + reserved.sendAnMmsPdu(getMmsReport(false, false)); + } + } + }, + getBufTm().getValue(), + TimeUnit.MILLISECONDS); + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/app/ConsoleClient.java b/src/main/java/com/beanit/iec61850bean/app/ConsoleClient.java new file mode 100644 index 0000000..a8cb403 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/app/ConsoleClient.java @@ -0,0 +1,436 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.app; + +import com.beanit.iec61850bean.BdaTriggerConditions; +import com.beanit.iec61850bean.Brcb; +import com.beanit.iec61850bean.ClientAssociation; +import com.beanit.iec61850bean.ClientEventListener; +import com.beanit.iec61850bean.ClientSap; +import com.beanit.iec61850bean.DataSet; +import com.beanit.iec61850bean.Fc; +import com.beanit.iec61850bean.FcModelNode; +import com.beanit.iec61850bean.ModelNode; +import com.beanit.iec61850bean.Report; +import com.beanit.iec61850bean.SclParseException; +import com.beanit.iec61850bean.SclParser; +import com.beanit.iec61850bean.ServerModel; +import com.beanit.iec61850bean.ServiceError; +import com.beanit.iec61850bean.Urcb; +import com.beanit.iec61850bean.internal.cli.Action; +import com.beanit.iec61850bean.internal.cli.ActionException; +import com.beanit.iec61850bean.internal.cli.ActionListener; +import com.beanit.iec61850bean.internal.cli.ActionProcessor; +import com.beanit.iec61850bean.internal.cli.CliParameter; +import com.beanit.iec61850bean.internal.cli.CliParameterBuilder; +import com.beanit.iec61850bean.internal.cli.CliParseException; +import com.beanit.iec61850bean.internal.cli.CliParser; +import com.beanit.iec61850bean.internal.cli.IntCliParameter; +import com.beanit.iec61850bean.internal.cli.StringCliParameter; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +public class ConsoleClient { + + private static final String PRINT_MODEL_KEY = "m"; + private static final String PRINT_MODEL_KEY_DESCRIPTION = "print model"; + private static final String GET_DATA_VALUES_KEY = "g"; + private static final String GET_DATA_VALUES_KEY_DESCRIPTION = "send GetDataValues request"; + private static final String READ_ALL_DATA_KEY = "ga"; + private static final String READ_ALL_DATA_KEY_DESCRIPTION = "update all data in the model"; + private static final String CREATE_DATA_SET_KEY = "cds"; + private static final String CREATE_DATA_SET_KEY_DESCRIPTION = "create data set"; + private static final String DELETE_DATA_SET_KEY = "dds"; + private static final String DELETE_DATA_SET_KEY_DESCRIPTION = "delete data set"; + private static final String REPORTING_KEY = "r"; + private static final String REPORTING_KEY_DESCRIPTION = "configure reporting"; + + private static final StringCliParameter hostParam = + new CliParameterBuilder("-h") + .setDescription("The IP/domain address of the server you want to access.") + .setMandatory() + .buildStringParameter("host"); + private static final IntCliParameter portParam = + new CliParameterBuilder("-p") + .setDescription("The port to connect to.") + .buildIntParameter("port", 102); + private static final StringCliParameter modelFileParam = + new CliParameterBuilder("-m") + .setDescription( + "The file name of the SCL file to read the model from. If this parameter is omitted the model will be read from the server device after connection.") + .buildStringParameter("model-file"); + private static final ActionProcessor actionProcessor = new ActionProcessor(new ActionExecutor()); + private static volatile ClientAssociation association; + private static ServerModel serverModel; + + public static void main(String[] args) { + + List cliParameters = new ArrayList<>(); + cliParameters.add(hostParam); + cliParameters.add(portParam); + cliParameters.add(modelFileParam); + + CliParser cliParser = + new CliParser( + "iec61850bean-console-client", "A client application to access IEC 61850 MMS servers."); + cliParser.addParameters(cliParameters); + + try { + cliParser.parseArguments(args); + } catch (CliParseException e1) { + System.err.println("Error parsing command line parameters: " + e1.getMessage()); + System.out.println(cliParser.getUsageString()); + System.exit(1); + } + + InetAddress address; + try { + address = InetAddress.getByName(hostParam.getValue()); + } catch (UnknownHostException e) { + System.out.println("Unknown host: " + hostParam.getValue()); + return; + } + + ClientSap clientSap = new ClientSap(); + + try { + association = clientSap.associate(address, portParam.getValue(), null, new EventListener()); + } catch (IOException e) { + System.out.println("Unable to connect to remote host."); + return; + } + + Runtime.getRuntime() + .addShutdownHook( + new Thread() { + @Override + public void run() { + association.close(); + } + }); + + System.out.println("successfully connected"); + + if (modelFileParam.isSelected()) { + System.out.println("reading model from file..."); + + try { + serverModel = SclParser.parse(modelFileParam.getValue()).get(0); + } catch (SclParseException e1) { + System.out.println("Error parsing SCL file: " + e1.getMessage()); + return; + } + + association.setServerModel(serverModel); + + System.out.println("successfully read model"); + + } else { + System.out.println("retrieving model..."); + + try { + serverModel = association.retrieveModel(); + } catch (ServiceError e) { + System.out.println("Service error: " + e.getMessage()); + return; + } catch (IOException e) { + System.out.println("Fatal error: " + e.getMessage()); + return; + } + + System.out.println("successfully read model"); + } + + actionProcessor.addAction(new Action(PRINT_MODEL_KEY, PRINT_MODEL_KEY_DESCRIPTION)); + actionProcessor.addAction(new Action(GET_DATA_VALUES_KEY, GET_DATA_VALUES_KEY_DESCRIPTION)); + actionProcessor.addAction(new Action(READ_ALL_DATA_KEY, READ_ALL_DATA_KEY_DESCRIPTION)); + actionProcessor.addAction(new Action(CREATE_DATA_SET_KEY, CREATE_DATA_SET_KEY_DESCRIPTION)); + actionProcessor.addAction(new Action(DELETE_DATA_SET_KEY, DELETE_DATA_SET_KEY_DESCRIPTION)); + actionProcessor.addAction(new Action(REPORTING_KEY, REPORTING_KEY_DESCRIPTION)); + + actionProcessor.start(); + } + + private static class EventListener implements ClientEventListener { + + @Override + public void newReport(Report report) { + System.out.println("\n----------------"); + System.out.println("Received report: "); + System.err.println(report); + System.out.println("------------------"); + } + + @Override + public void associationClosed(IOException e) { + System.out.print("Received connection closed signal. Reason: "); + if (!e.getMessage().isEmpty()) { + System.out.println(e.getMessage()); + } else { + System.out.println("unknown"); + } + actionProcessor.close(); + } + } + + private static class ActionExecutor implements ActionListener { + + @Override + public void actionCalled(String actionKey) throws ActionException { + try { + switch (actionKey) { + case PRINT_MODEL_KEY: + System.out.println(serverModel); + break; + case READ_ALL_DATA_KEY: + System.out.print("Reading all data..."); + try { + association.getAllDataValues(); + } catch (ServiceError e) { + System.err.println("Service error: " + e.getMessage()); + } + System.out.println("done"); + break; + case GET_DATA_VALUES_KEY: + { + if (serverModel == null) { + System.out.println("You have to retrieve the model before reading data."); + return; + } + + FcModelNode fcModelNode = askForFcModelNode(); + + System.out.println("Sending GetDataValues request..."); + + try { + association.getDataValues(fcModelNode); + } catch (ServiceError e) { + System.out.println("Service error: " + e.getMessage()); + return; + } catch (IOException e) { + System.out.println("Fatal error: " + e.getMessage()); + return; + } + + System.out.println("Successfully read data."); + System.out.println(fcModelNode); + + break; + } + case CREATE_DATA_SET_KEY: + { + System.out.println( + "Enter the reference of the data set to create (e.g. myld/MYLN0.dataset1): "); + String reference = actionProcessor.getReader().readLine(); + + System.out.println("How many entries shall the data set have: "); + String numberOfEntriesString = actionProcessor.getReader().readLine(); + int numDataSetEntries = Integer.parseInt(numberOfEntriesString); + + List dataSetMembers = new ArrayList<>(); + for (int i = 0; i < numDataSetEntries; i++) { + dataSetMembers.add(askForFcModelNode()); + } + + DataSet dataSet = new DataSet(reference, dataSetMembers); + System.out.print("Creating data set.."); + association.createDataSet(dataSet); + System.out.println("done"); + + break; + } + case DELETE_DATA_SET_KEY: + { + System.out.println( + "Enter the reference of the data set to delete (e.g. myld/MYLN0.dataset1): "); + String reference = actionProcessor.getReader().readLine(); + + DataSet dataSet = serverModel.getDataSet(reference); + if (dataSet == null) { + throw new ActionException("Unable to find data set with the given reference."); + } + System.out.print("Deleting data set.."); + association.deleteDataSet(dataSet); + System.out.println("done"); + + break; + } + case REPORTING_KEY: + { + System.out.println("Enter the URCB reference: "); + String reference = actionProcessor.getReader().readLine(); + Urcb urcb = serverModel.getUrcb(reference); + if (urcb == null) { + Brcb brcb = serverModel.getBrcb(reference); + if (brcb != null) { + throw new ActionException( + "Though buffered reporting is supported by the library it is not yet supported by the console application."); + } + throw new ActionException("Unable to find RCB with the given reference."); + } + + while (true) { + association.getRcbValues(urcb); + System.out.println(); + System.out.println(urcb); + System.out.println(); + System.out.println("What do you want to configure?"); + System.out.println("1 - reserve"); + System.out.println("2 - cancel reservation"); + System.out.println("3 - enable"); + System.out.println("4 - disable"); + System.out.println("5 - set data set"); + System.out.println("6 - set trigger options"); + System.out.println("7 - set integrity period"); + System.out.println("8 - send general interrogation"); + System.out.println("0 - quit"); + try { + int rcbAction = Integer.parseInt(actionProcessor.getReader().readLine()); + switch (rcbAction) { + case 0: + return; + case 1: + System.out.print("Reserving RCB.."); + association.reserveUrcb(urcb); + System.out.println("done"); + break; + case 2: + System.out.print("Canceling RCB reservation.."); + association.cancelUrcbReservation(urcb); + System.out.println("done"); + break; + case 3: + System.out.print("Enabling reporting.."); + association.enableReporting(urcb); + System.out.println("done"); + break; + case 4: + System.out.print("Disabling reporting.."); + association.disableReporting(urcb); + System.out.println("done"); + break; + case 5: + { + System.out.print("Set data set reference:"); + String dataSetReference = actionProcessor.getReader().readLine(); + urcb.getDatSet().setValue(dataSetReference); + List serviceErrors = + association.setRcbValues( + urcb, false, true, false, false, false, false, false, false); + if (serviceErrors.get(0) != null) { + throw serviceErrors.get(0); + } + System.out.println("done"); + break; + } + case 6: + { + System.out.print( + "Set the trigger options (data change, data update, quality change, interity, GI):"); + String triggerOptionsString = actionProcessor.getReader().readLine(); + String[] triggerOptionsStrings = triggerOptionsString.split(",", -1); + BdaTriggerConditions triggerOptions = urcb.getTrgOps(); + triggerOptions.setDataChange( + Boolean.parseBoolean(triggerOptionsStrings[0])); + triggerOptions.setDataUpdate( + Boolean.parseBoolean(triggerOptionsStrings[1])); + triggerOptions.setQualityChange( + Boolean.parseBoolean(triggerOptionsStrings[2])); + triggerOptions.setIntegrity(Boolean.parseBoolean(triggerOptionsStrings[3])); + triggerOptions.setGeneralInterrogation( + Boolean.parseBoolean(triggerOptionsStrings[4])); + List serviceErrors = + association.setRcbValues( + urcb, false, false, false, false, true, false, false, false); + if (serviceErrors.get(0) != null) { + throw serviceErrors.get(0); + } + System.out.println("done"); + break; + } + case 7: + { + System.out.print("Specify integrity period in ms:"); + String integrityPeriodString = actionProcessor.getReader().readLine(); + urcb.getIntgPd().setValue(Long.parseLong(integrityPeriodString)); + List serviceErrors = + association.setRcbValues( + urcb, false, false, false, false, false, true, false, false); + if (serviceErrors.get(0) != null) { + throw serviceErrors.get(0); + } + System.out.println("done"); + break; + } + case 8: + System.out.print("Sending GI.."); + association.startGi(urcb); + System.out.println("done"); + break; + default: + System.err.println("Unknown option."); + break; + } + } catch (ServiceError e) { + System.err.println("Service error: " + e.getMessage()); + } catch (NumberFormatException e) { + System.err.println("Cannot parse number: " + e.getMessage()); + } + } + } + default: + break; + } + } catch (Exception e) { + throw new ActionException(e); + } + } + + private FcModelNode askForFcModelNode() throws IOException, ActionException { + System.out.println("Enter reference (e.g. myld/MYLN0.do.da.bda): "); + String reference = actionProcessor.getReader().readLine(); + System.out.println("Enter functional constraint of referenced node: "); + String fcString = actionProcessor.getReader().readLine(); + + Fc fc = Fc.fromString(fcString); + if (fc == null) { + throw new ActionException("Unknown functional constraint."); + } + + ModelNode modelNode = serverModel.findModelNode(reference, Fc.fromString(fcString)); + if (modelNode == null) { + throw new ActionException( + "A model node with the given reference and functional constraint could not be found."); + } + + if (!(modelNode instanceof FcModelNode)) { + throw new ActionException( + "The given model node is not a functionally constraint model node."); + } + + FcModelNode fcModelNode = (FcModelNode) modelNode; + return fcModelNode; + } + + @Override + public void quit() { + System.out.println("** Closing connection."); + association.close(); + return; + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/app/ConsoleServer.java b/src/main/java/com/beanit/iec61850bean/app/ConsoleServer.java new file mode 100644 index 0000000..59049c9 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/app/ConsoleServer.java @@ -0,0 +1,250 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.app; + +import com.beanit.iec61850bean.BasicDataAttribute; +import com.beanit.iec61850bean.BdaBoolean; +import com.beanit.iec61850bean.BdaFloat32; +import com.beanit.iec61850bean.BdaFloat64; +import com.beanit.iec61850bean.BdaInt16; +import com.beanit.iec61850bean.BdaInt16U; +import com.beanit.iec61850bean.BdaInt32; +import com.beanit.iec61850bean.BdaInt32U; +import com.beanit.iec61850bean.BdaInt64; +import com.beanit.iec61850bean.BdaInt8; +import com.beanit.iec61850bean.BdaInt8U; +import com.beanit.iec61850bean.Fc; +import com.beanit.iec61850bean.ModelNode; +import com.beanit.iec61850bean.SclParseException; +import com.beanit.iec61850bean.SclParser; +import com.beanit.iec61850bean.ServerEventListener; +import com.beanit.iec61850bean.ServerModel; +import com.beanit.iec61850bean.ServerSap; +import com.beanit.iec61850bean.ServiceError; +import com.beanit.iec61850bean.internal.cli.Action; +import com.beanit.iec61850bean.internal.cli.ActionException; +import com.beanit.iec61850bean.internal.cli.ActionListener; +import com.beanit.iec61850bean.internal.cli.ActionProcessor; +import com.beanit.iec61850bean.internal.cli.CliParameter; +import com.beanit.iec61850bean.internal.cli.CliParameterBuilder; +import com.beanit.iec61850bean.internal.cli.CliParseException; +import com.beanit.iec61850bean.internal.cli.CliParser; +import com.beanit.iec61850bean.internal.cli.IntCliParameter; +import com.beanit.iec61850bean.internal.cli.StringCliParameter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ConsoleServer { + + private static final String WRITE_VALUE_KEY = "w"; + private static final String WRITE_VALUE_KEY_DESCRIPTION = "write value to model node"; + + private static final String PRINT_SERVER_MODEL_KEY = "p"; + private static final String PRINT_SERVER_MODEL_KEY_DESCRIPTION = "print server's model"; + + private static final IntCliParameter portParam = + new CliParameterBuilder("-p") + .setDescription( + "The port to listen on. On unix based systems you need root privilages for ports < 1000.") + .buildIntParameter("port", 102); + + private static final StringCliParameter modelFileParam = + new CliParameterBuilder("-m") + .setDescription("The SCL file that contains the server's information model.") + .setMandatory() + .buildStringParameter("model-file"); + private static final ActionProcessor actionProcessor = new ActionProcessor(new ActionExecutor()); + private static ServerModel serverModel; + private static ServerSap serverSap = null; + + public static void main(String[] args) throws IOException { + + List cliParameters = new ArrayList<>(); + cliParameters.add(modelFileParam); + cliParameters.add(portParam); + + CliParser cliParser = + new CliParser("iec61850bean-console-server", "An IEC 61850 MMS console server."); + cliParser.addParameters(cliParameters); + + try { + cliParser.parseArguments(args); + } catch (CliParseException e1) { + System.err.println("Error parsing command line parameters: " + e1.getMessage()); + System.out.println(cliParser.getUsageString()); + System.exit(1); + } + + List serverModels = null; + try { + serverModels = SclParser.parse(modelFileParam.getValue()); + } catch (SclParseException e) { + System.out.println("Error parsing SCL/ICD file: " + e.getMessage()); + return; + } + + serverSap = new ServerSap(102, 0, null, serverModels.get(0), null); + serverSap.setPort(portParam.getValue()); + + Runtime.getRuntime() + .addShutdownHook( + new Thread() { + @Override + public void run() { + if (serverSap != null) { + serverSap.stop(); + } + System.out.println("Server was stopped."); + } + }); + + serverModel = serverSap.getModelCopy(); + + serverSap.startListening(new EventListener()); + + actionProcessor.addAction( + new Action(PRINT_SERVER_MODEL_KEY, PRINT_SERVER_MODEL_KEY_DESCRIPTION)); + actionProcessor.addAction(new Action(WRITE_VALUE_KEY, WRITE_VALUE_KEY_DESCRIPTION)); + + actionProcessor.start(); + } + + private static class EventListener implements ServerEventListener { + + @Override + public void serverStoppedListening(ServerSap serverSap) { + System.out.println("The SAP stopped listening"); + } + + @Override + public List write(List bdas) { + for (BasicDataAttribute bda : bdas) { + System.out.println("got a write request: " + bda); + } + return null; + } + } + + private static class ActionExecutor implements ActionListener { + + @Override + public void actionCalled(String actionKey) throws ActionException { + try { + switch (actionKey) { + case PRINT_SERVER_MODEL_KEY: + System.out.println("** Printing model."); + + System.out.println(serverModel); + + break; + case WRITE_VALUE_KEY: + System.out.println("Enter reference to write (e.g. myld/MYLN0.do.da.bda): "); + String reference = actionProcessor.getReader().readLine(); + System.out.println("Enter functional constraint of referenced node: "); + String fcString = actionProcessor.getReader().readLine(); + + Fc fc = Fc.fromString(fcString); + if (fc == null) { + System.out.println("Unknown functional constraint."); + return; + } + + ModelNode modelNode = serverModel.findModelNode(reference, Fc.fromString(fcString)); + if (modelNode == null) { + System.out.println( + "A model node with the given reference and functional constraint could not be found."); + return; + } + + if (!(modelNode instanceof BasicDataAttribute)) { + System.out.println("The given model node is not a basic data attribute."); + return; + } + + BasicDataAttribute bda = + (BasicDataAttribute) serverModel.findModelNode(reference, Fc.fromString(fcString)); + + System.out.println("Enter value to write: "); + String valueString = actionProcessor.getReader().readLine(); + + try { + setBdaValue(bda, valueString); + } catch (Exception e) { + System.out.println( + "The console server does not support writing this type of basic data attribute."); + return; + } + + List bdas = new ArrayList<>(); + bdas.add(bda); + serverSap.setValues(bdas); + + System.out.println("Successfully wrote data."); + System.out.println(bda); + + break; + + default: + break; + } + } catch (Exception e) { + throw new ActionException(e); + } + } + + private void setBdaValue(BasicDataAttribute bda, String valueString) { + if (bda instanceof BdaFloat32) { + float value = Float.parseFloat(valueString); + ((BdaFloat32) bda).setFloat(value); + } else if (bda instanceof BdaFloat64) { + double value = Float.parseFloat(valueString); + ((BdaFloat64) bda).setDouble(value); + } else if (bda instanceof BdaInt8) { + byte value = Byte.parseByte(valueString); + ((BdaInt8) bda).setValue(value); + } else if (bda instanceof BdaInt8U) { + short value = Short.parseShort(valueString); + ((BdaInt8U) bda).setValue(value); + } else if (bda instanceof BdaInt16) { + short value = Short.parseShort(valueString); + ((BdaInt16) bda).setValue(value); + } else if (bda instanceof BdaInt16U) { + int value = Integer.parseInt(valueString); + ((BdaInt16U) bda).setValue(value); + } else if (bda instanceof BdaInt32) { + int value = Integer.parseInt(valueString); + ((BdaInt32) bda).setValue(value); + } else if (bda instanceof BdaInt32U) { + long value = Long.parseLong(valueString); + ((BdaInt32U) bda).setValue(value); + } else if (bda instanceof BdaInt64) { + long value = Long.parseLong(valueString); + ((BdaInt64) bda).setValue(value); + } else if (bda instanceof BdaBoolean) { + boolean value = Boolean.parseBoolean(valueString); + ((BdaBoolean) bda).setValue(value); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public void quit() { + System.out.println("** Stopping server."); + serverSap.stop(); + return; + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/BasicDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/BasicDataBind.java new file mode 100644 index 0000000..e99f24c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/BasicDataBind.java @@ -0,0 +1,66 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import com.beanit.iec61850bean.BasicDataAttribute; +import com.beanit.iec61850bean.BdaType; +import javax.swing.JComponent; +import javax.swing.JLabel; + +public abstract class BasicDataBind { + protected final E data; + + private JComponent valueField; + + protected BasicDataBind(E data, BdaType type) { + if (data.getBasicType() != type) { + throw new IllegalArgumentException(data.getName() + " is no " + type); + } + this.data = data; + } + + public JLabel getNameLabel() { + return new JLabel(data.getName()); + } + + public JComponent getValueField() { + if (valueField == null) { + valueField = init(); + } + + return valueField; + } + + public void reset() { + if (valueField == null) { + valueField = init(); + } + + resetImpl(); + } + + public void write() { + if (valueField == null) { + valueField = init(); + } + + writeImpl(); + } + + protected abstract JComponent init(); + + protected abstract void resetImpl(); + + protected abstract void writeImpl(); +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/ClientGui.java b/src/main/java/com/beanit/iec61850bean/clientgui/ClientGui.java new file mode 100644 index 0000000..a981eca --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/ClientGui.java @@ -0,0 +1,441 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import com.beanit.iec61850bean.ClientAssociation; +import com.beanit.iec61850bean.ClientSap; +import com.beanit.iec61850bean.ServerModel; +import com.beanit.iec61850bean.ServiceError; +import com.beanit.iec61850bean.clientgui.util.Counter; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Properties; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSeparator; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.ToolTipManager; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +public class ClientGui extends JFrame implements ActionListener, TreeSelectionListener { + + private static final String ADDRESS_KEY = "serverAddress"; + private static final String PORT_KEY = "serverPort"; + private static final String TSEL_LOCAL_KEY = "tselLocal"; + private static final String TSEL_REMOTE_KEY = "tselRemote"; + private static final String LASTCONNECTION_FILE = "lastconnection.properties"; + + private static final long serialVersionUID = -1938913902977758367L; + + private final JTextField ipTextField = new JTextField("127.0.0.1"); + private final JTextField portTextField = new JTextField("10002"); + private final JTree tree = new JTree(new DefaultMutableTreeNode("No server connected")); + private final JPanel detailsPanel = new JPanel(); + private final GridBagLayout detailsLayout = new GridBagLayout(); + + private final SettingsFrame settingsFrame = new SettingsFrame(); + + private ClientAssociation association; + + private DataTreeNode selectedNode; + + public ClientGui() { + super("IEC61850bean Client GUI"); + + Properties lastConnection = new Properties(); + + InputStream in = null; + try { + in = new FileInputStream(LASTCONNECTION_FILE); + lastConnection.load(in); + + ipTextField.setText(lastConnection.getProperty(ADDRESS_KEY)); + portTextField.setText(lastConnection.getProperty(PORT_KEY)); + + String[] tselString = lastConnection.getProperty(TSEL_LOCAL_KEY).split(","); + byte[] tsel = + new byte[] { + (byte) Integer.parseInt(tselString[0]), (byte) Integer.parseInt(tselString[1]) + }; + settingsFrame.setTselLocal(tsel); + + tselString = lastConnection.getProperty(TSEL_REMOTE_KEY).split(","); + tsel = + new byte[] { + (byte) Integer.parseInt(tselString[0]), (byte) Integer.parseInt(tselString[1]) + }; + settingsFrame.setTselRemote(tsel); + } catch (Exception ex) { + // no lastconnection.properties file found, use default. + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException ignored) { + // there is nothing that can be done if closing fails + } + } + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException e) { + System.out.println("Class not found: " + e.getMessage()); + } catch (InstantiationException e) { + System.out.println("Object not instantiated: " + e.getMessage()); + } catch (IllegalAccessException e) { + System.out.println("Illegal acces: " + e.getMessage()); + } catch (UnsupportedLookAndFeelException e) { + System.out.println("Unsupported LookAndFeel: " + e.getMessage()); + } + + GridBagLayout gbl = new GridBagLayout(); + setLayout(gbl); + + JPanel topPanel = new JPanel(); + topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS)); + + GridBagConstraints topPanelConstraint = new GridBagConstraints(); + topPanelConstraint.fill = GridBagConstraints.HORIZONTAL; + topPanelConstraint.gridwidth = GridBagConstraints.REMAINDER; + topPanelConstraint.gridx = 0; + topPanelConstraint.gridy = 0; + topPanelConstraint.insets = new Insets(5, 5, 5, 5); + topPanelConstraint.anchor = GridBagConstraints.NORTH; + gbl.setConstraints(topPanel, topPanelConstraint); + add(topPanel); + + JLabel label = new JLabel("IP: "); + topPanel.add(label); + topPanel.add(ipTextField); + topPanel.add(Box.createRigidArea(new Dimension(5, 0))); + + label = new JLabel("Port: "); + topPanel.add(label); + topPanel.add(portTextField); + topPanel.add(Box.createRigidArea(new Dimension(5, 0))); + + JButton newServerButton = new JButton("Connect to Server"); + newServerButton.addActionListener(this); + newServerButton.setActionCommand("Connect"); + topPanel.add(newServerButton); + topPanel.add(Box.createRigidArea(new Dimension(5, 0))); + + JButton settingsButton = new JButton("Settings"); + settingsButton.addActionListener(this); + settingsButton.setActionCommand("Settings"); + topPanel.add(settingsButton); + + ToolTipManager.sharedInstance().registerComponent(tree); + + tree.setCellRenderer(new DataObjectTreeCellRenderer()); + tree.setMinimumSize(new Dimension(100, 0)); + tree.addTreeSelectionListener(this); + JScrollPane treeScrollPane = new JScrollPane(tree); + treeScrollPane.setMinimumSize(new Dimension(100, 0)); + treeScrollPane.setVisible(true); + + GridBagConstraints treeScrollPaneConstraint = new GridBagConstraints(); + treeScrollPaneConstraint.fill = GridBagConstraints.BOTH; + treeScrollPaneConstraint.gridx = 0; + treeScrollPaneConstraint.gridy = 1; + treeScrollPaneConstraint.weightx = 0.2; + treeScrollPaneConstraint.weighty = 1; + treeScrollPaneConstraint.insets = new Insets(5, 5, 5, 5); + gbl.setConstraints(treeScrollPane, treeScrollPaneConstraint); + add(treeScrollPane); + + detailsPanel.setLayout(detailsLayout); + detailsPanel.setAlignmentY(TOP_ALIGNMENT); + JScrollPane detailsScrollPane = new JScrollPane(detailsPanel); + detailsPanel.setMaximumSize(detailsScrollPane.getSize()); + detailsScrollPane.setMinimumSize(new Dimension(0, 0)); + detailsScrollPane.setPreferredSize(new Dimension(200, 0)); + detailsScrollPane.setVisible(true); + GridBagConstraints detailsScrollPaneConstraint = new GridBagConstraints(); + detailsScrollPaneConstraint.fill = GridBagConstraints.BOTH; + detailsScrollPaneConstraint.gridx = 1; + detailsScrollPaneConstraint.gridy = 1; + detailsScrollPaneConstraint.weightx = 0.8; + detailsScrollPaneConstraint.weighty = 1; + detailsScrollPaneConstraint.insets = new Insets(5, 5, 5, 5); + gbl.setConstraints(detailsScrollPane, detailsScrollPaneConstraint); + add(detailsScrollPane); + + // Display the window. + setSize(700, 500); + setMinimumSize(new Dimension(420, 0)); + setVisible(true); + } + + public static void main(String[] args) { + ClientGui clientGui = new ClientGui(); + clientGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + clientGui.setVisible(true); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + if ("connect".equalsIgnoreCase(arg0.getActionCommand())) { + connect(); + } else if ("reload".equalsIgnoreCase(arg0.getActionCommand())) { + reload(); + } else if ("write".equalsIgnoreCase(arg0.getActionCommand())) { + write(); + } else if ("settings".equalsIgnoreCase(arg0.getActionCommand())) { + settingsFrame.setVisible(true); + } + } + + @Override + public void valueChanged(TreeSelectionEvent e) { + detailsPanel.removeAll(); + detailsPanel.repaint(); + if (e.getNewLeadSelectionPath() != null) { + selectedNode = (DataTreeNode) e.getNewLeadSelectionPath().getLastPathComponent(); + if (selectedNode.readable()) { + showDataDetails(selectedNode, new Counter()); + + JPanel filler = new JPanel(); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.BOTH; + gbc.gridx = 0; + gbc.gridy = GridBagConstraints.RELATIVE; + gbc.gridwidth = 3; + gbc.gridheight = 1; + gbc.weightx = 0; + gbc.weighty = 1; + detailsLayout.setConstraints(filler, gbc); + detailsPanel.add(filler); + + JButton button = new JButton("Reload values"); + button.addActionListener(this); + button.setActionCommand("reload"); + gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.NONE; + gbc.gridx = 0; + gbc.gridy = GridBagConstraints.RELATIVE; + gbc.gridwidth = 2; + gbc.gridheight = 1; + gbc.weightx = 0; + gbc.weighty = 0; + gbc.anchor = GridBagConstraints.SOUTHWEST; + gbc.insets = new Insets(0, 5, 5, 0); + detailsLayout.setConstraints(button, gbc); + detailsPanel.add(button); + + if (selectedNode.writable()) { + button = new JButton("Write values"); + button.addActionListener(this); + button.setActionCommand("write"); + gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.NONE; + gbc.gridx = 2; + gbc.gridy = GridBagConstraints.RELATIVE; + gbc.gridwidth = 1; + gbc.gridheight = 1; + gbc.weightx = 0; + gbc.weighty = 0; + gbc.anchor = GridBagConstraints.SOUTHEAST; + gbc.insets = new Insets(0, 0, 5, 5); + detailsLayout.setConstraints(button, gbc); + detailsPanel.add(button); + } + } + } else { + selectedNode = null; + } + + validate(); + } + + private void connect() { + ClientSap clientSap = new ClientSap(); + + InetAddress address = null; + try { + address = InetAddress.getByName(ipTextField.getText()); + } catch (UnknownHostException e1) { + e1.printStackTrace(); + return; + } + + int remotePort = 10002; + try { + remotePort = Integer.parseInt(portTextField.getText()); + if (remotePort < 1 || remotePort > 0xFFFF) { + throw new NumberFormatException("port must be in range [1, 65535]"); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + return; + } + + clientSap.setTSelLocal(settingsFrame.getTselLocal()); + clientSap.setTSelRemote(settingsFrame.getTselRemote()); + + try { + association = clientSap.associate(address, remotePort, null, null); + } catch (IOException e) { + System.out.println("Error connecting to server: " + e.getMessage()); + return; + } + + ServerModel serverModel; + try { + serverModel = association.retrieveModel(); + association.getAllDataValues(); + } catch (ServiceError e) { + System.out.println("Service Error requesting model." + e.getMessage()); + association.close(); + return; + } catch (IOException e) { + System.out.println("Fatal IOException requesting model." + e.getMessage()); + return; + } + + ServerModelParser parser = new ServerModelParser(serverModel); + tree.setModel(new DefaultTreeModel(parser.getModelTree())); + + Properties lastConnectSettings = new Properties(); + FileOutputStream out = null; + try { + lastConnectSettings.setProperty(ADDRESS_KEY, ipTextField.getText()); + lastConnectSettings.setProperty(PORT_KEY, portTextField.getText()); + byte[] tsel = settingsFrame.getTselLocal(); + lastConnectSettings.setProperty(TSEL_LOCAL_KEY, tsel[0] + "," + tsel[1]); + tsel = settingsFrame.getTselRemote(); + lastConnectSettings.setProperty(TSEL_REMOTE_KEY, tsel[0] + "," + tsel[1]); + + out = new FileOutputStream(LASTCONNECTION_FILE); + lastConnectSettings.store(out, null); + } catch (IOException ex) { + System.out.println("Writing properties file failed. Reason: " + ex.getMessage()); + } finally { + try { + if (out != null) { + out.close(); + } + } catch (IOException e) { + // nothing meaningful can be done if closing fails + } + } + + validate(); + } + + private void reload() { + if (selectedNode.readable()) { + try { + selectedNode.reset(association); + } catch (ServiceError e) { + System.out.println("ServiceError on reading" + e.getMessage()); + return; + } catch (IOException e) { + System.out.println("IOException on reading" + e.getMessage()); + return; + } + validate(); + } + } + + private void write() { + if (selectedNode.writable()) { + try { + selectedNode.writeValues(association); + } catch (ServiceError e) { + System.out.println("ServiceError on writing" + e.getMessage()); + return; + } catch (IOException e) { + System.out.println("IOException on writing" + e.getMessage()); + return; + } + validate(); + } + } + + private void showDataDetails(DataTreeNode node, Counter y) { + if (node.getData() != null) { + BasicDataBind data = node.getData(); + JLabel nameLabel = data.getNameLabel(); + nameLabel.setText(nameLabel.getText() + ": "); + addDetailsComponent(nameLabel, 0, y.getValue(), 1, 1, 0, 0); + addDetailsComponent(data.getValueField(), 1, y.getValue(), 2, 1, 1, 0); + y.increment(); + } else { + for (int i = 0; i < node.getChildCount(); i++) { + y.increment(); + DataObjectTreeNode childNode = (DataObjectTreeNode) node.getChildAt(i); + showDataDetails(childNode, childNode.toString(), y); + } + } + } + + private void showDataDetails(DataTreeNode node, String pre, Counter y) { + if (node.getData() != null) { + BasicDataBind data = node.getData(); + JLabel nameLabel = data.getNameLabel(); + nameLabel.setText(pre + ": "); + addDetailsComponent(nameLabel, 0, y.getValue(), 1, 1, 0, 0); + addDetailsComponent(data.getValueField(), 1, y.getValue(), 2, 1, 1, 0); + y.increment(); + } else { + for (int i = 0; i < node.getChildCount(); i++) { + y.increment(); + DataObjectTreeNode childNode = (DataObjectTreeNode) node.getChildAt(i); + showDataDetails(childNode, pre + "." + childNode.toString(), y); + detailsPanel.add(new JSeparator()); + addDetailsComponent(new JSeparator(), 0, y.getValue(), 3, 1, 1, 0); + } + } + } + + private void addDetailsComponent( + Component c, int x, int y, int width, int height, double weightx, double weighty) { + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.gridx = x; + gbc.gridy = y; + gbc.gridwidth = width; + gbc.gridheight = height; + gbc.weightx = weightx; + gbc.weighty = weighty; + gbc.anchor = GridBagConstraints.NORTH; + gbc.insets = new Insets(3, 3, 3, 3); + detailsLayout.setConstraints(c, gbc); + detailsPanel.add(c); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/DataObjectTreeCellRenderer.java b/src/main/java/com/beanit/iec61850bean/clientgui/DataObjectTreeCellRenderer.java new file mode 100644 index 0000000..808ec07 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/DataObjectTreeCellRenderer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import com.beanit.iec61850bean.BasicDataAttribute; +import com.beanit.iec61850bean.FcModelNode; +import java.awt.Component; +import javax.swing.JTree; +import javax.swing.tree.DefaultTreeCellRenderer; + +public class DataObjectTreeCellRenderer extends DefaultTreeCellRenderer { + + private static final long serialVersionUID = 1682378972258556129L; + + @Override + public Component getTreeCellRendererComponent( + JTree tree, + Object value, + boolean sel, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + + if (value instanceof DataObjectTreeNode) { + DataObjectTreeNode treeNode = (DataObjectTreeNode) value; + if (!leaf && treeNode.getNode() instanceof FcModelNode) { + setIcon(getLeafIcon()); + } + + if (treeNode.getNode() instanceof BasicDataAttribute) { + BasicDataAttribute attribute = (BasicDataAttribute) treeNode.getNode(); + String tooltip = attribute.getSAddr(); + setToolTipText(tooltip); + } + } + + return this; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/DataObjectTreeNode.java b/src/main/java/com/beanit/iec61850bean/clientgui/DataObjectTreeNode.java new file mode 100644 index 0000000..ec60968 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/DataObjectTreeNode.java @@ -0,0 +1,199 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import com.beanit.iec61850bean.BasicDataAttribute; +import com.beanit.iec61850bean.BdaBoolean; +import com.beanit.iec61850bean.BdaCheck; +import com.beanit.iec61850bean.BdaDoubleBitPos; +import com.beanit.iec61850bean.BdaEntryTime; +import com.beanit.iec61850bean.BdaFloat32; +import com.beanit.iec61850bean.BdaFloat64; +import com.beanit.iec61850bean.BdaInt16; +import com.beanit.iec61850bean.BdaInt16U; +import com.beanit.iec61850bean.BdaInt32; +import com.beanit.iec61850bean.BdaInt32U; +import com.beanit.iec61850bean.BdaInt64; +import com.beanit.iec61850bean.BdaInt8; +import com.beanit.iec61850bean.BdaInt8U; +import com.beanit.iec61850bean.BdaOctetString; +import com.beanit.iec61850bean.BdaOptFlds; +import com.beanit.iec61850bean.BdaQuality; +import com.beanit.iec61850bean.BdaReasonForInclusion; +import com.beanit.iec61850bean.BdaTapCommand; +import com.beanit.iec61850bean.BdaTimestamp; +import com.beanit.iec61850bean.BdaTriggerConditions; +import com.beanit.iec61850bean.BdaUnicodeString; +import com.beanit.iec61850bean.BdaVisibleString; +import com.beanit.iec61850bean.ClientAssociation; +import com.beanit.iec61850bean.Fc; +import com.beanit.iec61850bean.FcModelNode; +import com.beanit.iec61850bean.ModelNode; +import com.beanit.iec61850bean.ServiceError; +import com.beanit.iec61850bean.clientgui.databind.BooleanDataBind; +import com.beanit.iec61850bean.clientgui.databind.CheckDataBind; +import com.beanit.iec61850bean.clientgui.databind.DoubleBitPosDataBind; +import com.beanit.iec61850bean.clientgui.databind.EntryTimeDataBind; +import com.beanit.iec61850bean.clientgui.databind.Float32DataBind; +import com.beanit.iec61850bean.clientgui.databind.Float64DataBind; +import com.beanit.iec61850bean.clientgui.databind.Int16DataBind; +import com.beanit.iec61850bean.clientgui.databind.Int16UDataBind; +import com.beanit.iec61850bean.clientgui.databind.Int32DataBind; +import com.beanit.iec61850bean.clientgui.databind.Int32UDataBind; +import com.beanit.iec61850bean.clientgui.databind.Int64DataBind; +import com.beanit.iec61850bean.clientgui.databind.Int8DataBind; +import com.beanit.iec61850bean.clientgui.databind.Int8UDataBind; +import com.beanit.iec61850bean.clientgui.databind.OctetStringDataBind; +import com.beanit.iec61850bean.clientgui.databind.OptfldsDataBind; +import com.beanit.iec61850bean.clientgui.databind.QualityDataBind; +import com.beanit.iec61850bean.clientgui.databind.ReasonForInclusionDataBind; +import com.beanit.iec61850bean.clientgui.databind.TapCommandDataBind; +import com.beanit.iec61850bean.clientgui.databind.TimeStampDataBind; +import com.beanit.iec61850bean.clientgui.databind.TriggerConditionDataBind; +import com.beanit.iec61850bean.clientgui.databind.UnicodeStringDataBind; +import com.beanit.iec61850bean.clientgui.databind.VisibleStringDataBind; +import java.io.IOException; +import javax.swing.tree.DefaultMutableTreeNode; + +public class DataObjectTreeNode extends DefaultMutableTreeNode implements DataTreeNode { + + private static final long serialVersionUID = -3596243932937737877L; + + private final ModelNode node; + private final BasicDataBind data; + + public DataObjectTreeNode(String name, ModelNode node) { + super(name); + this.node = node; + if (node != null && node.getChildren() == null) { + // for (ModelNode child : node.getChildren()) { + // if (child instanceof BasicDataAttribute) { + // data.add(createDataBind((BasicDataAttribute) child)); + // } + // } + data = createDataBind((BasicDataAttribute) node); + } else { + data = null; + } + } + + private static BasicDataBind createDataBind(BasicDataAttribute bda) { + switch (bda.getBasicType()) { + case BOOLEAN: + return new BooleanDataBind((BdaBoolean) bda); + case ENTRY_TIME: + return new EntryTimeDataBind((BdaEntryTime) bda); + case FLOAT32: + return new Float32DataBind((BdaFloat32) bda); + case FLOAT64: + return new Float64DataBind((BdaFloat64) bda); + case INT16: + return new Int16DataBind((BdaInt16) bda); + case INT16U: + return new Int16UDataBind((BdaInt16U) bda); + case INT32: + return new Int32DataBind((BdaInt32) bda); + case INT32U: + return new Int32UDataBind((BdaInt32U) bda); + case INT64: + return new Int64DataBind((BdaInt64) bda); + case INT8: + return new Int8DataBind((BdaInt8) bda); + case INT8U: + return new Int8UDataBind((BdaInt8U) bda); + case OCTET_STRING: + return new OctetStringDataBind((BdaOctetString) bda); + case TIMESTAMP: + return new TimeStampDataBind((BdaTimestamp) bda); + case UNICODE_STRING: + return new UnicodeStringDataBind((BdaUnicodeString) bda); + case VISIBLE_STRING: + return new VisibleStringDataBind((BdaVisibleString) bda); + case CHECK: + return new CheckDataBind((BdaCheck) bda); + case DOUBLE_BIT_POS: + return new DoubleBitPosDataBind((BdaDoubleBitPos) bda); + case OPTFLDS: + return new OptfldsDataBind((BdaOptFlds) bda); + case QUALITY: + return new QualityDataBind((BdaQuality) bda); + case REASON_FOR_INCLUSION: + return new ReasonForInclusionDataBind((BdaReasonForInclusion) bda); + case TAP_COMMAND: + return new TapCommandDataBind((BdaTapCommand) bda); + case TRIGGER_CONDITIONS: + return new TriggerConditionDataBind((BdaTriggerConditions) bda); + default: + throw new IllegalArgumentException("BasicType " + bda.getBasicType() + " unknown"); + } + } + + public ModelNode getNode() { + return node; + } + + @Override + public BasicDataBind getData() { + return data; + } + + @Override + public void reset(ClientAssociation association) throws ServiceError, IOException { + if (association != null) { + association.getDataValues((FcModelNode) node); + } + if (data != null) { + data.reset(); + } else { + for (int i = 0; i < getChildCount(); i++) { + if (getChildAt(i) instanceof DataObjectTreeNode) { + DataTreeNode child = (DataTreeNode) getChildAt(i); + child.reset(null); + } + } + } + } + + @Override + public void writeValues(ClientAssociation association) throws ServiceError, IOException { + if (data != null) { + data.write(); + } else { + for (int i = 0; i < getChildCount(); i++) { + if (getChildAt(i) instanceof DataObjectTreeNode) { + DataTreeNode child = (DataTreeNode) getChildAt(i); + child.writeValues(null); + } + } + } + if (association != null) { + association.setDataValues((FcModelNode) node); + } + } + + @Override + public boolean writable() { + if (node instanceof FcModelNode) { + FcModelNode modelNode = (FcModelNode) node; + Fc constraint = modelNode.getFc(); + return constraint != Fc.ST && constraint != Fc.MX; + } + return false; + } + + @Override + public boolean readable() { + return node instanceof FcModelNode; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/DataSetTreeNode.java b/src/main/java/com/beanit/iec61850bean/clientgui/DataSetTreeNode.java new file mode 100644 index 0000000..bbf1a9a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/DataSetTreeNode.java @@ -0,0 +1,77 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import com.beanit.iec61850bean.ClientAssociation; +import com.beanit.iec61850bean.DataSet; +import com.beanit.iec61850bean.ServiceError; +import java.io.IOException; +import javax.swing.tree.DefaultMutableTreeNode; + +public class DataSetTreeNode extends DefaultMutableTreeNode implements DataTreeNode { + + private static final long serialVersionUID = 7919716359809465616L; + + private final DataSet node; + + public DataSetTreeNode(String name, DataSet node) { + super(name); + this.node = node; + } + + public DataSet getNode() { + return node; + } + + @Override + public void reset(ClientAssociation association) throws ServiceError, IOException { + if (association != null) { + association.getDataSetValues(node); + } + for (int i = 0; i < getChildCount(); i++) { + if (getChildAt(i) instanceof DataObjectTreeNode) { + DataTreeNode child = (DataTreeNode) getChildAt(i); + child.reset(null); + } + } + } + + @Override + public void writeValues(ClientAssociation association) throws ServiceError, IOException { + for (int i = 0; i < getChildCount(); i++) { + if (getChildAt(i) instanceof DataObjectTreeNode) { + DataTreeNode child = (DataTreeNode) getChildAt(i); + child.writeValues(null); + } + } + if (association != null) { + association.setDataSetValues(node); + } + } + + @Override + public BasicDataBind getData() { + return null; + } + + @Override + public boolean writable() { + return true; + } + + @Override + public boolean readable() { + return true; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/DataTreeNode.java b/src/main/java/com/beanit/iec61850bean/clientgui/DataTreeNode.java new file mode 100644 index 0000000..92e108c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/DataTreeNode.java @@ -0,0 +1,36 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import com.beanit.iec61850bean.ClientAssociation; +import com.beanit.iec61850bean.ServiceError; +import java.io.IOException; +import javax.swing.tree.TreeNode; + +public interface DataTreeNode { + + BasicDataBind getData(); + + void reset(ClientAssociation association) throws ServiceError, IOException; + + void writeValues(ClientAssociation association) throws ServiceError, IOException; + + int getChildCount(); + + TreeNode getChildAt(int index); + + boolean writable(); + + boolean readable(); +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/ServerModelParser.java b/src/main/java/com/beanit/iec61850bean/clientgui/ServerModelParser.java new file mode 100644 index 0000000..e904391 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/ServerModelParser.java @@ -0,0 +1,131 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import com.beanit.iec61850bean.DataSet; +import com.beanit.iec61850bean.Fc; +import com.beanit.iec61850bean.FcModelNode; +import com.beanit.iec61850bean.LogicalDevice; +import com.beanit.iec61850bean.LogicalNode; +import com.beanit.iec61850bean.ModelNode; +import com.beanit.iec61850bean.ServerModel; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.swing.tree.TreeNode; + +public class ServerModelParser { + + private final ServerModel model; + private DataObjectTreeNode modelTree; + + public ServerModelParser(ServerModel model) { + this.model = model; + } + + public TreeNode getModelTree() { + if (modelTree == null) { + createModelTree(); + } + return modelTree; + } + + private synchronized void createModelTree() { + if (modelTree == null) { + modelTree = new DataObjectTreeNode("server", null); + for (ModelNode node : model.getChildren()) { + if (node instanceof LogicalDevice == false) { + System.out.println( + "Node " + node.getName() + " is " + node.getClass() + " (should be LogicalDevice)"); + continue; + } + addLogicalDevice(modelTree, (LogicalDevice) node); + } + for (DataSet dataSet : model.getDataSets()) { + addDataSet(modelTree, dataSet); + } + } + } + + private void addLogicalDevice(DataObjectTreeNode root, LogicalDevice node) { + DataObjectTreeNode treeLD = new DataObjectTreeNode(node.getName(), node); + root.add(treeLD); + for (ModelNode subNode : node.getChildren()) { + if (subNode instanceof LogicalNode == false) { + System.out.println( + "Node " + subNode.getName() + " is " + subNode.getClass() + " (should be LogicalNode)"); + continue; + } + addLogicalNode(treeLD, (LogicalNode) subNode); + } + } + + private void addLogicalNode(DataObjectTreeNode parent, LogicalNode node) { + DataObjectTreeNode treeLN = new DataObjectTreeNode(node.getName(), node); + parent.add(treeLN); + Collection children = node.getChildren(); + Map> childMap = new HashMap<>(); + for (ModelNode child : children) { + if (!childMap.containsKey(child.getName())) { + childMap.put(child.getName(), new HashSet()); + } + childMap.get(child.getName()).add(((FcModelNode) child).getFc()); + } + for (Map.Entry> childEntry : childMap.entrySet()) { + addFunctionalConstraintObject(treeLN, node, childEntry.getKey(), childEntry.getValue()); + } + } + + private void addDataSet(DataObjectTreeNode parent, DataSet node) { + DataSetTreeNode treeDS = new DataSetTreeNode(node.getReferenceStr(), node); + parent.add(treeDS); + Collection children = node.getMembers(); + for (ModelNode child : children) { + addFunctionalConstraintObject(treeDS, child); + } + } + + private void addFunctionalConstraintObject( + DataObjectTreeNode parent, LogicalNode parentNode, String childName, Set childFcs) { + DataObjectTreeNode treeFCDO = new DataObjectTreeNode(childName, null); + parent.add(treeFCDO); + + for (Fc constraint : childFcs) { + ModelNode subNode = parentNode.getChild(childName, constraint); + addDataObject(treeFCDO, "[" + constraint + "]", subNode); + } + } + + private void addFunctionalConstraintObject(DataSetTreeNode parent, ModelNode node) { + DataObjectTreeNode treeFCDO = new DataObjectTreeNode(node.getReference().toString(), node); + parent.add(treeFCDO); + if (node.getChildren() != null) { + for (ModelNode subNode : node.getChildren()) { + addDataObject(treeFCDO, subNode.getName(), subNode); + } + } + } + + private void addDataObject(DataObjectTreeNode parent, String name, ModelNode node) { + DataObjectTreeNode treeDO = new DataObjectTreeNode(name, node); + parent.add(treeDO); + if (node.getChildren() != null) { + for (ModelNode subNode : node.getChildren()) { + addDataObject(treeDO, subNode.getName(), subNode); + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/SettingsFrame.java b/src/main/java/com/beanit/iec61850bean/clientgui/SettingsFrame.java new file mode 100644 index 0000000..52640bb --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/SettingsFrame.java @@ -0,0 +1,202 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JTextField; + +public class SettingsFrame extends JDialog implements ActionListener { + + private static final long serialVersionUID = -411845634137160667L; + + private int tselLocal1 = 0; + private final JTextField tselLocalField1 = new JTextField(Integer.toString(tselLocal1)); + private int tselLocal2 = 0; + private final JTextField tselLocalField2 = new JTextField(Integer.toString(tselLocal2)); + private int tselRemote1 = 0; + private final JTextField tselRemoteField1 = new JTextField(Integer.toString(tselRemote1)); + private int tselRemote2 = 1; + private final JTextField tselRemoteField2 = new JTextField(Integer.toString(tselRemote2)); + + public SettingsFrame() { + setModalityType(ModalityType.APPLICATION_MODAL); + + final GridBagLayout layout = new GridBagLayout(); + setLayout(layout); + + this.setSize(200, 120); + setLocationRelativeTo(null); + + JLabel label = new JLabel("TSelLocal: "); + GridBagConstraints constraint = new GridBagConstraints(); + constraint.gridwidth = 1; + constraint.gridheight = 1; + constraint.gridx = 0; + constraint.gridy = 0; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.WEST; + layout.setConstraints(label, constraint); + add(label); + + constraint = new GridBagConstraints(); + constraint.fill = GridBagConstraints.HORIZONTAL; + constraint.gridwidth = 1; + constraint.gridheight = 1; + constraint.gridx = 1; + constraint.gridy = 0; + constraint.weightx = 1; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.WEST; + layout.setConstraints(tselLocalField1, constraint); + add(tselLocalField1); + + constraint = new GridBagConstraints(); + constraint.fill = GridBagConstraints.HORIZONTAL; + constraint.gridwidth = 1; + constraint.gridheight = 1; + constraint.gridx = 2; + constraint.gridy = 0; + constraint.weightx = 1; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.WEST; + layout.setConstraints(tselLocalField2, constraint); + add(tselLocalField2); + + label = new JLabel("TSelRemote: "); + constraint = new GridBagConstraints(); + constraint.gridwidth = 1; + constraint.gridheight = 1; + constraint.gridx = 0; + constraint.gridy = 1; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.WEST; + layout.setConstraints(label, constraint); + add(label); + + constraint = new GridBagConstraints(); + constraint.fill = GridBagConstraints.HORIZONTAL; + constraint.gridwidth = 1; + constraint.gridheight = 1; + constraint.gridx = 1; + constraint.gridy = 1; + constraint.weightx = 1; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.WEST; + layout.setConstraints(tselRemoteField1, constraint); + add(tselRemoteField1); + + constraint = new GridBagConstraints(); + constraint.fill = GridBagConstraints.HORIZONTAL; + constraint.gridwidth = 1; + constraint.gridheight = 1; + constraint.gridx = 2; + constraint.gridy = 1; + constraint.weightx = 1; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.WEST; + layout.setConstraints(tselRemoteField2, constraint); + add(tselRemoteField2); + + JButton button = new JButton("Cancel"); + button.setActionCommand("Cancel"); + button.addActionListener(this); + constraint.gridwidth = 1; + constraint.gridheight = 1; + constraint.gridx = 0; + constraint.gridy = 2; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.SOUTHWEST; + layout.setConstraints(button, constraint); + add(button); + + button = new JButton("OK"); + button.setActionCommand("Okay"); + button.addActionListener(this); + constraint.gridwidth = 2; + constraint.gridheight = 1; + constraint.gridx = 1; + constraint.gridy = 2; + constraint.insets = new Insets(5, 5, 5, 5); + constraint.anchor = GridBagConstraints.SOUTHWEST; + layout.setConstraints(button, constraint); + add(button); + } + + @Override + public void actionPerformed(ActionEvent e) { + if ("cancel".equalsIgnoreCase(e.getActionCommand())) { + tselLocalField1.setText(Integer.toString(tselLocal1 & 0xFF)); + tselLocalField2.setText(Integer.toString(tselLocal2 & 0xFF)); + tselRemoteField1.setText(Integer.toString(tselRemote1 & 0xFF)); + tselRemoteField2.setText(Integer.toString(tselRemote2 & 0xFF)); + setVisible(false); + } else if ("okay".equalsIgnoreCase(e.getActionCommand())) { + tselLocal1 = parseTextField(tselLocalField1, tselLocal1); + tselLocal2 = parseTextField(tselLocalField2, tselLocal2); + tselRemote1 = parseTextField(tselRemoteField1, tselRemote1); + tselRemote2 = parseTextField(tselRemoteField2, tselRemote2); + setVisible(false); + } + } + + public byte[] getTselLocal() { + return new byte[] {(byte) tselLocal1, (byte) tselLocal2}; + } + + public void setTselLocal(byte[] tsel) { + if (tsel.length != 2) { + throw new IllegalArgumentException("TSel must consist of 2 bytes"); + } + tselLocal1 = tsel[0]; + tselLocal2 = tsel[1]; + + tselLocalField1.setText(Integer.toString(tselLocal1 & 0xFF)); + tselLocalField2.setText(Integer.toString(tselLocal2 & 0xFF)); + } + + public byte[] getTselRemote() { + return new byte[] {(byte) tselRemote1, (byte) tselRemote2}; + } + + public void setTselRemote(byte[] tsel) { + if (tsel.length != 2) { + throw new IllegalArgumentException("TSel must consist of 2 bytes"); + } + tselRemote1 = tsel[0]; + tselRemote2 = tsel[1]; + + tselRemoteField1.setText(Integer.toString(tselRemote1 & 0xFF)); + tselRemoteField2.setText(Integer.toString(tselRemote2 & 0xFF)); + } + + private int parseTextField(JTextField field, int oldValue) { + int value = oldValue; + try { + int newValue = Integer.parseInt(field.getText()); + if (newValue >= 0 && newValue <= 255) { + value = newValue; + } + } catch (NumberFormatException e) { + return oldValue; + } + return value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/BooleanDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/BooleanDataBind.java new file mode 100644 index 0000000..b08b920 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/BooleanDataBind.java @@ -0,0 +1,47 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaBoolean; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import javax.swing.JCheckBox; +import javax.swing.JComponent; + +public class BooleanDataBind extends BasicDataBind { + + private JCheckBox checkbox; + + public BooleanDataBind(BdaBoolean data) { + super(data, BdaType.BOOLEAN); + } + + @Override + protected JComponent init() { + checkbox = new JCheckBox(); + checkbox.setBorder(null); + checkbox.setSelected(data.getValue()); + return checkbox; + } + + @Override + protected void resetImpl() { + checkbox.setSelected(data.getValue()); + } + + @Override + protected void writeImpl() { + data.setValue(checkbox.isSelected()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/CheckDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/CheckDataBind.java new file mode 100644 index 0000000..687b6af --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/CheckDataBind.java @@ -0,0 +1,55 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaCheck; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import java.awt.Component; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +public class CheckDataBind extends BasicDataBind { + + private final JCheckBox interlock = new JCheckBox("Interlock"); + private final JCheckBox synchron = new JCheckBox("Synchron"); + + public CheckDataBind(BdaCheck data) { + super(data, BdaType.CHECK); + } + + @Override + protected JComponent init() { + interlock.setAlignmentX(Component.LEFT_ALIGNMENT); + JPanel valuePanel = new JPanel(); + valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS)); + valuePanel.add(interlock); + valuePanel.add(synchron); + return valuePanel; + } + + @Override + protected void resetImpl() { + interlock.setSelected(data.getInterlockCheck()); + synchron.setSelected(data.getSynchrocheck()); + } + + @Override + protected void writeImpl() { + data.setInterlockCheck(interlock.isSelected()); + data.setSynchrocheck(synchron.isSelected()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/DoubleBitPosDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/DoubleBitPosDataBind.java new file mode 100644 index 0000000..16da758 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/DoubleBitPosDataBind.java @@ -0,0 +1,46 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaDoubleBitPos; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import javax.swing.JComboBox; +import javax.swing.JComponent; + +public class DoubleBitPosDataBind extends BasicDataBind { + + @SuppressWarnings("unchecked") + private final JComboBox valueField = new JComboBox(BdaDoubleBitPos.DoubleBitPos.values()); + + public DoubleBitPosDataBind(BdaDoubleBitPos data) { + super(data, BdaType.DOUBLE_BIT_POS); + } + + @Override + protected JComponent init() { + return valueField; + } + + @Override + protected void resetImpl() { + valueField.setSelectedItem(data.getDoubleBitPos()); + } + + @Override + protected void writeImpl() { + // TODO uncomment once data.setTapCommand() is implemented + // data.setTapCommand(valueField.getSelectedItem()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/EntryTimeDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/EntryTimeDataBind.java new file mode 100644 index 0000000..40efefc --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/EntryTimeDataBind.java @@ -0,0 +1,53 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaEntryTime; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import javax.swing.JComponent; +import javax.swing.JLabel; + +public class EntryTimeDataBind extends BasicDataBind { + + public EntryTimeDataBind(BdaEntryTime data) { + super(data, BdaType.ENTRY_TIME); + } + + @Override + protected JComponent init() { + byte[] value = data.getValue(); + StringBuilder sb; + + sb = new StringBuilder("EntryTime ["); + for (int i = 0; i < value.length; i++) { + sb.append(Integer.toHexString(value[i] & 0xff)); + if (i != value.length - 1) { + sb.append(", "); + } + } + sb.append("]"); + return new JLabel(sb.toString()); + } + + @Override + protected void resetImpl() { + // ignore for now + } + + @Override + protected void writeImpl() { + // ignore for now + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Float32DataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Float32DataBind.java new file mode 100644 index 0000000..cc1785c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Float32DataBind.java @@ -0,0 +1,49 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaFloat32; +import com.beanit.iec61850bean.BdaType; + +public class Float32DataBind extends TextFieldDataBind { + + private static final FloatFilter FILTER = new FloatFilter(); + + public Float32DataBind(BdaFloat32 data) { + super(data, BdaType.FLOAT32, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(data.getFloat().toString()); + } + + @Override + protected void writeImpl() { + float newFloat = Float.parseFloat(inputField.getText()); + data.setFloat(newFloat); + } + + private static class FloatFilter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + Float.parseFloat(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Float64DataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Float64DataBind.java new file mode 100644 index 0000000..da50178 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Float64DataBind.java @@ -0,0 +1,49 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaFloat64; +import com.beanit.iec61850bean.BdaType; + +public class Float64DataBind extends TextFieldDataBind { + + private static final DoubleFilter FILTER = new DoubleFilter(); + + public Float64DataBind(BdaFloat64 data) { + super(data, BdaType.FLOAT64, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(data.getDouble().toString()); + } + + @Override + protected void writeImpl() { + double newDouble = Double.parseDouble(inputField.getText()); + data.setDouble(newDouble); + } + + private static class DoubleFilter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + Double.parseDouble(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int16DataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int16DataBind.java new file mode 100644 index 0000000..eb9250e --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int16DataBind.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaInt16; +import com.beanit.iec61850bean.BdaType; + +public class Int16DataBind extends TextFieldDataBind { + + private static final Int16Filter FILTER = new Int16Filter(); + + public Int16DataBind(BdaInt16 data) { + super(data, BdaType.INT16, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(Short.toString(data.getValue())); + } + + @Override + protected void writeImpl() { + data.setValue(Short.parseShort(inputField.getText())); + } + + private static class Int16Filter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + Short.parseShort(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int16UDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int16UDataBind.java new file mode 100644 index 0000000..7196aff --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int16UDataBind.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaInt16U; +import com.beanit.iec61850bean.BdaType; + +public class Int16UDataBind extends TextFieldDataBind { + + private static final UInt16Filter FILTER = new UInt16Filter(); + + public Int16UDataBind(BdaInt16U data) { + super(data, BdaType.INT16U, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(Integer.toString(data.getValue())); + } + + @Override + protected void writeImpl() { + data.setValue(Integer.parseInt(inputField.getText())); + } + + private static class UInt16Filter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + int value = Integer.parseInt(text); + return value >= 0 && value <= 0xFFFF; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int32DataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int32DataBind.java new file mode 100644 index 0000000..2075ab5 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int32DataBind.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaInt32; +import com.beanit.iec61850bean.BdaType; + +public class Int32DataBind extends TextFieldDataBind { + + private static final Int32Filter FILTER = new Int32Filter(); + + public Int32DataBind(BdaInt32 data) { + super(data, BdaType.INT32, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(Integer.toString(data.getValue())); + } + + @Override + protected void writeImpl() { + data.setValue(Integer.parseInt(inputField.getText())); + } + + private static class Int32Filter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + Integer.parseInt(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int32UDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int32UDataBind.java new file mode 100644 index 0000000..1409848 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int32UDataBind.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaInt32U; +import com.beanit.iec61850bean.BdaType; + +public class Int32UDataBind extends TextFieldDataBind { + + private static final UInt32Filter FILTER = new UInt32Filter(); + + public Int32UDataBind(BdaInt32U data) { + super(data, BdaType.INT32U, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(Long.toString(data.getValue())); + } + + @Override + protected void writeImpl() { + data.setValue(Long.parseLong(inputField.getText())); + } + + private static class UInt32Filter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + long value = Long.parseLong(text); + return value >= 0 && value <= 0xFFFFFFFFL; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int64DataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int64DataBind.java new file mode 100644 index 0000000..a7b16cb --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int64DataBind.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaInt64; +import com.beanit.iec61850bean.BdaType; + +public class Int64DataBind extends TextFieldDataBind { + + private static final Int64Filter FILTER = new Int64Filter(); + + public Int64DataBind(BdaInt64 data) { + super(data, BdaType.INT64, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(Long.toString(data.getValue())); + } + + @Override + protected void writeImpl() { + data.setValue(Long.parseLong(inputField.getText())); + } + + private static class Int64Filter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + Long.parseLong(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int8DataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int8DataBind.java new file mode 100644 index 0000000..6acf98e --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int8DataBind.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaInt8; +import com.beanit.iec61850bean.BdaType; + +public class Int8DataBind extends TextFieldDataBind { + + private static final Int8Filter FILTER = new Int8Filter(); + + public Int8DataBind(BdaInt8 data) { + super(data, BdaType.INT8, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(Byte.toString(data.getValue())); + } + + @Override + protected void writeImpl() { + data.setValue(Byte.parseByte(inputField.getText())); + } + + private static class Int8Filter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + Byte.parseByte(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int8UDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int8UDataBind.java new file mode 100644 index 0000000..0205554 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/Int8UDataBind.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaInt8U; +import com.beanit.iec61850bean.BdaType; + +public class Int8UDataBind extends TextFieldDataBind { + + private static final UInt8Filter FILTER = new UInt8Filter(); + + public Int8UDataBind(BdaInt8U data) { + super(data, BdaType.INT8U, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(Short.toString(data.getValue())); + } + + @Override + protected void writeImpl() { + data.setValue(Short.parseShort(inputField.getText())); + } + + private static class UInt8Filter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + short value = Short.parseShort(text); + return value >= 0 && value <= 0xFF; + } catch (NumberFormatException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/OctetStringDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/OctetStringDataBind.java new file mode 100644 index 0000000..a682f11 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/OctetStringDataBind.java @@ -0,0 +1,53 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaOctetString; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import javax.swing.JComponent; +import javax.swing.JLabel; + +public class OctetStringDataBind extends BasicDataBind { + + public OctetStringDataBind(BdaOctetString data) { + super(data, BdaType.OCTET_STRING); + } + + @Override + protected JComponent init() { + byte[] value = data.getValue(); + StringBuilder sb; + + sb = new StringBuilder("OctetString ["); + for (int i = 0; i < value.length; i++) { + sb.append(Integer.toHexString(value[i] & 0xff)); + if (i != value.length - 1) { + sb.append(", "); + } + } + sb.append("]"); + return new JLabel(sb.toString()); + } + + @Override + protected void resetImpl() { + // ignore for now + } + + @Override + protected void writeImpl() { + // ignore for now + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/OptfldsDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/OptfldsDataBind.java new file mode 100644 index 0000000..73e60c2 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/OptfldsDataBind.java @@ -0,0 +1,83 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaOptFlds; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import java.awt.Component; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +public class OptfldsDataBind extends BasicDataBind { + + private final JCheckBox bufferOverflow = new JCheckBox("BufferOverflow"); + private final JCheckBox configRevision = new JCheckBox("ConfigRevision"); + private final JCheckBox dataReference = new JCheckBox("DataReference"); + private final JCheckBox dataSetName = new JCheckBox("DataSetName"); + private final JCheckBox entryId = new JCheckBox("EntryId"); + private final JCheckBox reasonForInclusion = new JCheckBox("ReasonForInclusion"); + private final JCheckBox reportTimestamp = new JCheckBox("ReportTimestamp"); + private final JCheckBox segmentation = new JCheckBox("Segmentation"); + private final JCheckBox sequenceNumber = new JCheckBox("SequenceNumber"); + + public OptfldsDataBind(BdaOptFlds data) { + super(data, BdaType.OPTFLDS); + } + + @Override + protected JComponent init() { + bufferOverflow.setAlignmentX(Component.LEFT_ALIGNMENT); + JPanel valuePanel = new JPanel(); + valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS)); + valuePanel.add(bufferOverflow); + valuePanel.add(configRevision); + valuePanel.add(dataReference); + valuePanel.add(dataSetName); + valuePanel.add(entryId); + valuePanel.add(reasonForInclusion); + valuePanel.add(reportTimestamp); + valuePanel.add(segmentation); + valuePanel.add(sequenceNumber); + return valuePanel; + } + + @Override + protected void resetImpl() { + bufferOverflow.setSelected(data.isBufferOverflow()); + configRevision.setSelected(data.isConfigRevision()); + dataReference.setSelected(data.isDataReference()); + dataSetName.setSelected(data.isDataSetName()); + entryId.setSelected(data.isEntryId()); + reasonForInclusion.setSelected(data.isReasonForInclusion()); + reportTimestamp.setSelected(data.isReportTimestamp()); + segmentation.setSelected(data.isSegmentation()); + sequenceNumber.setSelected(data.isSequenceNumber()); + } + + @Override + protected void writeImpl() { + data.setBufferOverflow(bufferOverflow.isSelected()); + data.setConfigRevision(configRevision.isSelected()); + data.setDataReference(dataReference.isSelected()); + data.setDataSetName(dataSetName.isSelected()); + data.setEntryId(entryId.isSelected()); + data.setReasonForInclusion(reasonForInclusion.isSelected()); + data.setReportTimestamp(reportTimestamp.isSelected()); + data.setSegmentation(segmentation.isSelected()); + data.setSequenceNumber(sequenceNumber.isSelected()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/QualityDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/QualityDataBind.java new file mode 100644 index 0000000..5c126d6 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/QualityDataBind.java @@ -0,0 +1,100 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaQuality; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import java.awt.Component; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +public class QualityDataBind extends BasicDataBind { + + @SuppressWarnings("unchecked") + private final JComboBox validity = new JComboBox(BdaQuality.Validity.values()); + + private final JCheckBox badReference = new JCheckBox("BadReference"); + private final JCheckBox failure = new JCheckBox("Failure"); + private final JCheckBox inaccurate = new JCheckBox("Inaccurate"); + private final JCheckBox inconsistent = new JCheckBox("Inconsistent"); + private final JCheckBox oldData = new JCheckBox("OldData"); + private final JCheckBox operatorBlocked = new JCheckBox("OperatorBlocked"); + private final JCheckBox oscillatory = new JCheckBox("Oscillatory"); + private final JCheckBox outOfRange = new JCheckBox("OutOfRange"); + private final JCheckBox overflow = new JCheckBox("Overflow"); + private final JCheckBox substituded = new JCheckBox("Substituded"); + private final JCheckBox test = new JCheckBox("Test"); + + public QualityDataBind(BdaQuality data) { + super(data, BdaType.QUALITY); + } + + @Override + protected JComponent init() { + validity.setAlignmentX(Component.LEFT_ALIGNMENT); + JPanel valuePanel = new JPanel(); + valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS)); + valuePanel.setAlignmentX(Component.LEFT_ALIGNMENT); + valuePanel.add(validity); + valuePanel.add(badReference); + valuePanel.add(failure); + valuePanel.add(inaccurate); + valuePanel.add(inconsistent); + valuePanel.add(oldData); + valuePanel.add(operatorBlocked); + valuePanel.add(oscillatory); + valuePanel.add(outOfRange); + valuePanel.add(overflow); + valuePanel.add(substituded); + valuePanel.add(test); + return valuePanel; + } + + @Override + protected void resetImpl() { + validity.setSelectedItem(data.getValidity()); + badReference.setSelected(data.isBadReference()); + failure.setSelected(data.isFailure()); + inaccurate.setSelected(data.isInaccurate()); + inconsistent.setSelected(data.isInconsistent()); + oldData.setSelected(data.isOldData()); + operatorBlocked.setSelected(data.isOperatorBlocked()); + oscillatory.setSelected(data.isOscillatory()); + outOfRange.setSelected(data.isOutOfRange()); + overflow.setSelected(data.isOverflow()); + substituded.setSelected(data.isSubstituted()); + test.setSelected(data.isTest()); + } + + @Override + protected void writeImpl() { + // TODO uncomment once mutators are implemented + // data.setValidity(validity.getSelectedItem()); + // data.setBadReference(badReference.isSelected()); + // data.setFailure(failure.isSelected()); + // data.setInaccurate(inaccurate.isSelected()); + // data.setInconsistent(inconsistent.isSelected()); + // data.setOldData(oldData.isSelected()); + // data.setOperatorBlocked(operatorBlocked.isSelected()); + // data.setOlscillatory(oscillatory.isSelected()); + // data.setOutOfRange(outOfRange.isSelected()); + // data.setOverflow(overflow.isSelected()); + // data.setSubstituded(substituded.isSelected()); + // data.setTest(test.isSelected()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/ReasonForInclusionDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/ReasonForInclusionDataBind.java new file mode 100644 index 0000000..9085073 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/ReasonForInclusionDataBind.java @@ -0,0 +1,71 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaReasonForInclusion; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import java.awt.Component; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +public class ReasonForInclusionDataBind extends BasicDataBind { + + private final JCheckBox applicationTrigger = new JCheckBox("ApplicationTrigger"); + private final JCheckBox dataChange = new JCheckBox("DataChange"); + private final JCheckBox dataUpdate = new JCheckBox("DataUpdate"); + private final JCheckBox generalInterrogation = new JCheckBox("GeneralInterrogation"); + private final JCheckBox integrity = new JCheckBox("Integrity"); + private final JCheckBox qualitychanged = new JCheckBox("QualityChanged"); + + public ReasonForInclusionDataBind(BdaReasonForInclusion data) { + super(data, BdaType.REASON_FOR_INCLUSION); + } + + @Override + protected JComponent init() { + applicationTrigger.setAlignmentX(Component.LEFT_ALIGNMENT); + JPanel valuePanel = new JPanel(); + valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS)); + valuePanel.add(applicationTrigger); + valuePanel.add(dataChange); + valuePanel.add(dataUpdate); + valuePanel.add(generalInterrogation); + valuePanel.add(integrity); + valuePanel.add(qualitychanged); + return valuePanel; + } + + @Override + protected void resetImpl() { + applicationTrigger.setSelected(data.isApplicationTrigger()); + dataChange.setSelected(data.isDataChange()); + dataUpdate.setSelected(data.isDataUpdate()); + generalInterrogation.setSelected(data.isGeneralInterrogation()); + integrity.setSelected(data.isIntegrity()); + qualitychanged.setSelected(data.isQualityChange()); + } + + @Override + protected void writeImpl() { + data.setApplicationTrigger(applicationTrigger.isSelected()); + data.setDataChange(dataChange.isSelected()); + data.setDataUpdate(dataUpdate.isSelected()); + data.setGeneralInterrogation(generalInterrogation.isSelected()); + data.setIntegrity(integrity.isSelected()); + data.setQualityChange(qualitychanged.isSelected()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/TapCommandDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TapCommandDataBind.java new file mode 100644 index 0000000..1270a0d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TapCommandDataBind.java @@ -0,0 +1,46 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaTapCommand; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import javax.swing.JComboBox; +import javax.swing.JComponent; + +public class TapCommandDataBind extends BasicDataBind { + + @SuppressWarnings("unchecked") + private final JComboBox tapCommand = new JComboBox(BdaTapCommand.TapCommand.values()); + + public TapCommandDataBind(BdaTapCommand data) { + super(data, BdaType.TAP_COMMAND); + } + + @Override + protected JComponent init() { + return tapCommand; + } + + @Override + protected void resetImpl() { + tapCommand.setSelectedItem(data.getTapCommand()); + } + + @Override + protected void writeImpl() { + // TODO uncomment once data.setTapCommand is implemented + // data.setTapCommand(tapCommand.getSelectedItem()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/TextFieldDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TextFieldDataBind.java new file mode 100644 index 0000000..4b4e7a3 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TextFieldDataBind.java @@ -0,0 +1,90 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BasicDataAttribute; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import javax.swing.JComponent; +import javax.swing.JTextField; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.DocumentFilter; +import javax.swing.text.PlainDocument; + +public abstract class TextFieldDataBind extends BasicDataBind { + + private final DocumentFilter filter; + protected JTextField inputField; + + TextFieldDataBind(E data, BdaType type, AbstractFilter filter) { + super(data, type); + this.filter = filter; + } + + @Override + protected JComponent init() { + inputField = new JTextField(); + PlainDocument doc = (PlainDocument) inputField.getDocument(); + doc.setDocumentFilter(filter); + resetImpl(); + return inputField; + } + + protected abstract static class AbstractFilter extends DocumentFilter { + @Override + public final void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) + throws BadLocationException { + + Document doc = fb.getDocument(); + StringBuilder sb = new StringBuilder(); + sb.append(doc.getText(0, doc.getLength())); + sb.insert(offset, string); + + if (test(sb.toString())) { + super.insertString(fb, offset, string, attr); + } + } + + @Override + public final void replace( + FilterBypass fb, int offset, int length, String text, AttributeSet attrs) + throws BadLocationException { + + Document doc = fb.getDocument(); + StringBuilder sb = new StringBuilder(); + sb.append(doc.getText(0, doc.getLength())); + sb.replace(offset, offset + length, text); + + if (test(sb.toString())) { + super.replace(fb, offset, length, text, attrs); + } + } + + @Override + public final void remove(FilterBypass fb, int offset, int length) throws BadLocationException { + Document doc = fb.getDocument(); + StringBuilder sb = new StringBuilder(); + sb.append(doc.getText(0, doc.getLength())); + sb.delete(offset, offset + length); + + if (test(sb.toString())) { + super.remove(fb, offset, length); + } + } + + protected abstract boolean test(String text); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/TimeStampDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TimeStampDataBind.java new file mode 100644 index 0000000..d193463 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TimeStampDataBind.java @@ -0,0 +1,50 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaTimestamp; +import com.beanit.iec61850bean.BdaType; +import java.time.Instant; +import java.time.format.DateTimeParseException; + +public class TimeStampDataBind extends TextFieldDataBind { + + private static final TimestampFilter FILTER = new TimestampFilter(); + + public TimeStampDataBind(BdaTimestamp data) { + super(data, BdaType.TIMESTAMP, FILTER); + } + + @Override + protected void resetImpl() { + inputField.setText(data.getInstant().toString()); + } + + @Override + protected void writeImpl() { + data.setInstant(Instant.parse(inputField.getText())); + } + + private static class TimestampFilter extends AbstractFilter { + @Override + protected boolean test(String text) { + try { + Instant.parse(text); + return true; + } catch (DateTimeParseException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/TriggerConditionDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TriggerConditionDataBind.java new file mode 100644 index 0000000..9ed6168 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/TriggerConditionDataBind.java @@ -0,0 +1,67 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaTriggerConditions; +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.clientgui.BasicDataBind; +import java.awt.Component; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JPanel; + +public class TriggerConditionDataBind extends BasicDataBind { + + private final JCheckBox dataChange = new JCheckBox("DataChange"); + private final JCheckBox dataUpdate = new JCheckBox("DataUpdate"); + private final JCheckBox generalInterrogation = new JCheckBox("GeneralInterrogation"); + private final JCheckBox integrity = new JCheckBox("Integrity"); + private final JCheckBox qualityChange = new JCheckBox("QualityChange"); + + public TriggerConditionDataBind(BdaTriggerConditions data) { + super(data, BdaType.TRIGGER_CONDITIONS); + } + + @Override + protected JComponent init() { + dataChange.setAlignmentX(Component.LEFT_ALIGNMENT); + JPanel valuePanel = new JPanel(); + valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS)); + valuePanel.add(dataChange); + valuePanel.add(dataUpdate); + valuePanel.add(generalInterrogation); + valuePanel.add(integrity); + valuePanel.add(qualityChange); + return valuePanel; + } + + @Override + protected void resetImpl() { + dataChange.setSelected(data.isDataChange()); + dataUpdate.setSelected(data.isDataUpdate()); + generalInterrogation.setSelected(data.isGeneralInterrogation()); + integrity.setSelected(data.isIntegrity()); + qualityChange.setSelected(data.isQualityChange()); + } + + @Override + protected void writeImpl() { + data.setDataChange(dataChange.isSelected()); + data.setDataUpdate(dataUpdate.isSelected()); + data.setGeneralInterrogation(generalInterrogation.isSelected()); + data.setIntegrity(integrity.isSelected()); + data.setQualityChange(qualityChange.isSelected()); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/UnicodeStringDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/UnicodeStringDataBind.java new file mode 100644 index 0000000..85d51b9 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/UnicodeStringDataBind.java @@ -0,0 +1,60 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.BdaUnicodeString; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; + +public class UnicodeStringDataBind extends TextFieldDataBind { + + private static final Charset UTF8 = StandardCharsets.UTF_8; + + public UnicodeStringDataBind(BdaUnicodeString data) { + super(data, BdaType.UNICODE_STRING, new Utf8Filter(data.getMaxLength())); + } + + @Override + protected void resetImpl() { + inputField.setText(new String(data.getValue(), UTF8)); + } + + @Override + protected void writeImpl() { + data.setValue(UTF8.encode(inputField.getText()).array()); + } + + private static class Utf8Filter extends AbstractFilter { + private final CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); + private final int maxBytes; + + public Utf8Filter(int maxBytes) { + this.maxBytes = maxBytes; + } + + @Override + protected boolean test(String text) { + try { + byte[] codedString = encoder.encode(CharBuffer.wrap(text)).array(); + return codedString.length <= maxBytes; + } catch (CharacterCodingException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/databind/VisibleStringDataBind.java b/src/main/java/com/beanit/iec61850bean/clientgui/databind/VisibleStringDataBind.java new file mode 100644 index 0000000..5acba4e --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/databind/VisibleStringDataBind.java @@ -0,0 +1,60 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.databind; + +import com.beanit.iec61850bean.BdaType; +import com.beanit.iec61850bean.BdaVisibleString; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; + +public class VisibleStringDataBind extends TextFieldDataBind { + + private static final Charset ASCII = StandardCharsets.US_ASCII; + + public VisibleStringDataBind(BdaVisibleString data) { + super(data, BdaType.VISIBLE_STRING, new AsciiFilter(data.getMaxLength())); + } + + @Override + protected void resetImpl() { + inputField.setText(new String(data.getValue(), ASCII)); + } + + @Override + protected void writeImpl() { + data.setValue(ASCII.encode(inputField.getText()).array()); + } + + private static class AsciiFilter extends TextFieldDataBind.AbstractFilter { + private final CharsetEncoder encoder = StandardCharsets.US_ASCII.newEncoder(); + private final int maxBytes; + + public AsciiFilter(int maxBytes) { + this.maxBytes = maxBytes; + } + + @Override + protected boolean test(String text) { + try { + byte[] codedString = encoder.encode(CharBuffer.wrap(text)).array(); + return codedString.length <= maxBytes; + } catch (CharacterCodingException e) { + return false; + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/clientgui/util/Counter.java b/src/main/java/com/beanit/iec61850bean/clientgui/util/Counter.java new file mode 100644 index 0000000..c29f48f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/clientgui/util/Counter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.clientgui.util; + +public class Counter { + private int value; + + public Counter(int value) { + this.value = value; + } + + public Counter() { + this(0); + } + + public void increment() { + value++; + } + + public int getValue() { + return value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/BerBoolean.java b/src/main/java/com/beanit/iec61850bean/internal/BerBoolean.java new file mode 100644 index 0000000..635282d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/BerBoolean.java @@ -0,0 +1,117 @@ +/* + * Copyright 2012 The jASN1 Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class BerBoolean implements Serializable, BerType { + + public static final BerTag tag = + new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.PRIMITIVE, BerTag.BOOLEAN_TAG); + private static final long serialVersionUID = 1L; + public boolean value; + private byte[] code = null; + + public BerBoolean() {} + + public BerBoolean(byte[] code) { + this.code = code; + } + + public BerBoolean(boolean value) { + this.value = value; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 1; + + if (value) { + reverseOS.write(0x01); + } else { + reverseOS.write(0); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + + int codeLength = 0; + + if (withTag) { + codeLength += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + codeLength += length.decode(is); + + if (length.val != 1) { + throw new IOException("Decoded length of BerBoolean is not correct"); + } + + int nextByte = is.read(); + if (nextByte == -1) { + throw new EOFException("Unexpected end of input stream."); + } + + codeLength++; + value = nextByte != 0; + + return codeLength; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream os = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(os, false); + code = os.getArray(); + } + + @Override + public String toString() { + return "" + value; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/HexString.java b/src/main/java/com/beanit/iec61850bean/internal/HexString.java new file mode 100644 index 0000000..0636370 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/HexString.java @@ -0,0 +1,152 @@ +/* + * Copyright 2019 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal; + +import java.nio.ByteBuffer; +import java.util.Objects; + +public class HexString { + + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + /** Don't let anyone instantiate this class. */ + private HexString() {} + + /** + * Returns the byte as a hex string. If b is less than 16 the hex string returned contains a + * leading zero. + * + * @param b the byte to be converted + * @return the hex string. + */ + public static String fromByte(byte b) { + return fromBytes(new byte[] {b}); + } + + public static String fromByte(int b) { + return fromBytes(new byte[] {(byte) b}); + } + + /** + * Returns the integer value as hex string filled with leading zeros. + * + * @param i the integer value to be converted + * @return the hex string + */ + public static String fromInt(int i) { + byte[] bytes = new byte[] {(byte) (i >> 24), (byte) (i >> 16), (byte) (i >> 8), (byte) i}; + return fromBytes(bytes); + } + + /** + * Returns the long value as hex string filled with leading zeros. + * + * @param l the long value to be converted + * @return the hex string + */ + public static String fromLong(long l) { + byte[] bytes = + new byte[] { + (byte) (l >> 56), + (byte) (l >> 48), + (byte) (l >> 40), + (byte) (l >> 32), + (byte) (l >> 24), + (byte) (l >> 16), + (byte) (l >> 8), + (byte) l + }; + return fromBytes(bytes); + } + + public static String fromBytes(byte[] bytes) { + return fromBytes(bytes, 0, bytes.length); + } + + public static String fromBytesFormatted(byte[] bytes) { + return fromBytesFormatted(bytes, 0, bytes.length); + } + + public static String fromBytes(byte[] bytes, int offset, int length) { + char[] hexChars = new char[length * 2]; + for (int j = 0; j < length; j++) { + int v = bytes[j + offset] & 0xff; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0f]; + } + return new String(hexChars); + } + + public static String fromBytes(ByteBuffer buffer) { + return fromBytes(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.limit()); + } + + public static String fromBytesFormatted(byte[] bytes, int offset, int length) { + StringBuilder builder = new StringBuilder(); + + int l = 1; + for (int i = offset; i < (offset + length); i++) { + if ((l != 1) && ((l - 1) % 8 == 0)) { + builder.append(' '); + } + if ((l != 1) && ((l - 1) % 16 == 0)) { + builder.append('\n'); + } + l++; + appendFromByte(bytes[i], builder); + if (i != offset + length - 1) { + builder.append(' '); + } + } + return builder.toString(); + } + + /** + * Converts the given hex string to a byte array. + * + * @param hexString the hex string + * @return the bytes + * @throws NumberFormatException if the string is not a valid hex string + */ + public static byte[] toBytes(String hexString) { + + Objects.requireNonNull(hexString); + if ((hexString.length() == 0) || ((hexString.length() % 2) != 0)) { + throw new NumberFormatException("argument is not a valid hex string"); + } + + int length = hexString.length(); + + byte[] data = new byte[length / 2]; + for (int i = 0; i < length; i += 2) { + int firstCharacter = Character.digit(hexString.charAt(i), 16); + int secondCharacter = Character.digit(hexString.charAt(i + 1), 16); + + if (firstCharacter == -1 || secondCharacter == -1) { + throw new NumberFormatException("argument is not a valid hex string"); + } + + data[i / 2] = (byte) ((firstCharacter << 4) + secondCharacter); + } + return data; + } + + public static void appendFromByte(byte b, StringBuilder builder) { + builder.append(fromByte(b)); + } + + public static void appendFromBytes(StringBuilder builder, byte[] bytes, int offset, int length) { + builder.append(fromBytes(bytes, offset, length)); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/NamedThreadFactory.java b/src/main/java/com/beanit/iec61850bean/internal/NamedThreadFactory.java new file mode 100644 index 0000000..2d663ce --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/NamedThreadFactory.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +public class NamedThreadFactory implements ThreadFactory { + + private final AtomicInteger threadCounter = new AtomicInteger(1); + private final String namePrefix; + + /** + * Creates a thread factory with the given pool name as a name prefix. Threads created will have + * the name {@code -thread-}. A common pool name is of format {@code + * -}. + * + * @param poolName the thread pool name + */ + public NamedThreadFactory(String poolName) { + this.namePrefix = poolName + "-thread-"; + } + + @Override + public Thread newThread(Runnable r) { + Thread thread = new Thread(r); + thread.setName(namePrefix + threadCounter.getAndIncrement()); + return thread; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/Action.java b/src/main/java/com/beanit/iec61850bean/internal/cli/Action.java new file mode 100644 index 0000000..f040472 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/Action.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public class Action { + + private final String key; + private final String description; + + public Action(String key, String description) { + this.key = key; + this.description = description; + } + + public String getKey() { + return key; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/ActionException.java b/src/main/java/com/beanit/iec61850bean/internal/cli/ActionException.java new file mode 100644 index 0000000..f6bb64c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/ActionException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public final class ActionException extends Exception { + + private static final long serialVersionUID = 4806947065917148946L; + + public ActionException() { + super(); + } + + public ActionException(String s) { + super(s); + } + + public ActionException(Throwable cause) { + super(cause); + } + + public ActionException(String s, Throwable cause) { + super(s, cause); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/ActionListener.java b/src/main/java/com/beanit/iec61850bean/internal/cli/ActionListener.java new file mode 100644 index 0000000..cbacc6e --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/ActionListener.java @@ -0,0 +1,21 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public interface ActionListener { + + void actionCalled(String actionKey) throws ActionException; + + void quit(); +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/ActionProcessor.java b/src/main/java/com/beanit/iec61850bean/internal/cli/ActionProcessor.java new file mode 100644 index 0000000..a20b9ca --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/ActionProcessor.java @@ -0,0 +1,131 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +import static java.lang.System.exit; +import static java.lang.System.out; +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.LinkedHashMap; +import java.util.Map; + +public class ActionProcessor { + + private static final String SEPARATOR_LINE = + "------------------------------------------------------"; + + private final BufferedReader reader; + private final ActionListener actionListener; + private final Map actionMap = new LinkedHashMap<>(); + private final Action helpAction = new Action("h", "print help message"); + private final Action quitAction = new Action("q", "quit the application"); + private volatile boolean closed = false; + + public ActionProcessor(ActionListener actionListener) { + reader = new BufferedReader(new InputStreamReader(System.in, UTF_8)); + this.actionListener = actionListener; + } + + public void addAction(Action action) { + actionMap.put(action.getKey(), action); + } + + public BufferedReader getReader() { + return reader; + } + + public void start() { + + actionMap.put(helpAction.getKey(), helpAction); + actionMap.put(quitAction.getKey(), quitAction); + + printHelp(); + + try { + + String actionKey; + while (true) { + + if (closed) { + exit(1); + return; + } + + System.out.println("\n** Enter action key: "); + + try { + actionKey = reader.readLine(); + } catch (IOException e) { + System.err.printf("%s. Application is being shut down.\n", e.getMessage()); + exit(2); + return; + } + + if (closed) { + exit(1); + return; + } + + if (actionMap.get(actionKey) == null) { + System.err.println("Illegal action key.\n"); + printHelp(); + continue; + } + + if (actionKey.equals(helpAction.getKey())) { + printHelp(); + continue; + } + + if (actionKey.equals(quitAction.getKey())) { + actionListener.quit(); + return; + } + + actionListener.actionCalled(actionKey); + } + + } catch (Exception e) { + e.printStackTrace(); + actionListener.quit(); + } finally { + close(); + } + } + + private void printHelp() { + final String message = " %s - %s\n"; + out.flush(); + out.println(); + out.println(SEPARATOR_LINE); + + for (Action action : actionMap.values()) { + out.printf(message, action.getKey(), action.getDescription()); + } + + out.println(SEPARATOR_LINE); + } + + public void close() { + closed = true; + try { + reader.close(); + } catch (IOException ignored) { + // if closing fails there is nothing meaningful that can be done + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/CliParameter.java b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParameter.java new file mode 100644 index 0000000..8170f73 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParameter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public abstract class CliParameter { + + final String name; + final String description; + final boolean optional; + boolean selected; + + CliParameter(CliParameterBuilder builder) { + name = builder.name; + description = builder.description; + optional = builder.optional; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public boolean isOptional() { + return optional; + } + + public boolean isSelected() { + return selected; + } + + abstract int parse(String[] args, int i) throws CliParseException; + + abstract int appendSynopsis(StringBuilder sb); + + abstract void appendDescription(StringBuilder sb); +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/CliParameterBuilder.java b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParameterBuilder.java new file mode 100644 index 0000000..6154857 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParameterBuilder.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +import java.util.List; + +public class CliParameterBuilder { + + final String name; + String description; + boolean optional = true; + + public CliParameterBuilder(String name) { + this.name = name; + } + + public CliParameterBuilder setDescription(String description) { + this.description = description; + return this; + } + + public CliParameterBuilder setMandatory() { + optional = false; + return this; + } + + public LongCliParameter buildLongParameter(String parameterName, long defaultValue) { + return new LongCliParameter(this, parameterName, defaultValue); + } + + public LongCliParameter buildLongParameter(String parameterName) { + return new LongCliParameter(this, parameterName); + } + + public IntCliParameter buildIntParameter(String parameterName, int defaultValue) { + return new IntCliParameter(this, parameterName, defaultValue); + } + + public IntCliParameter buildIntParameter(String parameterName) { + return new IntCliParameter(this, parameterName); + } + + public StringCliParameter buildStringParameter(String parameterName, String defaultValue) { + return new StringCliParameter(this, parameterName, defaultValue); + } + + public StringCliParameter buildStringParameter(String parameterName) { + return new StringCliParameter(this, parameterName); + } + + public StringListCliParameter buildStringListParameter(String parameterName) { + return new StringListCliParameter(this, parameterName); + } + + public StringListCliParameter buildStringListParameter( + String parameterName, List defaultValue) { + return new StringListCliParameter(this, parameterName, defaultValue); + } + + public FlagCliParameter buildFlagParameter() { + return new FlagCliParameter(this); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/CliParseException.java b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParseException.java new file mode 100644 index 0000000..27e5ae7 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParseException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public final class CliParseException extends Exception { + + private static final long serialVersionUID = -5162894897245715377L; + + public CliParseException() { + super(); + } + + public CliParseException(String s) { + super(s); + } + + public CliParseException(Throwable cause) { + super(cause); + } + + public CliParseException(String s, Throwable cause) { + super(s, cause); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/CliParser.java b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParser.java new file mode 100644 index 0000000..386c7b1 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/CliParser.java @@ -0,0 +1,146 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public class CliParser { + + private static final String HELP = "--help"; + private final String name; + private final String description; + private final List commandLineParameterGroups = new ArrayList<>(); + private String selectedGroup = ""; + + public CliParser(String name, String description) { + this.name = name; + this.description = description; + } + + public void addParameterGroup(String groupName, List parameters) { + commandLineParameterGroups.add(new ParameterGroup(groupName.toLowerCase(), parameters)); + } + + public void addParameters(List parameters) { + commandLineParameterGroups.clear(); + commandLineParameterGroups.add(new ParameterGroup("", parameters)); + } + + public String getSelectedGroup() { + return selectedGroup; + } + + public void parseArguments(String[] args) throws CliParseException { + + if (args.length > 0 && HELP.equals(args[0])) { + System.out.println(getUsageString()); + System.exit(0); + } + + List parameters = null; + + int i = 0; + if (commandLineParameterGroups.get(0).name.isEmpty()) { + parameters = commandLineParameterGroups.get(0).parameters; + } else { + if (args.length == 0) { + throw new CliParseException("No parameters found."); + } + for (ParameterGroup parameterGroup : commandLineParameterGroups) { + if (parameterGroup.name.equals(args[0].toLowerCase())) { + selectedGroup = parameterGroup.name; + parameters = parameterGroup.parameters; + } + } + if (parameters == null) { + throw new CliParseException("Group name " + args[0] + " is undefined."); + } + i++; + } + + while (i < args.length) { + boolean found = false; + for (CliParameter option : parameters) { + if (args[i].equals(option.getName())) { + i += option.parse(args, i); + found = true; + break; + } + } + if (!found) { + throw new CliParseException("Unknown parameter found: " + args[i]); + } + } + + for (CliParameter option : parameters) { + if (!option.isOptional() && !option.isSelected()) { + throw new CliParseException( + "Parameter " + option.getName() + " is mandatory but was not selected."); + } + } + } + + public String getUsageString() { + + StringBuilder sb = new StringBuilder(); + sb.append("NAME\n\t").append(name).append(" - ").append(description).append("\n\nSYNOPSIS\n"); + + for (ParameterGroup parameterGroup : commandLineParameterGroups) { + sb.append("\t").append(name).append(" ").append(parameterGroup.name); + + int characterColumn = name.length() + parameterGroup.name.length() + 1; + + for (CliParameter parameter : parameterGroup.parameters) { + if ((characterColumn + parameter.appendSynopsis(new StringBuilder())) > 90) { + characterColumn = 0; + sb.append("\n\t "); + } + sb.append(' '); + characterColumn += parameter.appendSynopsis(sb) + 1; + } + sb.append("\n"); + } + + sb.append("\nOPTIONS\n"); + + Set parameters = new LinkedHashSet<>(); + + for (ParameterGroup parameterGroup : commandLineParameterGroups) { + parameters.addAll(parameterGroup.parameters); + } + + for (CliParameter parameter : parameters) { + sb.append(' '); + parameter.appendDescription(sb); + sb.append("\n\n"); + } + + sb.append("\t--help display this help and exit"); + + return sb.toString(); + } + + private static class ParameterGroup { + private final String name; + private final List parameters; + + public ParameterGroup(String name, List parameters) { + this.name = name; + this.parameters = parameters; + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/FlagCliParameter.java b/src/main/java/com/beanit/iec61850bean/internal/cli/FlagCliParameter.java new file mode 100644 index 0000000..dc01286 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/FlagCliParameter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public class FlagCliParameter extends CliParameter { + + FlagCliParameter(CliParameterBuilder builder) { + super(builder); + } + + @Override + int appendSynopsis(StringBuilder sb) { + int length = 0; + if (optional) { + sb.append("["); + length++; + } + sb.append(name); + length += name.length(); + if (optional) { + sb.append("]"); + length++; + } + return length; + } + + @Override + void appendDescription(StringBuilder sb) { + sb.append("\t").append(name).append("\n\t ").append(description); + } + + @Override + int parse(String[] args, int i) { + selected = true; + return 1; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/IntCliParameter.java b/src/main/java/com/beanit/iec61850bean/internal/cli/IntCliParameter.java new file mode 100644 index 0000000..5e3dd4f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/IntCliParameter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public class IntCliParameter extends ValueCliParameter { + + Integer value; + private Integer defaultValue = null; + + IntCliParameter(CliParameterBuilder builder, String parameterName, int defaultValue) { + super(builder, parameterName); + this.defaultValue = defaultValue; + value = defaultValue; + } + + IntCliParameter(CliParameterBuilder builder, String parameterName) { + super(builder, parameterName); + } + + public int getValue() { + return value; + } + + @Override + int parse(String[] args, int i) throws CliParseException { + selected = true; + + if (args.length < (i + 2)) { + throw new CliParseException("Parameter " + name + " has no value."); + } + + try { + value = Integer.decode(args[i + 1]); + } catch (Exception e) { + throw new CliParseException( + "Parameter value " + args[i + 1] + " cannot be converted to int."); + } + return 2; + } + + @Override + void appendDescription(StringBuilder sb) { + super.appendDescription(sb); + if (defaultValue != null) { + sb.append(" Default is ").append(defaultValue).append("."); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/LongCliParameter.java b/src/main/java/com/beanit/iec61850bean/internal/cli/LongCliParameter.java new file mode 100644 index 0000000..343575a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/LongCliParameter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public class LongCliParameter extends ValueCliParameter { + + Long value; + private Long defaultValue = null; + + LongCliParameter(CliParameterBuilder builder, String parameterName, long defaultValue) { + super(builder, parameterName); + this.defaultValue = defaultValue; + value = defaultValue; + } + + LongCliParameter(CliParameterBuilder builder, String parameterName) { + super(builder, parameterName); + } + + public long getValue() { + return value; + } + + @Override + int parse(String[] args, int i) throws CliParseException { + selected = true; + + if (args.length < (i + 2)) { + throw new CliParseException("Parameter " + name + " has no value."); + } + + try { + value = Long.decode(args[i + 1]); + } catch (Exception e) { + throw new CliParseException( + "Parameter value " + args[i + 1] + " cannot be converted to long."); + } + return 2; + } + + @Override + void appendDescription(StringBuilder sb) { + super.appendDescription(sb); + if (defaultValue != null) { + sb.append(" Default is ").append(defaultValue).append("."); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/StringCliParameter.java b/src/main/java/com/beanit/iec61850bean/internal/cli/StringCliParameter.java new file mode 100644 index 0000000..68dfc99 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/StringCliParameter.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +public class StringCliParameter extends ValueCliParameter { + + String value; + private String defaultValue = null; + + StringCliParameter(CliParameterBuilder builder, String parameterName, String defaultValue) { + super(builder, parameterName); + this.defaultValue = defaultValue; + value = defaultValue; + } + + StringCliParameter(CliParameterBuilder builder, String parameterName) { + super(builder, parameterName); + } + + public String getValue() { + return value; + } + + @Override + int parse(String[] args, int i) throws CliParseException { + selected = true; + + if (args.length < (i + 2)) { + throw new CliParseException("Parameter " + name + " has no value."); + } + value = args[i + 1]; + + return 2; + } + + @Override + public void appendDescription(StringBuilder sb) { + super.appendDescription(sb); + if (defaultValue != null) { + sb.append(" Default is \"").append(defaultValue).append("\"."); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/StringListCliParameter.java b/src/main/java/com/beanit/iec61850bean/internal/cli/StringListCliParameter.java new file mode 100644 index 0000000..c9935db --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/StringListCliParameter.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +import java.util.ArrayList; +import java.util.List; + +public class StringListCliParameter extends ValueCliParameter { + + List value; + private List defaultValue = null; + + StringListCliParameter( + CliParameterBuilder builder, String parameterName, List defaultValue) { + super(builder, parameterName); + this.defaultValue = defaultValue; + value = defaultValue; + } + + StringListCliParameter(CliParameterBuilder builder, String parameterName) { + super(builder, parameterName); + } + + public List getValue() { + return value; + } + + @Override + int parse(String[] args, int i) throws CliParseException { + selected = true; + + value = new ArrayList<>(); + i++; + while (i < args.length) { + if (args[i].length() > 0 && args[i].startsWith("-")) { + break; + } + value.add(args[i++]); + } + + if (value.size() == 0) { + throw new CliParseException("Parameter " + name + " has no value."); + } + + return value.size() + 1; + } + + @Override + int appendSynopsis(StringBuilder sb) { + int length = 0; + if (optional) { + sb.append("["); + length++; + } + sb.append(name).append(" <").append(parameterName).append(">..."); + length += (name.length() + 6 + parameterName.length()); + if (optional) { + sb.append("]"); + length++; + } + return length; + } + + @Override + public void appendDescription(StringBuilder sb) { + sb.append("\t") + .append(name) + .append(" <") + .append(parameterName) + .append(">...\n\t ") + .append(description); + if (defaultValue != null) { + sb.append(" Default is \""); + for (String stringValue : defaultValue) { + sb.append(stringValue); + } + sb.append("\"."); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/cli/ValueCliParameter.java b/src/main/java/com/beanit/iec61850bean/internal/cli/ValueCliParameter.java new file mode 100644 index 0000000..c20351b --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/cli/ValueCliParameter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.cli; + +abstract class ValueCliParameter extends CliParameter { + + final String parameterName; + + ValueCliParameter(CliParameterBuilder builder, String parameterName) { + super(builder); + this.parameterName = parameterName; + } + + @Override + int appendSynopsis(StringBuilder sb) { + int length = 0; + if (optional) { + sb.append("["); + length++; + } + sb.append(name).append(" <").append(parameterName).append(">"); + length += (name.length() + 3 + parameterName.length()); + if (optional) { + sb.append("]"); + length++; + } + return length; + } + + @Override + void appendDescription(StringBuilder sb) { + sb.append("\t") + .append(name) + .append(" <") + .append(parameterName) + .append(">\n\t ") + .append(description); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AccessResult.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AccessResult.java new file mode 100644 index 0000000..21f7d41 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AccessResult.java @@ -0,0 +1,136 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AccessResult implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private DataAccessError failure = null; + private Data success = null; + + public AccessResult() {} + + public AccessResult(byte[] code) { + this.code = code; + } + + public DataAccessError getFailure() { + return failure; + } + + public void setFailure(DataAccessError failure) { + this.failure = failure; + } + + public Data getSuccess() { + return success; + } + + public void setSuccess(Data success) { + this.success = success; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (success != null) { + codeLength += success.encode(reverseOS); + return codeLength; + } + + if (failure != null) { + codeLength += failure.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + int numDecodedBytes; + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + failure = new DataAccessError(); + tlvByteCount += failure.decode(is, false); + return tlvByteCount; + } + + success = new Data(); + numDecodedBytes = success.decode(is, berTag); + if (numDecodedBytes != 0) { + return tlvByteCount + numDecodedBytes; + } else { + success = null; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (failure != null) { + sb.append("failure: ").append(failure); + return; + } + + if (success != null) { + sb.append("success: "); + success.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AlternateAccess.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AlternateAccess.java new file mode 100644 index 0000000..b334b89 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AlternateAccess.java @@ -0,0 +1,250 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class AlternateAccess implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public AlternateAccess() { + seqOf = new ArrayList(); + } + + public AlternateAccess(byte[] code) { + this.code = code; + } + + public List getCHOICE() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + CHOICE element = new CHOICE(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class CHOICE implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private AlternateAccessSelection unnamed = null; + + public CHOICE() {} + + public CHOICE(byte[] code) { + this.code = code; + } + + public AlternateAccessSelection getUnnamed() { + return unnamed; + } + + public void setUnnamed(AlternateAccessSelection unnamed) { + this.unnamed = unnamed; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (unnamed != null) { + codeLength += unnamed.encode(reverseOS); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + int numDecodedBytes; + + unnamed = new AlternateAccessSelection(); + numDecodedBytes = unnamed.decode(is, berTag); + if (numDecodedBytes != 0) { + return tlvByteCount + numDecodedBytes; + } else { + unnamed = null; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (unnamed != null) { + sb.append("unnamed: "); + unnamed.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AlternateAccessSelection.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AlternateAccessSelection.java new file mode 100644 index 0000000..5a622ee --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/AlternateAccessSelection.java @@ -0,0 +1,1179 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AlternateAccessSelection implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private SelectAlternateAccess selectAlternateAccess = null; + private SelectAccess selectAccess = null; + + public AlternateAccessSelection() {} + + public AlternateAccessSelection(byte[] code) { + this.code = code; + } + + public SelectAlternateAccess getSelectAlternateAccess() { + return selectAlternateAccess; + } + + public void setSelectAlternateAccess(SelectAlternateAccess selectAlternateAccess) { + this.selectAlternateAccess = selectAlternateAccess; + } + + public SelectAccess getSelectAccess() { + return selectAccess; + } + + public void setSelectAccess(SelectAccess selectAccess) { + this.selectAccess = selectAccess; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (selectAccess != null) { + codeLength += selectAccess.encode(reverseOS); + return codeLength; + } + + if (selectAlternateAccess != null) { + codeLength += selectAlternateAccess.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + int numDecodedBytes; + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + selectAlternateAccess = new SelectAlternateAccess(); + tlvByteCount += selectAlternateAccess.decode(is, false); + return tlvByteCount; + } + + selectAccess = new SelectAccess(); + numDecodedBytes = selectAccess.decode(is, berTag); + if (numDecodedBytes != 0) { + return tlvByteCount + numDecodedBytes; + } else { + selectAccess = null; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (selectAlternateAccess != null) { + sb.append("selectAlternateAccess: "); + selectAlternateAccess.appendAsString(sb, indentLevel + 1); + return; + } + + if (selectAccess != null) { + sb.append("selectAccess: "); + selectAccess.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } + + public static class SelectAlternateAccess implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private AccessSelection accessSelection = null; + private AlternateAccess alternateAccess = null; + + public SelectAlternateAccess() {} + + public SelectAlternateAccess(byte[] code) { + this.code = code; + } + + public AccessSelection getAccessSelection() { + return accessSelection; + } + + public void setAccessSelection(AccessSelection accessSelection) { + this.accessSelection = accessSelection; + } + + public AlternateAccess getAlternateAccess() { + return alternateAccess; + } + + public void setAlternateAccess(AlternateAccess alternateAccess) { + this.alternateAccess = alternateAccess; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += alternateAccess.encode(reverseOS, true); + + codeLength += accessSelection.encode(reverseOS); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + accessSelection = new AccessSelection(); + numDecodedBytes = accessSelection.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (berTag.equals(AlternateAccess.tag)) { + alternateAccess = new AlternateAccess(); + vByteCount += alternateAccess.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (accessSelection != null) { + sb.append("accessSelection: "); + accessSelection.appendAsString(sb, indentLevel + 1); + } else { + sb.append("accessSelection: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (alternateAccess != null) { + sb.append("alternateAccess: "); + alternateAccess.appendAsString(sb, indentLevel + 1); + } else { + sb.append("alternateAccess: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class AccessSelection implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private Component component = null; + private Unsigned32 index = null; + private IndexRange indexRange = null; + private BerNull allElements = null; + + public AccessSelection() {} + + public AccessSelection(byte[] code) { + this.code = code; + } + + public Component getComponent() { + return component; + } + + public void setComponent(Component component) { + this.component = component; + } + + public Unsigned32 getIndex() { + return index; + } + + public void setIndex(Unsigned32 index) { + this.index = index; + } + + public IndexRange getIndexRange() { + return indexRange; + } + + public void setIndexRange(IndexRange indexRange) { + this.indexRange = indexRange; + } + + public BerNull getAllElements() { + return allElements; + } + + public void setAllElements(BerNull allElements) { + this.allElements = allElements; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (allElements != null) { + codeLength += allElements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + return codeLength; + } + + if (indexRange != null) { + codeLength += indexRange.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + return codeLength; + } + + if (index != null) { + codeLength += index.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (component != null) { + sublength = component.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + component = new Component(); + tlvByteCount += component.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + index = new Unsigned32(); + tlvByteCount += index.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + indexRange = new IndexRange(); + tlvByteCount += indexRange.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + allElements = new BerNull(); + tlvByteCount += allElements.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (component != null) { + sb.append("component: "); + component.appendAsString(sb, indentLevel + 1); + return; + } + + if (index != null) { + sb.append("index: ").append(index); + return; + } + + if (indexRange != null) { + sb.append("indexRange: "); + indexRange.appendAsString(sb, indentLevel + 1); + return; + } + + if (allElements != null) { + sb.append("allElements: ").append(allElements); + return; + } + + sb.append(""); + } + + public static class Component implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BasicIdentifier basic = null; + + public Component() {} + + public Component(byte[] code) { + this.code = code; + } + + public BasicIdentifier getBasic() { + return basic; + } + + public void setBasic(BasicIdentifier basic) { + this.basic = basic; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (basic != null) { + codeLength += basic.encode(reverseOS, true); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BasicIdentifier.tag)) { + basic = new BasicIdentifier(); + tlvByteCount += basic.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (basic != null) { + sb.append("basic: ").append(basic); + return; + } + + sb.append(""); + } + } + + public static class IndexRange implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 lowIndex = null; + private Unsigned32 numberOfElements = null; + + public IndexRange() {} + + public IndexRange(byte[] code) { + this.code = code; + } + + public Unsigned32 getLowIndex() { + return lowIndex; + } + + public void setLowIndex(Unsigned32 lowIndex) { + this.lowIndex = lowIndex; + } + + public Unsigned32 getNumberOfElements() { + return numberOfElements; + } + + public void setNumberOfElements(Unsigned32 numberOfElements) { + this.numberOfElements = numberOfElements; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += numberOfElements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + codeLength += lowIndex.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + lowIndex = new Unsigned32(); + vByteCount += lowIndex.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + numberOfElements = new Unsigned32(); + vByteCount += numberOfElements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (lowIndex != null) { + sb.append("lowIndex: ").append(lowIndex); + } else { + sb.append("lowIndex: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (numberOfElements != null) { + sb.append("numberOfElements: ").append(numberOfElements); + } else { + sb.append("numberOfElements: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } + } + } + + public static class SelectAccess implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private Component component = null; + private Unsigned32 index = null; + private IndexRange indexRange = null; + private BerNull allElements = null; + + public SelectAccess() {} + + public SelectAccess(byte[] code) { + this.code = code; + } + + public Component getComponent() { + return component; + } + + public void setComponent(Component component) { + this.component = component; + } + + public Unsigned32 getIndex() { + return index; + } + + public void setIndex(Unsigned32 index) { + this.index = index; + } + + public IndexRange getIndexRange() { + return indexRange; + } + + public void setIndexRange(IndexRange indexRange) { + this.indexRange = indexRange; + } + + public BerNull getAllElements() { + return allElements; + } + + public void setAllElements(BerNull allElements) { + this.allElements = allElements; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (allElements != null) { + codeLength += allElements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 4 + reverseOS.write(0x84); + codeLength += 1; + return codeLength; + } + + if (indexRange != null) { + codeLength += indexRange.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 3 + reverseOS.write(0xA3); + codeLength += 1; + return codeLength; + } + + if (index != null) { + codeLength += index.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (component != null) { + sublength = component.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + component = new Component(); + tlvByteCount += component.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + index = new Unsigned32(); + tlvByteCount += index.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 3)) { + indexRange = new IndexRange(); + tlvByteCount += indexRange.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 4)) { + allElements = new BerNull(); + tlvByteCount += allElements.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (component != null) { + sb.append("component: "); + component.appendAsString(sb, indentLevel + 1); + return; + } + + if (index != null) { + sb.append("index: ").append(index); + return; + } + + if (indexRange != null) { + sb.append("indexRange: "); + indexRange.appendAsString(sb, indentLevel + 1); + return; + } + + if (allElements != null) { + sb.append("allElements: ").append(allElements); + return; + } + + sb.append(""); + } + + public static class Component implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BasicIdentifier basic = null; + + public Component() {} + + public Component(byte[] code) { + this.code = code; + } + + public BasicIdentifier getBasic() { + return basic; + } + + public void setBasic(BasicIdentifier basic) { + this.basic = basic; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (basic != null) { + codeLength += basic.encode(reverseOS, true); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BasicIdentifier.tag)) { + basic = new BasicIdentifier(); + tlvByteCount += basic.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (basic != null) { + sb.append("basic: ").append(basic); + return; + } + + sb.append(""); + } + } + + public static class IndexRange implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 lowIndex = null; + private Unsigned32 numberOfElements = null; + + public IndexRange() {} + + public IndexRange(byte[] code) { + this.code = code; + } + + public Unsigned32 getLowIndex() { + return lowIndex; + } + + public void setLowIndex(Unsigned32 lowIndex) { + this.lowIndex = lowIndex; + } + + public Unsigned32 getNumberOfElements() { + return numberOfElements; + } + + public void setNumberOfElements(Unsigned32 numberOfElements) { + this.numberOfElements = numberOfElements; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += numberOfElements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + codeLength += lowIndex.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + lowIndex = new Unsigned32(); + vByteCount += lowIndex.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + numberOfElements = new Unsigned32(); + vByteCount += numberOfElements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (lowIndex != null) { + sb.append("lowIndex: ").append(lowIndex); + } else { + sb.append("lowIndex: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (numberOfElements != null) { + sb.append("numberOfElements: ").append(numberOfElements); + } else { + sb.append("numberOfElements: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/BasicIdentifier.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/BasicIdentifier.java new file mode 100644 index 0000000..60e5875 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/BasicIdentifier.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.string.BerVisibleString; + +public class BasicIdentifier extends BerVisibleString { + + private static final long serialVersionUID = 1L; + + public BasicIdentifier() {} + + public BasicIdentifier(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConcludeRequestPDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConcludeRequestPDU.java new file mode 100644 index 0000000..8a1824f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConcludeRequestPDU.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerNull; + +public class ConcludeRequestPDU extends BerNull { + + private static final long serialVersionUID = 1L; + + public ConcludeRequestPDU() {} + + public ConcludeRequestPDU(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedErrorPDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedErrorPDU.java new file mode 100644 index 0000000..7a50d0a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedErrorPDU.java @@ -0,0 +1,204 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ConfirmedErrorPDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 invokeID = null; + private Unsigned32 modifierPosition = null; + private ServiceError serviceError = null; + + public ConfirmedErrorPDU() {} + + public ConfirmedErrorPDU(byte[] code) { + this.code = code; + } + + public Unsigned32 getInvokeID() { + return invokeID; + } + + public void setInvokeID(Unsigned32 invokeID) { + this.invokeID = invokeID; + } + + public Unsigned32 getModifierPosition() { + return modifierPosition; + } + + public void setModifierPosition(Unsigned32 modifierPosition) { + this.modifierPosition = modifierPosition; + } + + public ServiceError getServiceError() { + return serviceError; + } + + public void setServiceError(ServiceError serviceError) { + this.serviceError = serviceError; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += serviceError.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + + if (modifierPosition != null) { + codeLength += modifierPosition.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + codeLength += invokeID.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + invokeID = new Unsigned32(); + vByteCount += invokeID.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + modifierPosition = new Unsigned32(); + vByteCount += modifierPosition.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + serviceError = new ServiceError(); + vByteCount += serviceError.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (invokeID != null) { + sb.append("invokeID: ").append(invokeID); + } else { + sb.append("invokeID: "); + } + + if (modifierPosition != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("modifierPosition: ").append(modifierPosition); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (serviceError != null) { + sb.append("serviceError: "); + serviceError.appendAsString(sb, indentLevel + 1); + } else { + sb.append("serviceError: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedRequestPDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedRequestPDU.java new file mode 100644 index 0000000..b9cd2ac --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedRequestPDU.java @@ -0,0 +1,169 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ConfirmedRequestPDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 invokeID = null; + private ConfirmedServiceRequest service = null; + + public ConfirmedRequestPDU() {} + + public ConfirmedRequestPDU(byte[] code) { + this.code = code; + } + + public Unsigned32 getInvokeID() { + return invokeID; + } + + public void setInvokeID(Unsigned32 invokeID) { + this.invokeID = invokeID; + } + + public ConfirmedServiceRequest getService() { + return service; + } + + public void setService(ConfirmedServiceRequest service) { + this.service = service; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += service.encode(reverseOS); + + codeLength += invokeID.encode(reverseOS, true); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(Unsigned32.tag)) { + invokeID = new Unsigned32(); + vByteCount += invokeID.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + service = new ConfirmedServiceRequest(); + numDecodedBytes = service.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (invokeID != null) { + sb.append("invokeID: ").append(invokeID); + } else { + sb.append("invokeID: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (service != null) { + sb.append("service: "); + service.appendAsString(sb, indentLevel + 1); + } else { + sb.append("service: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedResponsePDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedResponsePDU.java new file mode 100644 index 0000000..06742bf --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedResponsePDU.java @@ -0,0 +1,169 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ConfirmedResponsePDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 invokeID = null; + private ConfirmedServiceResponse service = null; + + public ConfirmedResponsePDU() {} + + public ConfirmedResponsePDU(byte[] code) { + this.code = code; + } + + public Unsigned32 getInvokeID() { + return invokeID; + } + + public void setInvokeID(Unsigned32 invokeID) { + this.invokeID = invokeID; + } + + public ConfirmedServiceResponse getService() { + return service; + } + + public void setService(ConfirmedServiceResponse service) { + this.service = service; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += service.encode(reverseOS); + + codeLength += invokeID.encode(reverseOS, true); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(Unsigned32.tag)) { + invokeID = new Unsigned32(); + vByteCount += invokeID.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + service = new ConfirmedServiceResponse(); + numDecodedBytes = service.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (invokeID != null) { + sb.append("invokeID: ").append(invokeID); + } else { + sb.append("invokeID: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (service != null) { + sb.append("service: "); + service.appendAsString(sb, indentLevel + 1); + } else { + sb.append("service: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedServiceRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedServiceRequest.java new file mode 100644 index 0000000..997f25b --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedServiceRequest.java @@ -0,0 +1,444 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ConfirmedServiceRequest implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private GetNameListRequest getNameList = null; + private ReadRequest read = null; + private WriteRequest write = null; + private GetVariableAccessAttributesRequest getVariableAccessAttributes = null; + private DefineNamedVariableListRequest defineNamedVariableList = null; + private GetNamedVariableListAttributesRequest getNamedVariableListAttributes = null; + private DeleteNamedVariableListRequest deleteNamedVariableList = null; + private FileOpenRequest fileOpen = null; + private FileReadRequest fileRead = null; + private FileCloseRequest fileClose = null; + private FileDeleteRequest fileDelete = null; + private FileDirectoryRequest fileDirectory = null; + + public ConfirmedServiceRequest() {} + + public ConfirmedServiceRequest(byte[] code) { + this.code = code; + } + + public GetNameListRequest getGetNameList() { + return getNameList; + } + + public void setGetNameList(GetNameListRequest getNameList) { + this.getNameList = getNameList; + } + + public ReadRequest getRead() { + return read; + } + + public void setRead(ReadRequest read) { + this.read = read; + } + + public WriteRequest getWrite() { + return write; + } + + public void setWrite(WriteRequest write) { + this.write = write; + } + + public GetVariableAccessAttributesRequest getGetVariableAccessAttributes() { + return getVariableAccessAttributes; + } + + public void setGetVariableAccessAttributes( + GetVariableAccessAttributesRequest getVariableAccessAttributes) { + this.getVariableAccessAttributes = getVariableAccessAttributes; + } + + public DefineNamedVariableListRequest getDefineNamedVariableList() { + return defineNamedVariableList; + } + + public void setDefineNamedVariableList(DefineNamedVariableListRequest defineNamedVariableList) { + this.defineNamedVariableList = defineNamedVariableList; + } + + public GetNamedVariableListAttributesRequest getGetNamedVariableListAttributes() { + return getNamedVariableListAttributes; + } + + public void setGetNamedVariableListAttributes( + GetNamedVariableListAttributesRequest getNamedVariableListAttributes) { + this.getNamedVariableListAttributes = getNamedVariableListAttributes; + } + + public DeleteNamedVariableListRequest getDeleteNamedVariableList() { + return deleteNamedVariableList; + } + + public void setDeleteNamedVariableList(DeleteNamedVariableListRequest deleteNamedVariableList) { + this.deleteNamedVariableList = deleteNamedVariableList; + } + + public FileOpenRequest getFileOpen() { + return fileOpen; + } + + public void setFileOpen(FileOpenRequest fileOpen) { + this.fileOpen = fileOpen; + } + + public FileReadRequest getFileRead() { + return fileRead; + } + + public void setFileRead(FileReadRequest fileRead) { + this.fileRead = fileRead; + } + + public FileCloseRequest getFileClose() { + return fileClose; + } + + public void setFileClose(FileCloseRequest fileClose) { + this.fileClose = fileClose; + } + + public FileDeleteRequest getFileDelete() { + return fileDelete; + } + + public void setFileDelete(FileDeleteRequest fileDelete) { + this.fileDelete = fileDelete; + } + + public FileDirectoryRequest getFileDirectory() { + return fileDirectory; + } + + public void setFileDirectory(FileDirectoryRequest fileDirectory) { + this.fileDirectory = fileDirectory; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (fileDirectory != null) { + codeLength += fileDirectory.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 77 + reverseOS.write(0x4D); + reverseOS.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (fileDelete != null) { + codeLength += fileDelete.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 76 + reverseOS.write(0x4C); + reverseOS.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (fileClose != null) { + codeLength += fileClose.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 74 + reverseOS.write(0x4A); + reverseOS.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileRead != null) { + codeLength += fileRead.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 73 + reverseOS.write(0x49); + reverseOS.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileOpen != null) { + codeLength += fileOpen.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 72 + reverseOS.write(0x48); + reverseOS.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (deleteNamedVariableList != null) { + codeLength += deleteNamedVariableList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 13 + reverseOS.write(0xAD); + codeLength += 1; + return codeLength; + } + + if (getNamedVariableListAttributes != null) { + sublength = getNamedVariableListAttributes.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 12 + reverseOS.write(0xAC); + codeLength += 1; + return codeLength; + } + + if (defineNamedVariableList != null) { + codeLength += defineNamedVariableList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 11 + reverseOS.write(0xAB); + codeLength += 1; + return codeLength; + } + + if (getVariableAccessAttributes != null) { + sublength = getVariableAccessAttributes.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 6 + reverseOS.write(0xA6); + codeLength += 1; + return codeLength; + } + + if (write != null) { + codeLength += write.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 5 + reverseOS.write(0xA5); + codeLength += 1; + return codeLength; + } + + if (read != null) { + codeLength += read.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + return codeLength; + } + + if (getNameList != null) { + codeLength += getNameList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + getNameList = new GetNameListRequest(); + tlvByteCount += getNameList.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + read = new ReadRequest(); + tlvByteCount += read.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 5)) { + write = new WriteRequest(); + tlvByteCount += write.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 6)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + getVariableAccessAttributes = new GetVariableAccessAttributesRequest(); + tlvByteCount += getVariableAccessAttributes.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 11)) { + defineNamedVariableList = new DefineNamedVariableListRequest(); + tlvByteCount += defineNamedVariableList.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 12)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + getNamedVariableListAttributes = new GetNamedVariableListAttributesRequest(); + tlvByteCount += getNamedVariableListAttributes.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 13)) { + deleteNamedVariableList = new DeleteNamedVariableListRequest(); + tlvByteCount += deleteNamedVariableList.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 72)) { + fileOpen = new FileOpenRequest(); + tlvByteCount += fileOpen.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 73)) { + fileRead = new FileReadRequest(); + tlvByteCount += fileRead.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 74)) { + fileClose = new FileCloseRequest(); + tlvByteCount += fileClose.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 76)) { + fileDelete = new FileDeleteRequest(); + tlvByteCount += fileDelete.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 77)) { + fileDirectory = new FileDirectoryRequest(); + tlvByteCount += fileDirectory.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (getNameList != null) { + sb.append("getNameList: "); + getNameList.appendAsString(sb, indentLevel + 1); + return; + } + + if (read != null) { + sb.append("read: "); + read.appendAsString(sb, indentLevel + 1); + return; + } + + if (write != null) { + sb.append("write: "); + write.appendAsString(sb, indentLevel + 1); + return; + } + + if (getVariableAccessAttributes != null) { + sb.append("getVariableAccessAttributes: "); + getVariableAccessAttributes.appendAsString(sb, indentLevel + 1); + return; + } + + if (defineNamedVariableList != null) { + sb.append("defineNamedVariableList: "); + defineNamedVariableList.appendAsString(sb, indentLevel + 1); + return; + } + + if (getNamedVariableListAttributes != null) { + sb.append("getNamedVariableListAttributes: "); + getNamedVariableListAttributes.appendAsString(sb, indentLevel + 1); + return; + } + + if (deleteNamedVariableList != null) { + sb.append("deleteNamedVariableList: "); + deleteNamedVariableList.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileOpen != null) { + sb.append("fileOpen: "); + fileOpen.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileRead != null) { + sb.append("fileRead: ").append(fileRead); + return; + } + + if (fileClose != null) { + sb.append("fileClose: ").append(fileClose); + return; + } + + if (fileDelete != null) { + sb.append("fileDelete: "); + fileDelete.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileDirectory != null) { + sb.append("fileDirectory: "); + fileDirectory.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedServiceResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedServiceResponse.java new file mode 100644 index 0000000..268d091 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ConfirmedServiceResponse.java @@ -0,0 +1,430 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ConfirmedServiceResponse implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private GetNameListResponse getNameList = null; + private ReadResponse read = null; + private WriteResponse write = null; + private GetVariableAccessAttributesResponse getVariableAccessAttributes = null; + private DefineNamedVariableListResponse defineNamedVariableList = null; + private GetNamedVariableListAttributesResponse getNamedVariableListAttributes = null; + private DeleteNamedVariableListResponse deleteNamedVariableList = null; + private FileOpenResponse fileOpen = null; + private FileReadResponse fileRead = null; + private FileCloseResponse fileClose = null; + private FileDeleteResponse fileDelete = null; + private FileDirectoryResponse fileDirectory = null; + + public ConfirmedServiceResponse() {} + + public ConfirmedServiceResponse(byte[] code) { + this.code = code; + } + + public GetNameListResponse getGetNameList() { + return getNameList; + } + + public void setGetNameList(GetNameListResponse getNameList) { + this.getNameList = getNameList; + } + + public ReadResponse getRead() { + return read; + } + + public void setRead(ReadResponse read) { + this.read = read; + } + + public WriteResponse getWrite() { + return write; + } + + public void setWrite(WriteResponse write) { + this.write = write; + } + + public GetVariableAccessAttributesResponse getGetVariableAccessAttributes() { + return getVariableAccessAttributes; + } + + public void setGetVariableAccessAttributes( + GetVariableAccessAttributesResponse getVariableAccessAttributes) { + this.getVariableAccessAttributes = getVariableAccessAttributes; + } + + public DefineNamedVariableListResponse getDefineNamedVariableList() { + return defineNamedVariableList; + } + + public void setDefineNamedVariableList(DefineNamedVariableListResponse defineNamedVariableList) { + this.defineNamedVariableList = defineNamedVariableList; + } + + public GetNamedVariableListAttributesResponse getGetNamedVariableListAttributes() { + return getNamedVariableListAttributes; + } + + public void setGetNamedVariableListAttributes( + GetNamedVariableListAttributesResponse getNamedVariableListAttributes) { + this.getNamedVariableListAttributes = getNamedVariableListAttributes; + } + + public DeleteNamedVariableListResponse getDeleteNamedVariableList() { + return deleteNamedVariableList; + } + + public void setDeleteNamedVariableList(DeleteNamedVariableListResponse deleteNamedVariableList) { + this.deleteNamedVariableList = deleteNamedVariableList; + } + + public FileOpenResponse getFileOpen() { + return fileOpen; + } + + public void setFileOpen(FileOpenResponse fileOpen) { + this.fileOpen = fileOpen; + } + + public FileReadResponse getFileRead() { + return fileRead; + } + + public void setFileRead(FileReadResponse fileRead) { + this.fileRead = fileRead; + } + + public FileCloseResponse getFileClose() { + return fileClose; + } + + public void setFileClose(FileCloseResponse fileClose) { + this.fileClose = fileClose; + } + + public FileDeleteResponse getFileDelete() { + return fileDelete; + } + + public void setFileDelete(FileDeleteResponse fileDelete) { + this.fileDelete = fileDelete; + } + + public FileDirectoryResponse getFileDirectory() { + return fileDirectory; + } + + public void setFileDirectory(FileDirectoryResponse fileDirectory) { + this.fileDirectory = fileDirectory; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (fileDirectory != null) { + codeLength += fileDirectory.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 77 + reverseOS.write(0x4D); + reverseOS.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (fileDelete != null) { + codeLength += fileDelete.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 76 + reverseOS.write(0x4C); + reverseOS.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileClose != null) { + codeLength += fileClose.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 74 + reverseOS.write(0x4A); + reverseOS.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileRead != null) { + codeLength += fileRead.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 73 + reverseOS.write(0x49); + reverseOS.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (fileOpen != null) { + codeLength += fileOpen.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 72 + reverseOS.write(0x48); + reverseOS.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (deleteNamedVariableList != null) { + codeLength += deleteNamedVariableList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 13 + reverseOS.write(0xAD); + codeLength += 1; + return codeLength; + } + + if (getNamedVariableListAttributes != null) { + codeLength += getNamedVariableListAttributes.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 12 + reverseOS.write(0xAC); + codeLength += 1; + return codeLength; + } + + if (defineNamedVariableList != null) { + codeLength += defineNamedVariableList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 11 + reverseOS.write(0x8B); + codeLength += 1; + return codeLength; + } + + if (getVariableAccessAttributes != null) { + codeLength += getVariableAccessAttributes.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 6 + reverseOS.write(0xA6); + codeLength += 1; + return codeLength; + } + + if (write != null) { + codeLength += write.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 5 + reverseOS.write(0xA5); + codeLength += 1; + return codeLength; + } + + if (read != null) { + codeLength += read.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + return codeLength; + } + + if (getNameList != null) { + codeLength += getNameList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + getNameList = new GetNameListResponse(); + tlvByteCount += getNameList.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + read = new ReadResponse(); + tlvByteCount += read.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 5)) { + write = new WriteResponse(); + tlvByteCount += write.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 6)) { + getVariableAccessAttributes = new GetVariableAccessAttributesResponse(); + tlvByteCount += getVariableAccessAttributes.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 11)) { + defineNamedVariableList = new DefineNamedVariableListResponse(); + tlvByteCount += defineNamedVariableList.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 12)) { + getNamedVariableListAttributes = new GetNamedVariableListAttributesResponse(); + tlvByteCount += getNamedVariableListAttributes.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 13)) { + deleteNamedVariableList = new DeleteNamedVariableListResponse(); + tlvByteCount += deleteNamedVariableList.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 72)) { + fileOpen = new FileOpenResponse(); + tlvByteCount += fileOpen.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 73)) { + fileRead = new FileReadResponse(); + tlvByteCount += fileRead.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 74)) { + fileClose = new FileCloseResponse(); + tlvByteCount += fileClose.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 76)) { + fileDelete = new FileDeleteResponse(); + tlvByteCount += fileDelete.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 77)) { + fileDirectory = new FileDirectoryResponse(); + tlvByteCount += fileDirectory.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (getNameList != null) { + sb.append("getNameList: "); + getNameList.appendAsString(sb, indentLevel + 1); + return; + } + + if (read != null) { + sb.append("read: "); + read.appendAsString(sb, indentLevel + 1); + return; + } + + if (write != null) { + sb.append("write: "); + write.appendAsString(sb, indentLevel + 1); + return; + } + + if (getVariableAccessAttributes != null) { + sb.append("getVariableAccessAttributes: "); + getVariableAccessAttributes.appendAsString(sb, indentLevel + 1); + return; + } + + if (defineNamedVariableList != null) { + sb.append("defineNamedVariableList: ").append(defineNamedVariableList); + return; + } + + if (getNamedVariableListAttributes != null) { + sb.append("getNamedVariableListAttributes: "); + getNamedVariableListAttributes.appendAsString(sb, indentLevel + 1); + return; + } + + if (deleteNamedVariableList != null) { + sb.append("deleteNamedVariableList: "); + deleteNamedVariableList.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileOpen != null) { + sb.append("fileOpen: "); + fileOpen.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileRead != null) { + sb.append("fileRead: "); + fileRead.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileClose != null) { + sb.append("fileClose: ").append(fileClose); + return; + } + + if (fileDelete != null) { + sb.append("fileDelete: ").append(fileDelete); + return; + } + + if (fileDirectory != null) { + sb.append("fileDirectory: "); + fileDirectory.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Data.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Data.java new file mode 100644 index 0000000..7cc9217 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Data.java @@ -0,0 +1,701 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerOctetString; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.asn1bean.ber.types.string.BerVisibleString; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class Data implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private Array array = null; + private Structure structure = null; + private BerBoolean bool = null; + private BerBitString bitString = null; + private BerInteger integer = null; + private BerInteger unsigned = null; + private FloatingPoint floatingPoint = null; + private BerOctetString octetString = null; + private BerVisibleString visibleString = null; + private TimeOfDay binaryTime = null; + private MMSString mMSString = null; + private UtcTime utcTime = null; + + public Data() {} + + public Data(byte[] code) { + this.code = code; + } + + public Array getArray() { + return array; + } + + public void setArray(Array array) { + this.array = array; + } + + public Structure getStructure() { + return structure; + } + + public void setStructure(Structure structure) { + this.structure = structure; + } + + public BerBoolean getBool() { + return bool; + } + + public void setBool(BerBoolean bool) { + this.bool = bool; + } + + public BerBitString getBitString() { + return bitString; + } + + public void setBitString(BerBitString bitString) { + this.bitString = bitString; + } + + public BerInteger getInteger() { + return integer; + } + + public void setInteger(BerInteger integer) { + this.integer = integer; + } + + public BerInteger getUnsigned() { + return unsigned; + } + + public void setUnsigned(BerInteger unsigned) { + this.unsigned = unsigned; + } + + public FloatingPoint getFloatingPoint() { + return floatingPoint; + } + + public void setFloatingPoint(FloatingPoint floatingPoint) { + this.floatingPoint = floatingPoint; + } + + public BerOctetString getOctetString() { + return octetString; + } + + public void setOctetString(BerOctetString octetString) { + this.octetString = octetString; + } + + public BerVisibleString getVisibleString() { + return visibleString; + } + + public void setVisibleString(BerVisibleString visibleString) { + this.visibleString = visibleString; + } + + public TimeOfDay getBinaryTime() { + return binaryTime; + } + + public void setBinaryTime(TimeOfDay binaryTime) { + this.binaryTime = binaryTime; + } + + public MMSString getMMSString() { + return mMSString; + } + + public void setMMSString(MMSString mMSString) { + this.mMSString = mMSString; + } + + public UtcTime getUtcTime() { + return utcTime; + } + + public void setUtcTime(UtcTime utcTime) { + this.utcTime = utcTime; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (utcTime != null) { + codeLength += utcTime.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 17 + reverseOS.write(0x91); + codeLength += 1; + return codeLength; + } + + if (mMSString != null) { + codeLength += mMSString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 16 + reverseOS.write(0x90); + codeLength += 1; + return codeLength; + } + + if (binaryTime != null) { + codeLength += binaryTime.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 12 + reverseOS.write(0x8C); + codeLength += 1; + return codeLength; + } + + if (visibleString != null) { + codeLength += visibleString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 10 + reverseOS.write(0x8A); + codeLength += 1; + return codeLength; + } + + if (octetString != null) { + codeLength += octetString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 9 + reverseOS.write(0x89); + codeLength += 1; + return codeLength; + } + + if (floatingPoint != null) { + codeLength += floatingPoint.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 7 + reverseOS.write(0x87); + codeLength += 1; + return codeLength; + } + + if (unsigned != null) { + codeLength += unsigned.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 6 + reverseOS.write(0x86); + codeLength += 1; + return codeLength; + } + + if (integer != null) { + codeLength += integer.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 5 + reverseOS.write(0x85); + codeLength += 1; + return codeLength; + } + + if (bitString != null) { + codeLength += bitString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 4 + reverseOS.write(0x84); + codeLength += 1; + return codeLength; + } + + if (bool != null) { + codeLength += bool.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + return codeLength; + } + + if (structure != null) { + codeLength += structure.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + return codeLength; + } + + if (array != null) { + codeLength += array.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + array = new Array(); + tlvByteCount += array.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + structure = new Structure(); + tlvByteCount += structure.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + bool = new BerBoolean(); + tlvByteCount += bool.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 4)) { + bitString = new BerBitString(); + tlvByteCount += bitString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 5)) { + integer = new BerInteger(); + tlvByteCount += integer.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 6)) { + unsigned = new BerInteger(); + tlvByteCount += unsigned.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 7)) { + floatingPoint = new FloatingPoint(); + tlvByteCount += floatingPoint.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 9)) { + octetString = new BerOctetString(); + tlvByteCount += octetString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 10)) { + visibleString = new BerVisibleString(); + tlvByteCount += visibleString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 12)) { + binaryTime = new TimeOfDay(); + tlvByteCount += binaryTime.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 16)) { + mMSString = new MMSString(); + tlvByteCount += mMSString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 17)) { + utcTime = new UtcTime(); + tlvByteCount += utcTime.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (array != null) { + sb.append("array: "); + array.appendAsString(sb, indentLevel + 1); + return; + } + + if (structure != null) { + sb.append("structure: "); + structure.appendAsString(sb, indentLevel + 1); + return; + } + + if (bool != null) { + sb.append("bool: ").append(bool); + return; + } + + if (bitString != null) { + sb.append("bitString: ").append(bitString); + return; + } + + if (integer != null) { + sb.append("integer: ").append(integer); + return; + } + + if (unsigned != null) { + sb.append("unsigned: ").append(unsigned); + return; + } + + if (floatingPoint != null) { + sb.append("floatingPoint: ").append(floatingPoint); + return; + } + + if (octetString != null) { + sb.append("octetString: ").append(octetString); + return; + } + + if (visibleString != null) { + sb.append("visibleString: ").append(visibleString); + return; + } + + if (binaryTime != null) { + sb.append("binaryTime: ").append(binaryTime); + return; + } + + if (mMSString != null) { + sb.append("mMSString: ").append(mMSString); + return; + } + + if (utcTime != null) { + sb.append("utcTime: ").append(utcTime); + return; + } + + sb.append(""); + } + + public static class Array implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public Array() { + seqOf = new ArrayList(); + } + + public Array(byte[] code) { + this.code = code; + } + + public List getData() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + Data element = new Data(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } + + public static class Structure implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public Structure() { + seqOf = new ArrayList(); + } + + public Structure(byte[] code) { + this.code = code; + } + + public List getData() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + Data element = new Data(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DataAccessError.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DataAccessError.java new file mode 100644 index 0000000..160a6d6 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DataAccessError.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class DataAccessError extends BerInteger { + + private static final long serialVersionUID = 1L; + + public DataAccessError() {} + + public DataAccessError(byte[] code) { + super(code); + } + + public DataAccessError(BigInteger value) { + super(value); + } + + public DataAccessError(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DefineNamedVariableListRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DefineNamedVariableListRequest.java new file mode 100644 index 0000000..99cc1ad --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DefineNamedVariableListRequest.java @@ -0,0 +1,173 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class DefineNamedVariableListRequest implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ObjectName variableListName = null; + private VariableDefs listOfVariable = null; + + public DefineNamedVariableListRequest() {} + + public DefineNamedVariableListRequest(byte[] code) { + this.code = code; + } + + public ObjectName getVariableListName() { + return variableListName; + } + + public void setVariableListName(ObjectName variableListName) { + this.variableListName = variableListName; + } + + public VariableDefs getListOfVariable() { + return listOfVariable; + } + + public void setListOfVariable(VariableDefs listOfVariable) { + this.listOfVariable = listOfVariable; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += listOfVariable.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += variableListName.encode(reverseOS); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + variableListName = new ObjectName(); + numDecodedBytes = variableListName.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + listOfVariable = new VariableDefs(); + vByteCount += listOfVariable.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (variableListName != null) { + sb.append("variableListName: "); + variableListName.appendAsString(sb, indentLevel + 1); + } else { + sb.append("variableListName: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (listOfVariable != null) { + sb.append("listOfVariable: "); + listOfVariable.appendAsString(sb, indentLevel + 1); + } else { + sb.append("listOfVariable: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DefineNamedVariableListResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DefineNamedVariableListResponse.java new file mode 100644 index 0000000..11e582b --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DefineNamedVariableListResponse.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerNull; + +public class DefineNamedVariableListResponse extends BerNull { + + private static final long serialVersionUID = 1L; + + public DefineNamedVariableListResponse() {} + + public DefineNamedVariableListResponse(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DeleteNamedVariableListRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DeleteNamedVariableListRequest.java new file mode 100644 index 0000000..abc9eaa --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DeleteNamedVariableListRequest.java @@ -0,0 +1,456 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class DeleteNamedVariableListRequest implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerInteger scopeOfDelete = null; + private ListOfVariableListName listOfVariableListName = null; + private DomainName domainName = null; + + public DeleteNamedVariableListRequest() {} + + public DeleteNamedVariableListRequest(byte[] code) { + this.code = code; + } + + public BerInteger getScopeOfDelete() { + return scopeOfDelete; + } + + public void setScopeOfDelete(BerInteger scopeOfDelete) { + this.scopeOfDelete = scopeOfDelete; + } + + public ListOfVariableListName getListOfVariableListName() { + return listOfVariableListName; + } + + public void setListOfVariableListName(ListOfVariableListName listOfVariableListName) { + this.listOfVariableListName = listOfVariableListName; + } + + public DomainName getDomainName() { + return domainName; + } + + public void setDomainName(DomainName domainName) { + this.domainName = domainName; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + if (domainName != null) { + sublength = domainName.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + } + + if (listOfVariableListName != null) { + codeLength += listOfVariableListName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + } + + if (scopeOfDelete != null) { + codeLength += scopeOfDelete.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + if (lengthVal == 0) { + return tlByteCount; + } + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + scopeOfDelete = new BerInteger(); + vByteCount += scopeOfDelete.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + listOfVariableListName = new ListOfVariableListName(); + vByteCount += listOfVariableListName.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + vByteCount += length.decode(is); + domainName = new DomainName(); + vByteCount += domainName.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (scopeOfDelete != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("scopeOfDelete: ").append(scopeOfDelete); + firstSelectedElement = false; + } + + if (listOfVariableListName != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("listOfVariableListName: "); + listOfVariableListName.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + if (domainName != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("domainName: "); + domainName.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ListOfVariableListName implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ListOfVariableListName() { + seqOf = new ArrayList(); + } + + public ListOfVariableListName(byte[] code) { + this.code = code; + } + + public List getObjectName() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + ObjectName element = new ObjectName(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } + + public static class DomainName implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BasicIdentifier basic = null; + + public DomainName() {} + + public DomainName(byte[] code) { + this.code = code; + } + + public BasicIdentifier getBasic() { + return basic; + } + + public void setBasic(BasicIdentifier basic) { + this.basic = basic; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (basic != null) { + codeLength += basic.encode(reverseOS, true); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BasicIdentifier.tag)) { + basic = new BasicIdentifier(); + tlvByteCount += basic.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (basic != null) { + sb.append("basic: ").append(basic); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DeleteNamedVariableListResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DeleteNamedVariableListResponse.java new file mode 100644 index 0000000..93b1e1c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DeleteNamedVariableListResponse.java @@ -0,0 +1,173 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class DeleteNamedVariableListResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 numberMatched = null; + private Unsigned32 numberDeleted = null; + + public DeleteNamedVariableListResponse() {} + + public DeleteNamedVariableListResponse(byte[] code) { + this.code = code; + } + + public Unsigned32 getNumberMatched() { + return numberMatched; + } + + public void setNumberMatched(Unsigned32 numberMatched) { + this.numberMatched = numberMatched; + } + + public Unsigned32 getNumberDeleted() { + return numberDeleted; + } + + public void setNumberDeleted(Unsigned32 numberDeleted) { + this.numberDeleted = numberDeleted; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += numberDeleted.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + codeLength += numberMatched.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + numberMatched = new Unsigned32(); + vByteCount += numberMatched.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + numberDeleted = new Unsigned32(); + vByteCount += numberDeleted.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (numberMatched != null) { + sb.append("numberMatched: ").append(numberMatched); + } else { + sb.append("numberMatched: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (numberDeleted != null) { + sb.append("numberDeleted: ").append(numberDeleted); + } else { + sb.append("numberDeleted: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DirectoryEntry.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DirectoryEntry.java new file mode 100644 index 0000000..52267a5 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/DirectoryEntry.java @@ -0,0 +1,175 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class DirectoryEntry implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private FileName fileName = null; + private FileAttributes fileAttributes = null; + + public DirectoryEntry() {} + + public DirectoryEntry(byte[] code) { + this.code = code; + } + + public FileName getFileName() { + return fileName; + } + + public void setFileName(FileName fileName) { + this.fileName = fileName; + } + + public FileAttributes getFileAttributes() { + return fileAttributes; + } + + public void setFileAttributes(FileAttributes fileAttributes) { + this.fileAttributes = fileAttributes; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += fileAttributes.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + codeLength += fileName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + fileName = new FileName(); + vByteCount += fileName.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + fileAttributes = new FileAttributes(); + vByteCount += fileAttributes.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileName != null) { + sb.append("fileName: "); + fileName.appendAsString(sb, indentLevel + 1); + } else { + sb.append("fileName: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileAttributes != null) { + sb.append("fileAttributes: "); + fileAttributes.appendAsString(sb, indentLevel + 1); + } else { + sb.append("fileAttributes: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileAttributes.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileAttributes.java new file mode 100644 index 0000000..183a3b8 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileAttributes.java @@ -0,0 +1,175 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerGeneralizedTime; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class FileAttributes implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 sizeOfFile = null; + private BerGeneralizedTime lastModified = null; + + public FileAttributes() {} + + public FileAttributes(byte[] code) { + this.code = code; + } + + public Unsigned32 getSizeOfFile() { + return sizeOfFile; + } + + public void setSizeOfFile(Unsigned32 sizeOfFile) { + this.sizeOfFile = sizeOfFile; + } + + public BerGeneralizedTime getLastModified() { + return lastModified; + } + + public void setLastModified(BerGeneralizedTime lastModified) { + this.lastModified = lastModified; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (lastModified != null) { + codeLength += lastModified.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + codeLength += sizeOfFile.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + sizeOfFile = new Unsigned32(); + vByteCount += sizeOfFile.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + lastModified = new BerGeneralizedTime(); + vByteCount += lastModified.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (sizeOfFile != null) { + sb.append("sizeOfFile: ").append(sizeOfFile); + } else { + sb.append("sizeOfFile: "); + } + + if (lastModified != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("lastModified: ").append(lastModified); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileCloseRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileCloseRequest.java new file mode 100644 index 0000000..37707cf --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileCloseRequest.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import java.math.BigInteger; + +public class FileCloseRequest extends Integer32 { + + private static final long serialVersionUID = 1L; + + public FileCloseRequest() {} + + public FileCloseRequest(byte[] code) { + super(code); + } + + public FileCloseRequest(BigInteger value) { + super(value); + } + + public FileCloseRequest(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileCloseResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileCloseResponse.java new file mode 100644 index 0000000..2d212f5 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileCloseResponse.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerNull; + +public class FileCloseResponse extends BerNull { + + private static final long serialVersionUID = 1L; + + public FileCloseResponse() {} + + public FileCloseResponse(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDeleteRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDeleteRequest.java new file mode 100644 index 0000000..fa48d94 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDeleteRequest.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +public class FileDeleteRequest extends FileName { + + private static final long serialVersionUID = 1L; + + public FileDeleteRequest() {} + + public FileDeleteRequest(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDeleteResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDeleteResponse.java new file mode 100644 index 0000000..cbaa661 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDeleteResponse.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerNull; + +public class FileDeleteResponse extends BerNull { + + private static final long serialVersionUID = 1L; + + public FileDeleteResponse() {} + + public FileDeleteResponse(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDirectoryRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDirectoryRequest.java new file mode 100644 index 0000000..b1018f6 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDirectoryRequest.java @@ -0,0 +1,182 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class FileDirectoryRequest implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private FileName fileSpecification = null; + private FileName continueAfter = null; + + public FileDirectoryRequest() {} + + public FileDirectoryRequest(byte[] code) { + this.code = code; + } + + public FileName getFileSpecification() { + return fileSpecification; + } + + public void setFileSpecification(FileName fileSpecification) { + this.fileSpecification = fileSpecification; + } + + public FileName getContinueAfter() { + return continueAfter; + } + + public void setContinueAfter(FileName continueAfter) { + this.continueAfter = continueAfter; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (continueAfter != null) { + codeLength += continueAfter.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + } + + if (fileSpecification != null) { + codeLength += fileSpecification.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + if (lengthVal == 0) { + return tlByteCount; + } + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + fileSpecification = new FileName(); + vByteCount += fileSpecification.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + continueAfter = new FileName(); + vByteCount += continueAfter.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (fileSpecification != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("fileSpecification: "); + fileSpecification.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + if (continueAfter != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("continueAfter: "); + continueAfter.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDirectoryResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDirectoryResponse.java new file mode 100644 index 0000000..7b5bf36 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileDirectoryResponse.java @@ -0,0 +1,321 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class FileDirectoryResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ListOfDirectoryEntry listOfDirectoryEntry = null; + private BerBoolean moreFollows = null; + + public FileDirectoryResponse() {} + + public FileDirectoryResponse(byte[] code) { + this.code = code; + } + + public ListOfDirectoryEntry getListOfDirectoryEntry() { + return listOfDirectoryEntry; + } + + public void setListOfDirectoryEntry(ListOfDirectoryEntry listOfDirectoryEntry) { + this.listOfDirectoryEntry = listOfDirectoryEntry; + } + + public BerBoolean getMoreFollows() { + return moreFollows; + } + + public void setMoreFollows(BerBoolean moreFollows) { + this.moreFollows = moreFollows; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + if (moreFollows != null) { + codeLength += moreFollows.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + sublength = listOfDirectoryEntry.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + vByteCount += length.decode(is); + listOfDirectoryEntry = new ListOfDirectoryEntry(); + vByteCount += listOfDirectoryEntry.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + moreFollows = new BerBoolean(); + vByteCount += moreFollows.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (listOfDirectoryEntry != null) { + sb.append("listOfDirectoryEntry: "); + listOfDirectoryEntry.appendAsString(sb, indentLevel + 1); + } else { + sb.append("listOfDirectoryEntry: "); + } + + if (moreFollows != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("moreFollows: ").append(moreFollows); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ListOfDirectoryEntry implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ListOfDirectoryEntry() { + seqOf = new ArrayList(); + } + + public ListOfDirectoryEntry(byte[] code) { + this.code = code; + } + + public List getDirectoryEntry() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(DirectoryEntry.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + DirectoryEntry element = new DirectoryEntry(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileName.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileName.java new file mode 100644 index 0000000..9fa0e3f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileName.java @@ -0,0 +1,154 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.asn1bean.ber.types.string.BerGraphicString; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class FileName implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public FileName() { + seqOf = new ArrayList(); + } + + public FileName(byte[] code) { + this.code = code; + } + + public List getBerGraphicString() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(BerGraphicString.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + BerGraphicString element = new BerGraphicString(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + sb.append(it.next()); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append(it.next()); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileOpenRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileOpenRequest.java new file mode 100644 index 0000000..1d9f6a1 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileOpenRequest.java @@ -0,0 +1,174 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class FileOpenRequest implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private FileName fileName = null; + private Unsigned32 initialPosition = null; + + public FileOpenRequest() {} + + public FileOpenRequest(byte[] code) { + this.code = code; + } + + public FileName getFileName() { + return fileName; + } + + public void setFileName(FileName fileName) { + this.fileName = fileName; + } + + public Unsigned32 getInitialPosition() { + return initialPosition; + } + + public void setInitialPosition(Unsigned32 initialPosition) { + this.initialPosition = initialPosition; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += initialPosition.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + codeLength += fileName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + fileName = new FileName(); + vByteCount += fileName.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + initialPosition = new Unsigned32(); + vByteCount += initialPosition.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileName != null) { + sb.append("fileName: "); + fileName.appendAsString(sb, indentLevel + 1); + } else { + sb.append("fileName: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (initialPosition != null) { + sb.append("initialPosition: ").append(initialPosition); + } else { + sb.append("initialPosition: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileOpenResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileOpenResponse.java new file mode 100644 index 0000000..6c2c538 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileOpenResponse.java @@ -0,0 +1,174 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class FileOpenResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Integer32 frsmID = null; + private FileAttributes fileAttributes = null; + + public FileOpenResponse() {} + + public FileOpenResponse(byte[] code) { + this.code = code; + } + + public Integer32 getFrsmID() { + return frsmID; + } + + public void setFrsmID(Integer32 frsmID) { + this.frsmID = frsmID; + } + + public FileAttributes getFileAttributes() { + return fileAttributes; + } + + public void setFileAttributes(FileAttributes fileAttributes) { + this.fileAttributes = fileAttributes; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += fileAttributes.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + codeLength += frsmID.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + frsmID = new Integer32(); + vByteCount += frsmID.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + fileAttributes = new FileAttributes(); + vByteCount += fileAttributes.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (frsmID != null) { + sb.append("frsmID: ").append(frsmID); + } else { + sb.append("frsmID: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileAttributes != null) { + sb.append("fileAttributes: "); + fileAttributes.appendAsString(sb, indentLevel + 1); + } else { + sb.append("fileAttributes: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileReadRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileReadRequest.java new file mode 100644 index 0000000..8a575ef --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileReadRequest.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import java.math.BigInteger; + +public class FileReadRequest extends Integer32 { + + private static final long serialVersionUID = 1L; + + public FileReadRequest() {} + + public FileReadRequest(byte[] code) { + super(code); + } + + public FileReadRequest(BigInteger value) { + super(value); + } + + public FileReadRequest(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileReadResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileReadResponse.java new file mode 100644 index 0000000..bf6a788 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FileReadResponse.java @@ -0,0 +1,176 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerOctetString; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class FileReadResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerOctetString fileData = null; + private BerBoolean moreFollows = null; + + public FileReadResponse() {} + + public FileReadResponse(byte[] code) { + this.code = code; + } + + public BerOctetString getFileData() { + return fileData; + } + + public void setFileData(BerOctetString fileData) { + this.fileData = fileData; + } + + public BerBoolean getMoreFollows() { + return moreFollows; + } + + public void setMoreFollows(BerBoolean moreFollows) { + this.moreFollows = moreFollows; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (moreFollows != null) { + codeLength += moreFollows.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + codeLength += fileData.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + fileData = new BerOctetString(); + vByteCount += fileData.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + moreFollows = new BerBoolean(); + vByteCount += moreFollows.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileData != null) { + sb.append("fileData: ").append(fileData); + } else { + sb.append("fileData: "); + } + + if (moreFollows != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("moreFollows: ").append(moreFollows); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FloatingPoint.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FloatingPoint.java new file mode 100644 index 0000000..5446e36 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/FloatingPoint.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerOctetString; + +public class FloatingPoint extends BerOctetString { + + private static final long serialVersionUID = 1L; + + public FloatingPoint() {} + + public FloatingPoint(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNameListRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNameListRequest.java new file mode 100644 index 0000000..1c0e27b --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNameListRequest.java @@ -0,0 +1,368 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class GetNameListRequest implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ObjectClass objectClass = null; + private ObjectScope objectScope = null; + private Identifier continueAfter = null; + + public GetNameListRequest() {} + + public GetNameListRequest(byte[] code) { + this.code = code; + } + + public ObjectClass getObjectClass() { + return objectClass; + } + + public void setObjectClass(ObjectClass objectClass) { + this.objectClass = objectClass; + } + + public ObjectScope getObjectScope() { + return objectScope; + } + + public void setObjectScope(ObjectScope objectScope) { + this.objectScope = objectScope; + } + + public Identifier getContinueAfter() { + return continueAfter; + } + + public void setContinueAfter(Identifier continueAfter) { + this.continueAfter = continueAfter; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + if (continueAfter != null) { + codeLength += continueAfter.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + } + + sublength = objectScope.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + sublength = objectClass.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + vByteCount += length.decode(is); + objectClass = new ObjectClass(); + vByteCount += objectClass.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + vByteCount += length.decode(is); + objectScope = new ObjectScope(); + vByteCount += objectScope.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + continueAfter = new Identifier(); + vByteCount += continueAfter.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (objectClass != null) { + sb.append("objectClass: "); + objectClass.appendAsString(sb, indentLevel + 1); + } else { + sb.append("objectClass: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (objectScope != null) { + sb.append("objectScope: "); + objectScope.appendAsString(sb, indentLevel + 1); + } else { + sb.append("objectScope: "); + } + + if (continueAfter != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("continueAfter: ").append(continueAfter); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ObjectScope implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerNull vmdSpecific = null; + private Identifier domainSpecific = null; + private BerNull aaSpecific = null; + + public ObjectScope() {} + + public ObjectScope(byte[] code) { + this.code = code; + } + + public BerNull getVmdSpecific() { + return vmdSpecific; + } + + public void setVmdSpecific(BerNull vmdSpecific) { + this.vmdSpecific = vmdSpecific; + } + + public Identifier getDomainSpecific() { + return domainSpecific; + } + + public void setDomainSpecific(Identifier domainSpecific) { + this.domainSpecific = domainSpecific; + } + + public BerNull getAaSpecific() { + return aaSpecific; + } + + public void setAaSpecific(BerNull aaSpecific) { + this.aaSpecific = aaSpecific; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (aaSpecific != null) { + codeLength += aaSpecific.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (domainSpecific != null) { + codeLength += domainSpecific.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (vmdSpecific != null) { + codeLength += vmdSpecific.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + vmdSpecific = new BerNull(); + tlvByteCount += vmdSpecific.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + domainSpecific = new Identifier(); + tlvByteCount += domainSpecific.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + aaSpecific = new BerNull(); + tlvByteCount += aaSpecific.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (vmdSpecific != null) { + sb.append("vmdSpecific: ").append(vmdSpecific); + return; + } + + if (domainSpecific != null) { + sb.append("domainSpecific: ").append(domainSpecific); + return; + } + + if (aaSpecific != null) { + sb.append("aaSpecific: ").append(aaSpecific); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNameListResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNameListResponse.java new file mode 100644 index 0000000..1508e81 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNameListResponse.java @@ -0,0 +1,315 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class GetNameListResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ListOfIdentifier listOfIdentifier = null; + private BerBoolean moreFollows = null; + + public GetNameListResponse() {} + + public GetNameListResponse(byte[] code) { + this.code = code; + } + + public ListOfIdentifier getListOfIdentifier() { + return listOfIdentifier; + } + + public void setListOfIdentifier(ListOfIdentifier listOfIdentifier) { + this.listOfIdentifier = listOfIdentifier; + } + + public BerBoolean getMoreFollows() { + return moreFollows; + } + + public void setMoreFollows(BerBoolean moreFollows) { + this.moreFollows = moreFollows; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (moreFollows != null) { + codeLength += moreFollows.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + codeLength += listOfIdentifier.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + listOfIdentifier = new ListOfIdentifier(); + vByteCount += listOfIdentifier.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + moreFollows = new BerBoolean(); + vByteCount += moreFollows.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (listOfIdentifier != null) { + sb.append("listOfIdentifier: "); + listOfIdentifier.appendAsString(sb, indentLevel + 1); + } else { + sb.append("listOfIdentifier: "); + } + + if (moreFollows != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("moreFollows: ").append(moreFollows); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ListOfIdentifier implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ListOfIdentifier() { + seqOf = new ArrayList(); + } + + public ListOfIdentifier(byte[] code) { + this.code = code; + } + + public List getIdentifier() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(Identifier.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + Identifier element = new Identifier(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + sb.append(it.next()); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append(it.next()); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNamedVariableListAttributesRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNamedVariableListAttributesRequest.java new file mode 100644 index 0000000..ff30386 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNamedVariableListAttributesRequest.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +public class GetNamedVariableListAttributesRequest extends ObjectName { + + private static final long serialVersionUID = 1L; + + public GetNamedVariableListAttributesRequest() {} + + public GetNamedVariableListAttributesRequest(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNamedVariableListAttributesResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNamedVariableListAttributesResponse.java new file mode 100644 index 0000000..261bd9b --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetNamedVariableListAttributesResponse.java @@ -0,0 +1,175 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class GetNamedVariableListAttributesResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerBoolean mmsDeletable = null; + private VariableDefs listOfVariable = null; + + public GetNamedVariableListAttributesResponse() {} + + public GetNamedVariableListAttributesResponse(byte[] code) { + this.code = code; + } + + public BerBoolean getMmsDeletable() { + return mmsDeletable; + } + + public void setMmsDeletable(BerBoolean mmsDeletable) { + this.mmsDeletable = mmsDeletable; + } + + public VariableDefs getListOfVariable() { + return listOfVariable; + } + + public void setListOfVariable(VariableDefs listOfVariable) { + this.listOfVariable = listOfVariable; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += listOfVariable.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + codeLength += mmsDeletable.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + mmsDeletable = new BerBoolean(); + vByteCount += mmsDeletable.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + listOfVariable = new VariableDefs(); + vByteCount += listOfVariable.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (mmsDeletable != null) { + sb.append("mmsDeletable: ").append(mmsDeletable); + } else { + sb.append("mmsDeletable: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (listOfVariable != null) { + sb.append("listOfVariable: "); + listOfVariable.appendAsString(sb, indentLevel + 1); + } else { + sb.append("listOfVariable: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetVariableAccessAttributesRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetVariableAccessAttributesRequest.java new file mode 100644 index 0000000..d77a126 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetVariableAccessAttributesRequest.java @@ -0,0 +1,115 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class GetVariableAccessAttributesRequest implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private ObjectName name = null; + + public GetVariableAccessAttributesRequest() {} + + public GetVariableAccessAttributesRequest(byte[] code) { + this.code = code; + } + + public ObjectName getName() { + return name; + } + + public void setName(ObjectName name) { + this.name = name; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (name != null) { + sublength = name.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + name = new ObjectName(); + tlvByteCount += name.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (name != null) { + sb.append("name: "); + name.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetVariableAccessAttributesResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetVariableAccessAttributesResponse.java new file mode 100644 index 0000000..ef3d91d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/GetVariableAccessAttributesResponse.java @@ -0,0 +1,181 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class GetVariableAccessAttributesResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerBoolean mmsDeletable = null; + private TypeDescription typeDescription = null; + + public GetVariableAccessAttributesResponse() {} + + public GetVariableAccessAttributesResponse(byte[] code) { + this.code = code; + } + + public BerBoolean getMmsDeletable() { + return mmsDeletable; + } + + public void setMmsDeletable(BerBoolean mmsDeletable) { + this.mmsDeletable = mmsDeletable; + } + + public TypeDescription getTypeDescription() { + return typeDescription; + } + + public void setTypeDescription(TypeDescription typeDescription) { + this.typeDescription = typeDescription; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + sublength = typeDescription.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + + codeLength += mmsDeletable.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + mmsDeletable = new BerBoolean(); + vByteCount += mmsDeletable.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + vByteCount += length.decode(is); + typeDescription = new TypeDescription(); + vByteCount += typeDescription.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (mmsDeletable != null) { + sb.append("mmsDeletable: ").append(mmsDeletable); + } else { + sb.append("mmsDeletable: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (typeDescription != null) { + sb.append("typeDescription: "); + typeDescription.appendAsString(sb, indentLevel + 1); + } else { + sb.append("typeDescription: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Identifier.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Identifier.java new file mode 100644 index 0000000..b995f14 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Identifier.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.string.BerVisibleString; + +public class Identifier extends BerVisibleString { + + private static final long serialVersionUID = 1L; + + public Identifier() {} + + public Identifier(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InformationReport.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InformationReport.java new file mode 100644 index 0000000..73cd471 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InformationReport.java @@ -0,0 +1,315 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class InformationReport implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private VariableAccessSpecification variableAccessSpecification = null; + private ListOfAccessResult listOfAccessResult = null; + + public InformationReport() {} + + public InformationReport(byte[] code) { + this.code = code; + } + + public VariableAccessSpecification getVariableAccessSpecification() { + return variableAccessSpecification; + } + + public void setVariableAccessSpecification( + VariableAccessSpecification variableAccessSpecification) { + this.variableAccessSpecification = variableAccessSpecification; + } + + public ListOfAccessResult getListOfAccessResult() { + return listOfAccessResult; + } + + public void setListOfAccessResult(ListOfAccessResult listOfAccessResult) { + this.listOfAccessResult = listOfAccessResult; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += listOfAccessResult.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += variableAccessSpecification.encode(reverseOS); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + variableAccessSpecification = new VariableAccessSpecification(); + numDecodedBytes = variableAccessSpecification.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + listOfAccessResult = new ListOfAccessResult(); + vByteCount += listOfAccessResult.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (variableAccessSpecification != null) { + sb.append("variableAccessSpecification: "); + variableAccessSpecification.appendAsString(sb, indentLevel + 1); + } else { + sb.append("variableAccessSpecification: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (listOfAccessResult != null) { + sb.append("listOfAccessResult: "); + listOfAccessResult.appendAsString(sb, indentLevel + 1); + } else { + sb.append("listOfAccessResult: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ListOfAccessResult implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ListOfAccessResult() { + seqOf = new ArrayList(); + } + + public ListOfAccessResult(byte[] code) { + this.code = code; + } + + public List getAccessResult() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + AccessResult element = new AccessResult(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateErrorPDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateErrorPDU.java new file mode 100644 index 0000000..f6bf083 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateErrorPDU.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +public class InitiateErrorPDU extends ServiceError { + + private static final long serialVersionUID = 1L; + + public InitiateErrorPDU() {} + + public InitiateErrorPDU(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateRequestPDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateRequestPDU.java new file mode 100644 index 0000000..2226bbe --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateRequestPDU.java @@ -0,0 +1,464 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class InitiateRequestPDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Integer32 localDetailCalling = null; + private Integer16 proposedMaxServOutstandingCalling = null; + private Integer16 proposedMaxServOutstandingCalled = null; + private Integer8 proposedDataStructureNestingLevel = null; + private InitRequestDetail initRequestDetail = null; + + public InitiateRequestPDU() {} + + public InitiateRequestPDU(byte[] code) { + this.code = code; + } + + public Integer32 getLocalDetailCalling() { + return localDetailCalling; + } + + public void setLocalDetailCalling(Integer32 localDetailCalling) { + this.localDetailCalling = localDetailCalling; + } + + public Integer16 getProposedMaxServOutstandingCalling() { + return proposedMaxServOutstandingCalling; + } + + public void setProposedMaxServOutstandingCalling(Integer16 proposedMaxServOutstandingCalling) { + this.proposedMaxServOutstandingCalling = proposedMaxServOutstandingCalling; + } + + public Integer16 getProposedMaxServOutstandingCalled() { + return proposedMaxServOutstandingCalled; + } + + public void setProposedMaxServOutstandingCalled(Integer16 proposedMaxServOutstandingCalled) { + this.proposedMaxServOutstandingCalled = proposedMaxServOutstandingCalled; + } + + public Integer8 getProposedDataStructureNestingLevel() { + return proposedDataStructureNestingLevel; + } + + public void setProposedDataStructureNestingLevel(Integer8 proposedDataStructureNestingLevel) { + this.proposedDataStructureNestingLevel = proposedDataStructureNestingLevel; + } + + public InitRequestDetail getInitRequestDetail() { + return initRequestDetail; + } + + public void setInitRequestDetail(InitRequestDetail initRequestDetail) { + this.initRequestDetail = initRequestDetail; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += initRequestDetail.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + + if (proposedDataStructureNestingLevel != null) { + codeLength += proposedDataStructureNestingLevel.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + } + + codeLength += proposedMaxServOutstandingCalled.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + + codeLength += proposedMaxServOutstandingCalling.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + if (localDetailCalling != null) { + codeLength += localDetailCalling.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + localDetailCalling = new Integer32(); + vByteCount += localDetailCalling.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + proposedMaxServOutstandingCalling = new Integer16(); + vByteCount += proposedMaxServOutstandingCalling.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + proposedMaxServOutstandingCalled = new Integer16(); + vByteCount += proposedMaxServOutstandingCalled.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + proposedDataStructureNestingLevel = new Integer8(); + vByteCount += proposedDataStructureNestingLevel.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + initRequestDetail = new InitRequestDetail(); + vByteCount += initRequestDetail.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (localDetailCalling != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("localDetailCalling: ").append(localDetailCalling); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (proposedMaxServOutstandingCalling != null) { + sb.append("proposedMaxServOutstandingCalling: ").append(proposedMaxServOutstandingCalling); + } else { + sb.append("proposedMaxServOutstandingCalling: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (proposedMaxServOutstandingCalled != null) { + sb.append("proposedMaxServOutstandingCalled: ").append(proposedMaxServOutstandingCalled); + } else { + sb.append("proposedMaxServOutstandingCalled: "); + } + + if (proposedDataStructureNestingLevel != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("proposedDataStructureNestingLevel: ").append(proposedDataStructureNestingLevel); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (initRequestDetail != null) { + sb.append("initRequestDetail: "); + initRequestDetail.appendAsString(sb, indentLevel + 1); + } else { + sb.append("initRequestDetail: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class InitRequestDetail implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Integer16 proposedVersionNumber = null; + private ParameterSupportOptions proposedParameterCBB = null; + private ServiceSupportOptions servicesSupportedCalling = null; + + public InitRequestDetail() {} + + public InitRequestDetail(byte[] code) { + this.code = code; + } + + public Integer16 getProposedVersionNumber() { + return proposedVersionNumber; + } + + public void setProposedVersionNumber(Integer16 proposedVersionNumber) { + this.proposedVersionNumber = proposedVersionNumber; + } + + public ParameterSupportOptions getProposedParameterCBB() { + return proposedParameterCBB; + } + + public void setProposedParameterCBB(ParameterSupportOptions proposedParameterCBB) { + this.proposedParameterCBB = proposedParameterCBB; + } + + public ServiceSupportOptions getServicesSupportedCalling() { + return servicesSupportedCalling; + } + + public void setServicesSupportedCalling(ServiceSupportOptions servicesSupportedCalling) { + this.servicesSupportedCalling = servicesSupportedCalling; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += servicesSupportedCalling.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + + codeLength += proposedParameterCBB.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + codeLength += proposedVersionNumber.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + proposedVersionNumber = new Integer16(); + vByteCount += proposedVersionNumber.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + proposedParameterCBB = new ParameterSupportOptions(); + vByteCount += proposedParameterCBB.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + servicesSupportedCalling = new ServiceSupportOptions(); + vByteCount += servicesSupportedCalling.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (proposedVersionNumber != null) { + sb.append("proposedVersionNumber: ").append(proposedVersionNumber); + } else { + sb.append("proposedVersionNumber: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (proposedParameterCBB != null) { + sb.append("proposedParameterCBB: ").append(proposedParameterCBB); + } else { + sb.append("proposedParameterCBB: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (servicesSupportedCalling != null) { + sb.append("servicesSupportedCalling: ").append(servicesSupportedCalling); + } else { + sb.append("servicesSupportedCalling: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateResponsePDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateResponsePDU.java new file mode 100644 index 0000000..d31e639 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/InitiateResponsePDU.java @@ -0,0 +1,467 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class InitiateResponsePDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Integer32 localDetailCalled = null; + private Integer16 negotiatedMaxServOutstandingCalling = null; + private Integer16 negotiatedMaxServOutstandingCalled = null; + private Integer8 negotiatedDataStructureNestingLevel = null; + private InitResponseDetail initResponseDetail = null; + + public InitiateResponsePDU() {} + + public InitiateResponsePDU(byte[] code) { + this.code = code; + } + + public Integer32 getLocalDetailCalled() { + return localDetailCalled; + } + + public void setLocalDetailCalled(Integer32 localDetailCalled) { + this.localDetailCalled = localDetailCalled; + } + + public Integer16 getNegotiatedMaxServOutstandingCalling() { + return negotiatedMaxServOutstandingCalling; + } + + public void setNegotiatedMaxServOutstandingCalling( + Integer16 negotiatedMaxServOutstandingCalling) { + this.negotiatedMaxServOutstandingCalling = negotiatedMaxServOutstandingCalling; + } + + public Integer16 getNegotiatedMaxServOutstandingCalled() { + return negotiatedMaxServOutstandingCalled; + } + + public void setNegotiatedMaxServOutstandingCalled(Integer16 negotiatedMaxServOutstandingCalled) { + this.negotiatedMaxServOutstandingCalled = negotiatedMaxServOutstandingCalled; + } + + public Integer8 getNegotiatedDataStructureNestingLevel() { + return negotiatedDataStructureNestingLevel; + } + + public void setNegotiatedDataStructureNestingLevel(Integer8 negotiatedDataStructureNestingLevel) { + this.negotiatedDataStructureNestingLevel = negotiatedDataStructureNestingLevel; + } + + public InitResponseDetail getInitResponseDetail() { + return initResponseDetail; + } + + public void setInitResponseDetail(InitResponseDetail initResponseDetail) { + this.initResponseDetail = initResponseDetail; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += initResponseDetail.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + + if (negotiatedDataStructureNestingLevel != null) { + codeLength += negotiatedDataStructureNestingLevel.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + } + + codeLength += negotiatedMaxServOutstandingCalled.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + + codeLength += negotiatedMaxServOutstandingCalling.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + if (localDetailCalled != null) { + codeLength += localDetailCalled.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + localDetailCalled = new Integer32(); + vByteCount += localDetailCalled.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + negotiatedMaxServOutstandingCalling = new Integer16(); + vByteCount += negotiatedMaxServOutstandingCalling.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + negotiatedMaxServOutstandingCalled = new Integer16(); + vByteCount += negotiatedMaxServOutstandingCalled.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + negotiatedDataStructureNestingLevel = new Integer8(); + vByteCount += negotiatedDataStructureNestingLevel.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + initResponseDetail = new InitResponseDetail(); + vByteCount += initResponseDetail.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (localDetailCalled != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("localDetailCalled: ").append(localDetailCalled); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (negotiatedMaxServOutstandingCalling != null) { + sb.append("negotiatedMaxServOutstandingCalling: ") + .append(negotiatedMaxServOutstandingCalling); + } else { + sb.append("negotiatedMaxServOutstandingCalling: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (negotiatedMaxServOutstandingCalled != null) { + sb.append("negotiatedMaxServOutstandingCalled: ").append(negotiatedMaxServOutstandingCalled); + } else { + sb.append("negotiatedMaxServOutstandingCalled: "); + } + + if (negotiatedDataStructureNestingLevel != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("negotiatedDataStructureNestingLevel: ") + .append(negotiatedDataStructureNestingLevel); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (initResponseDetail != null) { + sb.append("initResponseDetail: "); + initResponseDetail.appendAsString(sb, indentLevel + 1); + } else { + sb.append("initResponseDetail: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class InitResponseDetail implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Integer16 negotiatedVersionNumber = null; + private ParameterSupportOptions negotiatedParameterCBB = null; + private ServiceSupportOptions servicesSupportedCalled = null; + + public InitResponseDetail() {} + + public InitResponseDetail(byte[] code) { + this.code = code; + } + + public Integer16 getNegotiatedVersionNumber() { + return negotiatedVersionNumber; + } + + public void setNegotiatedVersionNumber(Integer16 negotiatedVersionNumber) { + this.negotiatedVersionNumber = negotiatedVersionNumber; + } + + public ParameterSupportOptions getNegotiatedParameterCBB() { + return negotiatedParameterCBB; + } + + public void setNegotiatedParameterCBB(ParameterSupportOptions negotiatedParameterCBB) { + this.negotiatedParameterCBB = negotiatedParameterCBB; + } + + public ServiceSupportOptions getServicesSupportedCalled() { + return servicesSupportedCalled; + } + + public void setServicesSupportedCalled(ServiceSupportOptions servicesSupportedCalled) { + this.servicesSupportedCalled = servicesSupportedCalled; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += servicesSupportedCalled.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + + codeLength += negotiatedParameterCBB.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + codeLength += negotiatedVersionNumber.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + negotiatedVersionNumber = new Integer16(); + vByteCount += negotiatedVersionNumber.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + negotiatedParameterCBB = new ParameterSupportOptions(); + vByteCount += negotiatedParameterCBB.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + servicesSupportedCalled = new ServiceSupportOptions(); + vByteCount += servicesSupportedCalled.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (negotiatedVersionNumber != null) { + sb.append("negotiatedVersionNumber: ").append(negotiatedVersionNumber); + } else { + sb.append("negotiatedVersionNumber: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (negotiatedParameterCBB != null) { + sb.append("negotiatedParameterCBB: ").append(negotiatedParameterCBB); + } else { + sb.append("negotiatedParameterCBB: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (servicesSupportedCalled != null) { + sb.append("servicesSupportedCalled: ").append(servicesSupportedCalled); + } else { + sb.append("servicesSupportedCalled: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer16.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer16.java new file mode 100644 index 0000000..20a43a8 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer16.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class Integer16 extends BerInteger { + + private static final long serialVersionUID = 1L; + + public Integer16() {} + + public Integer16(byte[] code) { + super(code); + } + + public Integer16(BigInteger value) { + super(value); + } + + public Integer16(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer32.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer32.java new file mode 100644 index 0000000..e3d9c6d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer32.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class Integer32 extends BerInteger { + + private static final long serialVersionUID = 1L; + + public Integer32() {} + + public Integer32(byte[] code) { + super(code); + } + + public Integer32(BigInteger value) { + super(value); + } + + public Integer32(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer8.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer8.java new file mode 100644 index 0000000..8c991ea --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Integer8.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class Integer8 extends BerInteger { + + private static final long serialVersionUID = 1L; + + public Integer8() {} + + public Integer8(byte[] code) { + super(code); + } + + public Integer8(BigInteger value) { + super(value); + } + + public Integer8(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/MMSString.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/MMSString.java new file mode 100644 index 0000000..0bf4673 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/MMSString.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.string.BerVisibleString; + +public class MMSString extends BerVisibleString { + + private static final long serialVersionUID = 1L; + + public MMSString() {} + + public MMSString(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/MMSpdu.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/MMSpdu.java new file mode 100644 index 0000000..96b0cc4 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/MMSpdu.java @@ -0,0 +1,338 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class MMSpdu implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private ConfirmedRequestPDU confirmedRequestPDU = null; + private ConfirmedResponsePDU confirmedResponsePDU = null; + private ConfirmedErrorPDU confirmedErrorPDU = null; + private UnconfirmedPDU unconfirmedPDU = null; + private RejectPDU rejectPDU = null; + private InitiateRequestPDU initiateRequestPDU = null; + private InitiateResponsePDU initiateResponsePDU = null; + private InitiateErrorPDU initiateErrorPDU = null; + private ConcludeRequestPDU concludeRequestPDU = null; + + public MMSpdu() {} + + public MMSpdu(byte[] code) { + this.code = code; + } + + public ConfirmedRequestPDU getConfirmedRequestPDU() { + return confirmedRequestPDU; + } + + public void setConfirmedRequestPDU(ConfirmedRequestPDU confirmedRequestPDU) { + this.confirmedRequestPDU = confirmedRequestPDU; + } + + public ConfirmedResponsePDU getConfirmedResponsePDU() { + return confirmedResponsePDU; + } + + public void setConfirmedResponsePDU(ConfirmedResponsePDU confirmedResponsePDU) { + this.confirmedResponsePDU = confirmedResponsePDU; + } + + public ConfirmedErrorPDU getConfirmedErrorPDU() { + return confirmedErrorPDU; + } + + public void setConfirmedErrorPDU(ConfirmedErrorPDU confirmedErrorPDU) { + this.confirmedErrorPDU = confirmedErrorPDU; + } + + public UnconfirmedPDU getUnconfirmedPDU() { + return unconfirmedPDU; + } + + public void setUnconfirmedPDU(UnconfirmedPDU unconfirmedPDU) { + this.unconfirmedPDU = unconfirmedPDU; + } + + public RejectPDU getRejectPDU() { + return rejectPDU; + } + + public void setRejectPDU(RejectPDU rejectPDU) { + this.rejectPDU = rejectPDU; + } + + public InitiateRequestPDU getInitiateRequestPDU() { + return initiateRequestPDU; + } + + public void setInitiateRequestPDU(InitiateRequestPDU initiateRequestPDU) { + this.initiateRequestPDU = initiateRequestPDU; + } + + public InitiateResponsePDU getInitiateResponsePDU() { + return initiateResponsePDU; + } + + public void setInitiateResponsePDU(InitiateResponsePDU initiateResponsePDU) { + this.initiateResponsePDU = initiateResponsePDU; + } + + public InitiateErrorPDU getInitiateErrorPDU() { + return initiateErrorPDU; + } + + public void setInitiateErrorPDU(InitiateErrorPDU initiateErrorPDU) { + this.initiateErrorPDU = initiateErrorPDU; + } + + public ConcludeRequestPDU getConcludeRequestPDU() { + return concludeRequestPDU; + } + + public void setConcludeRequestPDU(ConcludeRequestPDU concludeRequestPDU) { + this.concludeRequestPDU = concludeRequestPDU; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (concludeRequestPDU != null) { + codeLength += concludeRequestPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 11 + reverseOS.write(0x8B); + codeLength += 1; + return codeLength; + } + + if (initiateErrorPDU != null) { + codeLength += initiateErrorPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 10 + reverseOS.write(0xAA); + codeLength += 1; + return codeLength; + } + + if (initiateResponsePDU != null) { + codeLength += initiateResponsePDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 9 + reverseOS.write(0xA9); + codeLength += 1; + return codeLength; + } + + if (initiateRequestPDU != null) { + codeLength += initiateRequestPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 8 + reverseOS.write(0xA8); + codeLength += 1; + return codeLength; + } + + if (rejectPDU != null) { + codeLength += rejectPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + return codeLength; + } + + if (unconfirmedPDU != null) { + codeLength += unconfirmedPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 3 + reverseOS.write(0xA3); + codeLength += 1; + return codeLength; + } + + if (confirmedErrorPDU != null) { + codeLength += confirmedErrorPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + return codeLength; + } + + if (confirmedResponsePDU != null) { + codeLength += confirmedResponsePDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + if (confirmedRequestPDU != null) { + codeLength += confirmedRequestPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + confirmedRequestPDU = new ConfirmedRequestPDU(); + tlvByteCount += confirmedRequestPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + confirmedResponsePDU = new ConfirmedResponsePDU(); + tlvByteCount += confirmedResponsePDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + confirmedErrorPDU = new ConfirmedErrorPDU(); + tlvByteCount += confirmedErrorPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 3)) { + unconfirmedPDU = new UnconfirmedPDU(); + tlvByteCount += unconfirmedPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + rejectPDU = new RejectPDU(); + tlvByteCount += rejectPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 8)) { + initiateRequestPDU = new InitiateRequestPDU(); + tlvByteCount += initiateRequestPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 9)) { + initiateResponsePDU = new InitiateResponsePDU(); + tlvByteCount += initiateResponsePDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 10)) { + initiateErrorPDU = new InitiateErrorPDU(); + tlvByteCount += initiateErrorPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 11)) { + concludeRequestPDU = new ConcludeRequestPDU(); + tlvByteCount += concludeRequestPDU.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (confirmedRequestPDU != null) { + sb.append("confirmedRequestPDU: "); + confirmedRequestPDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (confirmedResponsePDU != null) { + sb.append("confirmedResponsePDU: "); + confirmedResponsePDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (confirmedErrorPDU != null) { + sb.append("confirmedErrorPDU: "); + confirmedErrorPDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (unconfirmedPDU != null) { + sb.append("unconfirmedPDU: "); + unconfirmedPDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (rejectPDU != null) { + sb.append("rejectPDU: "); + rejectPDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (initiateRequestPDU != null) { + sb.append("initiateRequestPDU: "); + initiateRequestPDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (initiateResponsePDU != null) { + sb.append("initiateResponsePDU: "); + initiateResponsePDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (initiateErrorPDU != null) { + sb.append("initiateErrorPDU: "); + initiateErrorPDU.appendAsString(sb, indentLevel + 1); + return; + } + + if (concludeRequestPDU != null) { + sb.append("concludeRequestPDU: ").append(concludeRequestPDU); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ObjectClass.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ObjectClass.java new file mode 100644 index 0000000..13734dd --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ObjectClass.java @@ -0,0 +1,107 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ObjectClass implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerInteger basicObjectClass = null; + + public ObjectClass() {} + + public ObjectClass(byte[] code) { + this.code = code; + } + + public BerInteger getBasicObjectClass() { + return basicObjectClass; + } + + public void setBasicObjectClass(BerInteger basicObjectClass) { + this.basicObjectClass = basicObjectClass; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (basicObjectClass != null) { + codeLength += basicObjectClass.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + basicObjectClass = new BerInteger(); + tlvByteCount += basicObjectClass.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (basicObjectClass != null) { + sb.append("basicObjectClass: ").append(basicObjectClass); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ObjectName.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ObjectName.java new file mode 100644 index 0000000..3ff3d84 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ObjectName.java @@ -0,0 +1,320 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ObjectName implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private Identifier vmdSpecific = null; + private DomainSpecific domainSpecific = null; + private Identifier aaSpecific = null; + + public ObjectName() {} + + public ObjectName(byte[] code) { + this.code = code; + } + + public Identifier getVmdSpecific() { + return vmdSpecific; + } + + public void setVmdSpecific(Identifier vmdSpecific) { + this.vmdSpecific = vmdSpecific; + } + + public DomainSpecific getDomainSpecific() { + return domainSpecific; + } + + public void setDomainSpecific(DomainSpecific domainSpecific) { + this.domainSpecific = domainSpecific; + } + + public Identifier getAaSpecific() { + return aaSpecific; + } + + public void setAaSpecific(Identifier aaSpecific) { + this.aaSpecific = aaSpecific; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (aaSpecific != null) { + codeLength += aaSpecific.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (domainSpecific != null) { + codeLength += domainSpecific.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + if (vmdSpecific != null) { + codeLength += vmdSpecific.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + vmdSpecific = new Identifier(); + tlvByteCount += vmdSpecific.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + domainSpecific = new DomainSpecific(); + tlvByteCount += domainSpecific.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + aaSpecific = new Identifier(); + tlvByteCount += aaSpecific.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (vmdSpecific != null) { + sb.append("vmdSpecific: ").append(vmdSpecific); + return; + } + + if (domainSpecific != null) { + sb.append("domainSpecific: "); + domainSpecific.appendAsString(sb, indentLevel + 1); + return; + } + + if (aaSpecific != null) { + sb.append("aaSpecific: ").append(aaSpecific); + return; + } + + sb.append(""); + } + + public static class DomainSpecific implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Identifier domainID = null; + private Identifier itemID = null; + + public DomainSpecific() {} + + public DomainSpecific(byte[] code) { + this.code = code; + } + + public Identifier getDomainID() { + return domainID; + } + + public void setDomainID(Identifier domainID) { + this.domainID = domainID; + } + + public Identifier getItemID() { + return itemID; + } + + public void setItemID(Identifier itemID) { + this.itemID = itemID; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += itemID.encode(reverseOS, true); + + codeLength += domainID.encode(reverseOS, true); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(Identifier.tag)) { + domainID = new Identifier(); + vByteCount += domainID.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(Identifier.tag)) { + itemID = new Identifier(); + vByteCount += itemID.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (domainID != null) { + sb.append("domainID: ").append(domainID); + } else { + sb.append("domainID: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (itemID != null) { + sb.append("itemID: ").append(itemID); + } else { + sb.append("itemID: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ParameterSupportOptions.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ParameterSupportOptions.java new file mode 100644 index 0000000..d703890 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ParameterSupportOptions.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerBitString; + +public class ParameterSupportOptions extends BerBitString { + + private static final long serialVersionUID = 1L; + + public ParameterSupportOptions() {} + + public ParameterSupportOptions(byte[] code) { + super(code); + } + + public ParameterSupportOptions(byte[] value, int numBits) { + super(value, numBits); + } + + public ParameterSupportOptions(boolean[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ReadRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ReadRequest.java new file mode 100644 index 0000000..e537027 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ReadRequest.java @@ -0,0 +1,184 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ReadRequest implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerBoolean specificationWithResult = null; + private VariableAccessSpecification variableAccessSpecification = null; + + public ReadRequest() {} + + public ReadRequest(byte[] code) { + this.code = code; + } + + public BerBoolean getSpecificationWithResult() { + return specificationWithResult; + } + + public void setSpecificationWithResult(BerBoolean specificationWithResult) { + this.specificationWithResult = specificationWithResult; + } + + public VariableAccessSpecification getVariableAccessSpecification() { + return variableAccessSpecification; + } + + public void setVariableAccessSpecification( + VariableAccessSpecification variableAccessSpecification) { + this.variableAccessSpecification = variableAccessSpecification; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + sublength = variableAccessSpecification.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + if (specificationWithResult != null) { + codeLength += specificationWithResult.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + specificationWithResult = new BerBoolean(); + vByteCount += specificationWithResult.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + vByteCount += length.decode(is); + variableAccessSpecification = new VariableAccessSpecification(); + vByteCount += variableAccessSpecification.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (specificationWithResult != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("specificationWithResult: ").append(specificationWithResult); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (variableAccessSpecification != null) { + sb.append("variableAccessSpecification: "); + variableAccessSpecification.appendAsString(sb, indentLevel + 1); + } else { + sb.append("variableAccessSpecification: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ReadResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ReadResponse.java new file mode 100644 index 0000000..03218db --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ReadResponse.java @@ -0,0 +1,325 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ReadResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private VariableAccessSpecification variableAccessSpecification = null; + private ListOfAccessResult listOfAccessResult = null; + + public ReadResponse() {} + + public ReadResponse(byte[] code) { + this.code = code; + } + + public VariableAccessSpecification getVariableAccessSpecification() { + return variableAccessSpecification; + } + + public void setVariableAccessSpecification( + VariableAccessSpecification variableAccessSpecification) { + this.variableAccessSpecification = variableAccessSpecification; + } + + public ListOfAccessResult getListOfAccessResult() { + return listOfAccessResult; + } + + public void setListOfAccessResult(ListOfAccessResult listOfAccessResult) { + this.listOfAccessResult = listOfAccessResult; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + codeLength += listOfAccessResult.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + if (variableAccessSpecification != null) { + sublength = variableAccessSpecification.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + vByteCount += length.decode(is); + variableAccessSpecification = new VariableAccessSpecification(); + vByteCount += variableAccessSpecification.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + listOfAccessResult = new ListOfAccessResult(); + vByteCount += listOfAccessResult.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (variableAccessSpecification != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("variableAccessSpecification: "); + variableAccessSpecification.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (listOfAccessResult != null) { + sb.append("listOfAccessResult: "); + listOfAccessResult.appendAsString(sb, indentLevel + 1); + } else { + sb.append("listOfAccessResult: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ListOfAccessResult implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ListOfAccessResult() { + seqOf = new ArrayList(); + } + + public ListOfAccessResult(byte[] code) { + this.code = code; + } + + public List getAccessResult() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + AccessResult element = new AccessResult(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/RejectPDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/RejectPDU.java new file mode 100644 index 0000000..d3e621c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/RejectPDU.java @@ -0,0 +1,548 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class RejectPDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned32 originalInvokeID = null; + private RejectReason rejectReason = null; + + public RejectPDU() {} + + public RejectPDU(byte[] code) { + this.code = code; + } + + public Unsigned32 getOriginalInvokeID() { + return originalInvokeID; + } + + public void setOriginalInvokeID(Unsigned32 originalInvokeID) { + this.originalInvokeID = originalInvokeID; + } + + public RejectReason getRejectReason() { + return rejectReason; + } + + public void setRejectReason(RejectReason rejectReason) { + this.rejectReason = rejectReason; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += rejectReason.encode(reverseOS); + + if (originalInvokeID != null) { + codeLength += originalInvokeID.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + originalInvokeID = new Unsigned32(); + vByteCount += originalInvokeID.decode(is, false); + vByteCount += berTag.decode(is); + } + + rejectReason = new RejectReason(); + numDecodedBytes = rejectReason.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (originalInvokeID != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("originalInvokeID: ").append(originalInvokeID); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (rejectReason != null) { + sb.append("rejectReason: "); + rejectReason.appendAsString(sb, indentLevel + 1); + } else { + sb.append("rejectReason: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class RejectReason implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerInteger confirmedRequestPDU = null; + private BerInteger confirmedResponsePDU = null; + private BerInteger confirmedErrorPDU = null; + private BerInteger unconfirmedPDU = null; + private BerInteger pduError = null; + private BerInteger cancelRequestPDU = null; + private BerInteger cancelResponsePDU = null; + private BerInteger cancelErrorPDU = null; + private BerInteger concludeRequestPDU = null; + private BerInteger concludeResponsePDU = null; + private BerInteger concludeErrorPDU = null; + + public RejectReason() {} + + public RejectReason(byte[] code) { + this.code = code; + } + + public BerInteger getConfirmedRequestPDU() { + return confirmedRequestPDU; + } + + public void setConfirmedRequestPDU(BerInteger confirmedRequestPDU) { + this.confirmedRequestPDU = confirmedRequestPDU; + } + + public BerInteger getConfirmedResponsePDU() { + return confirmedResponsePDU; + } + + public void setConfirmedResponsePDU(BerInteger confirmedResponsePDU) { + this.confirmedResponsePDU = confirmedResponsePDU; + } + + public BerInteger getConfirmedErrorPDU() { + return confirmedErrorPDU; + } + + public void setConfirmedErrorPDU(BerInteger confirmedErrorPDU) { + this.confirmedErrorPDU = confirmedErrorPDU; + } + + public BerInteger getUnconfirmedPDU() { + return unconfirmedPDU; + } + + public void setUnconfirmedPDU(BerInteger unconfirmedPDU) { + this.unconfirmedPDU = unconfirmedPDU; + } + + public BerInteger getPduError() { + return pduError; + } + + public void setPduError(BerInteger pduError) { + this.pduError = pduError; + } + + public BerInteger getCancelRequestPDU() { + return cancelRequestPDU; + } + + public void setCancelRequestPDU(BerInteger cancelRequestPDU) { + this.cancelRequestPDU = cancelRequestPDU; + } + + public BerInteger getCancelResponsePDU() { + return cancelResponsePDU; + } + + public void setCancelResponsePDU(BerInteger cancelResponsePDU) { + this.cancelResponsePDU = cancelResponsePDU; + } + + public BerInteger getCancelErrorPDU() { + return cancelErrorPDU; + } + + public void setCancelErrorPDU(BerInteger cancelErrorPDU) { + this.cancelErrorPDU = cancelErrorPDU; + } + + public BerInteger getConcludeRequestPDU() { + return concludeRequestPDU; + } + + public void setConcludeRequestPDU(BerInteger concludeRequestPDU) { + this.concludeRequestPDU = concludeRequestPDU; + } + + public BerInteger getConcludeResponsePDU() { + return concludeResponsePDU; + } + + public void setConcludeResponsePDU(BerInteger concludeResponsePDU) { + this.concludeResponsePDU = concludeResponsePDU; + } + + public BerInteger getConcludeErrorPDU() { + return concludeErrorPDU; + } + + public void setConcludeErrorPDU(BerInteger concludeErrorPDU) { + this.concludeErrorPDU = concludeErrorPDU; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (concludeErrorPDU != null) { + codeLength += concludeErrorPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 11 + reverseOS.write(0x8B); + codeLength += 1; + return codeLength; + } + + if (concludeResponsePDU != null) { + codeLength += concludeResponsePDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 10 + reverseOS.write(0x8A); + codeLength += 1; + return codeLength; + } + + if (concludeRequestPDU != null) { + codeLength += concludeRequestPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 9 + reverseOS.write(0x89); + codeLength += 1; + return codeLength; + } + + if (cancelErrorPDU != null) { + codeLength += cancelErrorPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 8 + reverseOS.write(0x88); + codeLength += 1; + return codeLength; + } + + if (cancelResponsePDU != null) { + codeLength += cancelResponsePDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 7 + reverseOS.write(0x87); + codeLength += 1; + return codeLength; + } + + if (cancelRequestPDU != null) { + codeLength += cancelRequestPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 6 + reverseOS.write(0x86); + codeLength += 1; + return codeLength; + } + + if (pduError != null) { + codeLength += pduError.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 5 + reverseOS.write(0x85); + codeLength += 1; + return codeLength; + } + + if (unconfirmedPDU != null) { + codeLength += unconfirmedPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 4 + reverseOS.write(0x84); + codeLength += 1; + return codeLength; + } + + if (confirmedErrorPDU != null) { + codeLength += confirmedErrorPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + return codeLength; + } + + if (confirmedResponsePDU != null) { + codeLength += confirmedResponsePDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (confirmedRequestPDU != null) { + codeLength += confirmedRequestPDU.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + confirmedRequestPDU = new BerInteger(); + tlvByteCount += confirmedRequestPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + confirmedResponsePDU = new BerInteger(); + tlvByteCount += confirmedResponsePDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + confirmedErrorPDU = new BerInteger(); + tlvByteCount += confirmedErrorPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 4)) { + unconfirmedPDU = new BerInteger(); + tlvByteCount += unconfirmedPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 5)) { + pduError = new BerInteger(); + tlvByteCount += pduError.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 6)) { + cancelRequestPDU = new BerInteger(); + tlvByteCount += cancelRequestPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 7)) { + cancelResponsePDU = new BerInteger(); + tlvByteCount += cancelResponsePDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 8)) { + cancelErrorPDU = new BerInteger(); + tlvByteCount += cancelErrorPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 9)) { + concludeRequestPDU = new BerInteger(); + tlvByteCount += concludeRequestPDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 10)) { + concludeResponsePDU = new BerInteger(); + tlvByteCount += concludeResponsePDU.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 11)) { + concludeErrorPDU = new BerInteger(); + tlvByteCount += concludeErrorPDU.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (confirmedRequestPDU != null) { + sb.append("confirmedRequestPDU: ").append(confirmedRequestPDU); + return; + } + + if (confirmedResponsePDU != null) { + sb.append("confirmedResponsePDU: ").append(confirmedResponsePDU); + return; + } + + if (confirmedErrorPDU != null) { + sb.append("confirmedErrorPDU: ").append(confirmedErrorPDU); + return; + } + + if (unconfirmedPDU != null) { + sb.append("unconfirmedPDU: ").append(unconfirmedPDU); + return; + } + + if (pduError != null) { + sb.append("pduError: ").append(pduError); + return; + } + + if (cancelRequestPDU != null) { + sb.append("cancelRequestPDU: ").append(cancelRequestPDU); + return; + } + + if (cancelResponsePDU != null) { + sb.append("cancelResponsePDU: ").append(cancelResponsePDU); + return; + } + + if (cancelErrorPDU != null) { + sb.append("cancelErrorPDU: ").append(cancelErrorPDU); + return; + } + + if (concludeRequestPDU != null) { + sb.append("concludeRequestPDU: ").append(concludeRequestPDU); + return; + } + + if (concludeResponsePDU != null) { + sb.append("concludeResponsePDU: ").append(concludeResponsePDU); + return; + } + + if (concludeErrorPDU != null) { + sb.append("concludeErrorPDU: ").append(concludeErrorPDU); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ServiceError.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ServiceError.java new file mode 100644 index 0000000..ef7df0f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ServiceError.java @@ -0,0 +1,645 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.asn1bean.ber.types.string.BerVisibleString; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ServiceError implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ErrorClass errorClass = null; + private BerInteger additionalCode = null; + private BerVisibleString additionalDescription = null; + + public ServiceError() {} + + public ServiceError(byte[] code) { + this.code = code; + } + + public ErrorClass getErrorClass() { + return errorClass; + } + + public void setErrorClass(ErrorClass errorClass) { + this.errorClass = errorClass; + } + + public BerInteger getAdditionalCode() { + return additionalCode; + } + + public void setAdditionalCode(BerInteger additionalCode) { + this.additionalCode = additionalCode; + } + + public BerVisibleString getAdditionalDescription() { + return additionalDescription; + } + + public void setAdditionalDescription(BerVisibleString additionalDescription) { + this.additionalDescription = additionalDescription; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + if (additionalDescription != null) { + codeLength += additionalDescription.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + } + + if (additionalCode != null) { + codeLength += additionalCode.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + sublength = errorClass.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + vByteCount += length.decode(is); + errorClass = new ErrorClass(); + vByteCount += errorClass.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + additionalCode = new BerInteger(); + vByteCount += additionalCode.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + additionalDescription = new BerVisibleString(); + vByteCount += additionalDescription.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (errorClass != null) { + sb.append("errorClass: "); + errorClass.appendAsString(sb, indentLevel + 1); + } else { + sb.append("errorClass: "); + } + + if (additionalCode != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("additionalCode: ").append(additionalCode); + } + + if (additionalDescription != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("additionalDescription: ").append(additionalDescription); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ErrorClass implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerInteger vmdState = null; + private BerInteger applicationReference = null; + private BerInteger definition = null; + private BerInteger resource = null; + private BerInteger service = null; + private BerInteger servicePreempt = null; + private BerInteger timeResolution = null; + private BerInteger access = null; + private BerInteger initiate = null; + private BerInteger conclude = null; + private BerInteger cancel = null; + private BerInteger file = null; + private BerInteger others = null; + + public ErrorClass() {} + + public ErrorClass(byte[] code) { + this.code = code; + } + + public BerInteger getVmdState() { + return vmdState; + } + + public void setVmdState(BerInteger vmdState) { + this.vmdState = vmdState; + } + + public BerInteger getApplicationReference() { + return applicationReference; + } + + public void setApplicationReference(BerInteger applicationReference) { + this.applicationReference = applicationReference; + } + + public BerInteger getDefinition() { + return definition; + } + + public void setDefinition(BerInteger definition) { + this.definition = definition; + } + + public BerInteger getResource() { + return resource; + } + + public void setResource(BerInteger resource) { + this.resource = resource; + } + + public BerInteger getService() { + return service; + } + + public void setService(BerInteger service) { + this.service = service; + } + + public BerInteger getServicePreempt() { + return servicePreempt; + } + + public void setServicePreempt(BerInteger servicePreempt) { + this.servicePreempt = servicePreempt; + } + + public BerInteger getTimeResolution() { + return timeResolution; + } + + public void setTimeResolution(BerInteger timeResolution) { + this.timeResolution = timeResolution; + } + + public BerInteger getAccess() { + return access; + } + + public void setAccess(BerInteger access) { + this.access = access; + } + + public BerInteger getInitiate() { + return initiate; + } + + public void setInitiate(BerInteger initiate) { + this.initiate = initiate; + } + + public BerInteger getConclude() { + return conclude; + } + + public void setConclude(BerInteger conclude) { + this.conclude = conclude; + } + + public BerInteger getCancel() { + return cancel; + } + + public void setCancel(BerInteger cancel) { + this.cancel = cancel; + } + + public BerInteger getFile() { + return file; + } + + public void setFile(BerInteger file) { + this.file = file; + } + + public BerInteger getOthers() { + return others; + } + + public void setOthers(BerInteger others) { + this.others = others; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (others != null) { + codeLength += others.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 12 + reverseOS.write(0x8C); + codeLength += 1; + return codeLength; + } + + if (file != null) { + codeLength += file.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 11 + reverseOS.write(0x8B); + codeLength += 1; + return codeLength; + } + + if (cancel != null) { + codeLength += cancel.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 10 + reverseOS.write(0x8A); + codeLength += 1; + return codeLength; + } + + if (conclude != null) { + codeLength += conclude.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 9 + reverseOS.write(0x89); + codeLength += 1; + return codeLength; + } + + if (initiate != null) { + codeLength += initiate.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 8 + reverseOS.write(0x88); + codeLength += 1; + return codeLength; + } + + if (access != null) { + codeLength += access.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 7 + reverseOS.write(0x87); + codeLength += 1; + return codeLength; + } + + if (timeResolution != null) { + codeLength += timeResolution.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 6 + reverseOS.write(0x86); + codeLength += 1; + return codeLength; + } + + if (servicePreempt != null) { + codeLength += servicePreempt.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 5 + reverseOS.write(0x85); + codeLength += 1; + return codeLength; + } + + if (service != null) { + codeLength += service.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 4 + reverseOS.write(0x84); + codeLength += 1; + return codeLength; + } + + if (resource != null) { + codeLength += resource.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + return codeLength; + } + + if (definition != null) { + codeLength += definition.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (applicationReference != null) { + codeLength += applicationReference.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (vmdState != null) { + codeLength += vmdState.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + vmdState = new BerInteger(); + tlvByteCount += vmdState.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + applicationReference = new BerInteger(); + tlvByteCount += applicationReference.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + definition = new BerInteger(); + tlvByteCount += definition.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + resource = new BerInteger(); + tlvByteCount += resource.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 4)) { + service = new BerInteger(); + tlvByteCount += service.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 5)) { + servicePreempt = new BerInteger(); + tlvByteCount += servicePreempt.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 6)) { + timeResolution = new BerInteger(); + tlvByteCount += timeResolution.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 7)) { + access = new BerInteger(); + tlvByteCount += access.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 8)) { + initiate = new BerInteger(); + tlvByteCount += initiate.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 9)) { + conclude = new BerInteger(); + tlvByteCount += conclude.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 10)) { + cancel = new BerInteger(); + tlvByteCount += cancel.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 11)) { + file = new BerInteger(); + tlvByteCount += file.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 12)) { + others = new BerInteger(); + tlvByteCount += others.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (vmdState != null) { + sb.append("vmdState: ").append(vmdState); + return; + } + + if (applicationReference != null) { + sb.append("applicationReference: ").append(applicationReference); + return; + } + + if (definition != null) { + sb.append("definition: ").append(definition); + return; + } + + if (resource != null) { + sb.append("resource: ").append(resource); + return; + } + + if (service != null) { + sb.append("service: ").append(service); + return; + } + + if (servicePreempt != null) { + sb.append("servicePreempt: ").append(servicePreempt); + return; + } + + if (timeResolution != null) { + sb.append("timeResolution: ").append(timeResolution); + return; + } + + if (access != null) { + sb.append("access: ").append(access); + return; + } + + if (initiate != null) { + sb.append("initiate: ").append(initiate); + return; + } + + if (conclude != null) { + sb.append("conclude: ").append(conclude); + return; + } + + if (cancel != null) { + sb.append("cancel: ").append(cancel); + return; + } + + if (file != null) { + sb.append("file: ").append(file); + return; + } + + if (others != null) { + sb.append("others: ").append(others); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ServiceSupportOptions.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ServiceSupportOptions.java new file mode 100644 index 0000000..55b7cd8 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/ServiceSupportOptions.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerBitString; + +public class ServiceSupportOptions extends BerBitString { + + private static final long serialVersionUID = 1L; + + public ServiceSupportOptions() {} + + public ServiceSupportOptions(byte[] code) { + super(code); + } + + public ServiceSupportOptions(byte[] value, int numBits) { + super(value, numBits); + } + + public ServiceSupportOptions(boolean[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TimeOfDay.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TimeOfDay.java new file mode 100644 index 0000000..5d56431 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TimeOfDay.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerOctetString; + +public class TimeOfDay extends BerOctetString { + + private static final long serialVersionUID = 1L; + + public TimeOfDay() {} + + public TimeOfDay(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TypeDescription.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TypeDescription.java new file mode 100644 index 0000000..3cc3da4 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TypeDescription.java @@ -0,0 +1,1256 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.iec61850bean.internal.BerBoolean; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class TypeDescription implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private Array array = null; + private Structure structure = null; + private BerNull bool = null; + private Integer32 bitString = null; + private Unsigned8 integer = null; + private Unsigned8 unsigned = null; + private FloatingPoint floatingPoint = null; + private Integer32 octetString = null; + private Integer32 visibleString = null; + private BerBoolean binaryTime = null; + private Integer32 mMSString = null; + private BerNull utcTime = null; + + public TypeDescription() {} + + public TypeDescription(byte[] code) { + this.code = code; + } + + public Array getArray() { + return array; + } + + public void setArray(Array array) { + this.array = array; + } + + public Structure getStructure() { + return structure; + } + + public void setStructure(Structure structure) { + this.structure = structure; + } + + public BerNull getBool() { + return bool; + } + + public void setBool(BerNull bool) { + this.bool = bool; + } + + public Integer32 getBitString() { + return bitString; + } + + public void setBitString(Integer32 bitString) { + this.bitString = bitString; + } + + public Unsigned8 getInteger() { + return integer; + } + + public void setInteger(Unsigned8 integer) { + this.integer = integer; + } + + public Unsigned8 getUnsigned() { + return unsigned; + } + + public void setUnsigned(Unsigned8 unsigned) { + this.unsigned = unsigned; + } + + public FloatingPoint getFloatingPoint() { + return floatingPoint; + } + + public void setFloatingPoint(FloatingPoint floatingPoint) { + this.floatingPoint = floatingPoint; + } + + public Integer32 getOctetString() { + return octetString; + } + + public void setOctetString(Integer32 octetString) { + this.octetString = octetString; + } + + public Integer32 getVisibleString() { + return visibleString; + } + + public void setVisibleString(Integer32 visibleString) { + this.visibleString = visibleString; + } + + public BerBoolean getBinaryTime() { + return binaryTime; + } + + public void setBinaryTime(BerBoolean binaryTime) { + this.binaryTime = binaryTime; + } + + public Integer32 getMMSString() { + return mMSString; + } + + public void setMMSString(Integer32 mMSString) { + this.mMSString = mMSString; + } + + public BerNull getUtcTime() { + return utcTime; + } + + public void setUtcTime(BerNull utcTime) { + this.utcTime = utcTime; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (utcTime != null) { + codeLength += utcTime.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 17 + reverseOS.write(0x91); + codeLength += 1; + return codeLength; + } + + if (mMSString != null) { + codeLength += mMSString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 16 + reverseOS.write(0x90); + codeLength += 1; + return codeLength; + } + + if (binaryTime != null) { + codeLength += binaryTime.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 12 + reverseOS.write(0x8C); + codeLength += 1; + return codeLength; + } + + if (visibleString != null) { + codeLength += visibleString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 10 + reverseOS.write(0x8A); + codeLength += 1; + return codeLength; + } + + if (octetString != null) { + codeLength += octetString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 9 + reverseOS.write(0x89); + codeLength += 1; + return codeLength; + } + + if (floatingPoint != null) { + codeLength += floatingPoint.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 7 + reverseOS.write(0xA7); + codeLength += 1; + return codeLength; + } + + if (unsigned != null) { + codeLength += unsigned.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 6 + reverseOS.write(0x86); + codeLength += 1; + return codeLength; + } + + if (integer != null) { + codeLength += integer.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 5 + reverseOS.write(0x85); + codeLength += 1; + return codeLength; + } + + if (bitString != null) { + codeLength += bitString.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 4 + reverseOS.write(0x84); + codeLength += 1; + return codeLength; + } + + if (bool != null) { + codeLength += bool.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + return codeLength; + } + + if (structure != null) { + codeLength += structure.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + return codeLength; + } + + if (array != null) { + codeLength += array.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + array = new Array(); + tlvByteCount += array.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + structure = new Structure(); + tlvByteCount += structure.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + bool = new BerNull(); + tlvByteCount += bool.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 4)) { + bitString = new Integer32(); + tlvByteCount += bitString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 5)) { + integer = new Unsigned8(); + tlvByteCount += integer.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 6)) { + unsigned = new Unsigned8(); + tlvByteCount += unsigned.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 7)) { + floatingPoint = new FloatingPoint(); + tlvByteCount += floatingPoint.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 9)) { + octetString = new Integer32(); + tlvByteCount += octetString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 10)) { + visibleString = new Integer32(); + tlvByteCount += visibleString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 12)) { + binaryTime = new BerBoolean(); + tlvByteCount += binaryTime.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 16)) { + mMSString = new Integer32(); + tlvByteCount += mMSString.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 17)) { + utcTime = new BerNull(); + tlvByteCount += utcTime.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (array != null) { + sb.append("array: "); + array.appendAsString(sb, indentLevel + 1); + return; + } + + if (structure != null) { + sb.append("structure: "); + structure.appendAsString(sb, indentLevel + 1); + return; + } + + if (bool != null) { + sb.append("bool: ").append(bool); + return; + } + + if (bitString != null) { + sb.append("bitString: ").append(bitString); + return; + } + + if (integer != null) { + sb.append("integer: ").append(integer); + return; + } + + if (unsigned != null) { + sb.append("unsigned: ").append(unsigned); + return; + } + + if (floatingPoint != null) { + sb.append("floatingPoint: "); + floatingPoint.appendAsString(sb, indentLevel + 1); + return; + } + + if (octetString != null) { + sb.append("octetString: ").append(octetString); + return; + } + + if (visibleString != null) { + sb.append("visibleString: ").append(visibleString); + return; + } + + if (binaryTime != null) { + sb.append("binaryTime: ").append(binaryTime); + return; + } + + if (mMSString != null) { + sb.append("mMSString: ").append(mMSString); + return; + } + + if (utcTime != null) { + sb.append("utcTime: ").append(utcTime); + return; + } + + sb.append(""); + } + + public static class Array implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerBoolean packed = null; + private Unsigned32 numberOfElements = null; + private TypeSpecification elementType = null; + + public Array() {} + + public Array(byte[] code) { + this.code = code; + } + + public BerBoolean getPacked() { + return packed; + } + + public void setPacked(BerBoolean packed) { + this.packed = packed; + } + + public Unsigned32 getNumberOfElements() { + return numberOfElements; + } + + public void setNumberOfElements(Unsigned32 numberOfElements) { + this.numberOfElements = numberOfElements; + } + + public TypeSpecification getElementType() { + return elementType; + } + + public void setElementType(TypeSpecification elementType) { + this.elementType = elementType; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + sublength = elementType.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + + codeLength += numberOfElements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + if (packed != null) { + codeLength += packed.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + packed = new BerBoolean(); + vByteCount += packed.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + numberOfElements = new Unsigned32(); + vByteCount += numberOfElements.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + vByteCount += length.decode(is); + elementType = new TypeSpecification(); + vByteCount += elementType.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (packed != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("packed: ").append(packed); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (numberOfElements != null) { + sb.append("numberOfElements: ").append(numberOfElements); + } else { + sb.append("numberOfElements: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (elementType != null) { + sb.append("elementType: "); + elementType.appendAsString(sb, indentLevel + 1); + } else { + sb.append("elementType: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } + + public static class Structure implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerBoolean packed = null; + private Components components = null; + + public Structure() {} + + public Structure(byte[] code) { + this.code = code; + } + + public BerBoolean getPacked() { + return packed; + } + + public void setPacked(BerBoolean packed) { + this.packed = packed; + } + + public Components getComponents() { + return components; + } + + public void setComponents(Components components) { + this.components = components; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += components.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + if (packed != null) { + codeLength += packed.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + packed = new BerBoolean(); + vByteCount += packed.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + components = new Components(); + vByteCount += components.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (packed != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("packed: ").append(packed); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (components != null) { + sb.append("components: "); + components.appendAsString(sb, indentLevel + 1); + } else { + sb.append("components: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class Components implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public Components() { + seqOf = new ArrayList(); + } + + public Components(byte[] code) { + this.code = code; + } + + public List getSEQUENCE() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(SEQUENCE.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + SEQUENCE element = new SEQUENCE(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class SEQUENCE implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Identifier componentName = null; + private TypeSpecification componentType = null; + + public SEQUENCE() {} + + public SEQUENCE(byte[] code) { + this.code = code; + } + + public Identifier getComponentName() { + return componentName; + } + + public void setComponentName(Identifier componentName) { + this.componentName = componentName; + } + + public TypeSpecification getComponentType() { + return componentType; + } + + public void setComponentType(TypeSpecification componentType) { + this.componentType = componentType; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + sublength = componentType.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + if (componentName != null) { + codeLength += componentName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + componentName = new Identifier(); + vByteCount += componentName.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + vByteCount += length.decode(is); + componentType = new TypeSpecification(); + vByteCount += componentType.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (componentName != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("componentName: ").append(componentName); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (componentType != null) { + sb.append("componentType: "); + componentType.appendAsString(sb, indentLevel + 1); + } else { + sb.append("componentType: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } + } + } + + public static class FloatingPoint implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Unsigned8 formatWidth = null; + private Unsigned8 exponentWidth = null; + + public FloatingPoint() {} + + public FloatingPoint(byte[] code) { + this.code = code; + } + + public Unsigned8 getFormatWidth() { + return formatWidth; + } + + public void setFormatWidth(Unsigned8 formatWidth) { + this.formatWidth = formatWidth; + } + + public Unsigned8 getExponentWidth() { + return exponentWidth; + } + + public void setExponentWidth(Unsigned8 exponentWidth) { + this.exponentWidth = exponentWidth; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += exponentWidth.encode(reverseOS, true); + + codeLength += formatWidth.encode(reverseOS, true); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(Unsigned8.tag)) { + formatWidth = new Unsigned8(); + vByteCount += formatWidth.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(Unsigned8.tag)) { + exponentWidth = new Unsigned8(); + vByteCount += exponentWidth.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (formatWidth != null) { + sb.append("formatWidth: ").append(formatWidth); + } else { + sb.append("formatWidth: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (exponentWidth != null) { + sb.append("exponentWidth: ").append(exponentWidth); + } else { + sb.append("exponentWidth: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TypeSpecification.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TypeSpecification.java new file mode 100644 index 0000000..cfe9237 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/TypeSpecification.java @@ -0,0 +1,108 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class TypeSpecification implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private TypeDescription typeDescription = null; + + public TypeSpecification() {} + + public TypeSpecification(byte[] code) { + this.code = code; + } + + public TypeDescription getTypeDescription() { + return typeDescription; + } + + public void setTypeDescription(TypeDescription typeDescription) { + this.typeDescription = typeDescription; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (typeDescription != null) { + codeLength += typeDescription.encode(reverseOS); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + int numDecodedBytes; + + typeDescription = new TypeDescription(); + numDecodedBytes = typeDescription.decode(is, berTag); + if (numDecodedBytes != 0) { + return tlvByteCount + numDecodedBytes; + } else { + typeDescription = null; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (typeDescription != null) { + sb.append("typeDescription: "); + typeDescription.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UnconfirmedPDU.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UnconfirmedPDU.java new file mode 100644 index 0000000..6fc2fef --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UnconfirmedPDU.java @@ -0,0 +1,140 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class UnconfirmedPDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private UnconfirmedService service = null; + + public UnconfirmedPDU() {} + + public UnconfirmedPDU(byte[] code) { + this.code = code; + } + + public UnconfirmedService getService() { + return service; + } + + public void setService(UnconfirmedService service) { + this.service = service; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += service.encode(reverseOS); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + service = new UnconfirmedService(); + numDecodedBytes = service.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (service != null) { + sb.append("service: "); + service.appendAsString(sb, indentLevel + 1); + } else { + sb.append("service: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UnconfirmedService.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UnconfirmedService.java new file mode 100644 index 0000000..bc2a3c2 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UnconfirmedService.java @@ -0,0 +1,107 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class UnconfirmedService implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private InformationReport informationReport = null; + + public UnconfirmedService() {} + + public UnconfirmedService(byte[] code) { + this.code = code; + } + + public InformationReport getInformationReport() { + return informationReport; + } + + public void setInformationReport(InformationReport informationReport) { + this.informationReport = informationReport; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (informationReport != null) { + codeLength += informationReport.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + informationReport = new InformationReport(); + tlvByteCount += informationReport.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (informationReport != null) { + sb.append("informationReport: "); + informationReport.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned16.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned16.java new file mode 100644 index 0000000..6a34e92 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned16.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class Unsigned16 extends BerInteger { + + private static final long serialVersionUID = 1L; + + public Unsigned16() {} + + public Unsigned16(byte[] code) { + super(code); + } + + public Unsigned16(BigInteger value) { + super(value); + } + + public Unsigned16(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned32.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned32.java new file mode 100644 index 0000000..4b79cfb --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned32.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class Unsigned32 extends BerInteger { + + private static final long serialVersionUID = 1L; + + public Unsigned32() {} + + public Unsigned32(byte[] code) { + super(code); + } + + public Unsigned32(BigInteger value) { + super(value); + } + + public Unsigned32(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned8.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned8.java new file mode 100644 index 0000000..5c83ebf --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/Unsigned8.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class Unsigned8 extends BerInteger { + + private static final long serialVersionUID = 1L; + + public Unsigned8() {} + + public Unsigned8(byte[] code) { + super(code); + } + + public Unsigned8(BigInteger value) { + super(value); + } + + public Unsigned8(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UtcTime.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UtcTime.java new file mode 100644 index 0000000..0903e5f --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/UtcTime.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.types.BerOctetString; + +public class UtcTime extends BerOctetString { + + private static final long serialVersionUID = 1L; + + public UtcTime() {} + + public UtcTime(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableAccessSpecification.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableAccessSpecification.java new file mode 100644 index 0000000..efcf15a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableAccessSpecification.java @@ -0,0 +1,144 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class VariableAccessSpecification implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private VariableDefs listOfVariable = null; + private ObjectName variableListName = null; + + public VariableAccessSpecification() {} + + public VariableAccessSpecification(byte[] code) { + this.code = code; + } + + public VariableDefs getListOfVariable() { + return listOfVariable; + } + + public void setListOfVariable(VariableDefs listOfVariable) { + this.listOfVariable = listOfVariable; + } + + public ObjectName getVariableListName() { + return variableListName; + } + + public void setVariableListName(ObjectName variableListName) { + this.variableListName = variableListName; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (variableListName != null) { + sublength = variableListName.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + if (listOfVariable != null) { + codeLength += listOfVariable.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + listOfVariable = new VariableDefs(); + tlvByteCount += listOfVariable.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + variableListName = new ObjectName(); + tlvByteCount += variableListName.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (listOfVariable != null) { + sb.append("listOfVariable: "); + listOfVariable.appendAsString(sb, indentLevel + 1); + return; + } + + if (variableListName != null) { + sb.append("variableListName: "); + variableListName.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableDefs.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableDefs.java new file mode 100644 index 0000000..803dc4e --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableDefs.java @@ -0,0 +1,316 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class VariableDefs implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public VariableDefs() { + seqOf = new ArrayList(); + } + + public VariableDefs(byte[] code) { + this.code = code; + } + + public List getSEQUENCE() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(SEQUENCE.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + SEQUENCE element = new SEQUENCE(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class SEQUENCE implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private VariableSpecification variableSpecification = null; + private AlternateAccess alternateAccess = null; + + public SEQUENCE() {} + + public SEQUENCE(byte[] code) { + this.code = code; + } + + public VariableSpecification getVariableSpecification() { + return variableSpecification; + } + + public void setVariableSpecification(VariableSpecification variableSpecification) { + this.variableSpecification = variableSpecification; + } + + public AlternateAccess getAlternateAccess() { + return alternateAccess; + } + + public void setAlternateAccess(AlternateAccess alternateAccess) { + this.alternateAccess = alternateAccess; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (alternateAccess != null) { + codeLength += alternateAccess.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 5 + reverseOS.write(0xA5); + codeLength += 1; + } + + codeLength += variableSpecification.encode(reverseOS); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + variableSpecification = new VariableSpecification(); + numDecodedBytes = variableSpecification.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 5)) { + alternateAccess = new AlternateAccess(); + vByteCount += alternateAccess.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (variableSpecification != null) { + sb.append("variableSpecification: "); + variableSpecification.appendAsString(sb, indentLevel + 1); + } else { + sb.append("variableSpecification: "); + } + + if (alternateAccess != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("alternateAccess: "); + alternateAccess.appendAsString(sb, indentLevel + 1); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableSpecification.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableSpecification.java new file mode 100644 index 0000000..0497a01 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/VariableSpecification.java @@ -0,0 +1,115 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class VariableSpecification implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private ObjectName name = null; + + public VariableSpecification() {} + + public VariableSpecification(byte[] code) { + this.code = code; + } + + public ObjectName getName() { + return name; + } + + public void setName(ObjectName name) { + this.name = name; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (name != null) { + sublength = name.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + name = new ObjectName(); + tlvByteCount += name.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (name != null) { + sb.append("name: "); + name.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/WriteRequest.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/WriteRequest.java new file mode 100644 index 0000000..3b0151d --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/WriteRequest.java @@ -0,0 +1,315 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class WriteRequest implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private VariableAccessSpecification variableAccessSpecification = null; + private ListOfData listOfData = null; + + public WriteRequest() {} + + public WriteRequest(byte[] code) { + this.code = code; + } + + public VariableAccessSpecification getVariableAccessSpecification() { + return variableAccessSpecification; + } + + public void setVariableAccessSpecification( + VariableAccessSpecification variableAccessSpecification) { + this.variableAccessSpecification = variableAccessSpecification; + } + + public ListOfData getListOfData() { + return listOfData; + } + + public void setListOfData(ListOfData listOfData) { + this.listOfData = listOfData; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += listOfData.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += variableAccessSpecification.encode(reverseOS); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + variableAccessSpecification = new VariableAccessSpecification(); + numDecodedBytes = variableAccessSpecification.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + listOfData = new ListOfData(); + vByteCount += listOfData.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (variableAccessSpecification != null) { + sb.append("variableAccessSpecification: "); + variableAccessSpecification.appendAsString(sb, indentLevel + 1); + } else { + sb.append("variableAccessSpecification: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (listOfData != null) { + sb.append("listOfData: "); + listOfData.appendAsString(sb, indentLevel + 1); + } else { + sb.append("listOfData: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class ListOfData implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ListOfData() { + seqOf = new ArrayList(); + } + + public ListOfData(byte[] code) { + this.code = code; + } + + public List getData() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + Data element = new Data(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/WriteResponse.java b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/WriteResponse.java new file mode 100644 index 0000000..21d07f4 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/mms/asn1/WriteResponse.java @@ -0,0 +1,277 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.iec61850bean.internal.mms.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerNull; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class WriteResponse implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public WriteResponse() { + seqOf = new ArrayList(); + } + + public WriteResponse(byte[] code) { + this.code = code; + } + + public List getCHOICE() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + CHOICE element = new CHOICE(); + numDecodedBytes = element.decode(is, berTag); + if (numDecodedBytes == 0) { + throw new IOException("Tag did not match"); + } + vByteCount += numDecodedBytes; + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class CHOICE implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private DataAccessError failure = null; + private BerNull success = null; + + public CHOICE() {} + + public CHOICE(byte[] code) { + this.code = code; + } + + public DataAccessError getFailure() { + return failure; + } + + public void setFailure(DataAccessError failure) { + this.failure = failure; + } + + public BerNull getSuccess() { + return success; + } + + public void setSuccess(BerNull success) { + this.success = success; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (success != null) { + codeLength += success.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (failure != null) { + codeLength += failure.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + failure = new DataAccessError(); + tlvByteCount += failure.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + success = new BerNull(); + tlvByteCount += success.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (failure != null) { + sb.append("failure: ").append(failure); + return; + } + + if (success != null) { + sb.append("success: ").append(success); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractDataAttribute.java b/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractDataAttribute.java new file mode 100644 index 0000000..11852d2 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractDataAttribute.java @@ -0,0 +1,79 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public abstract class AbstractDataAttribute extends AbstractElement { + + // attributes not needed: valKind + + public String value = null; + private String sAddr = null; /* optional - short address */ + private String bType = null; /* mandatory - basic type */ + private String type = null; /* conditional - if bType = "Enum" or "Struct" */ + private int count = 0; /* optional - number of array elements */ + + AbstractDataAttribute(Node xmlNode) throws SclParseException { + super(xmlNode); + + NamedNodeMap attributes = xmlNode.getAttributes(); + + for (int i = 0; i < attributes.getLength(); i++) { + Node node = attributes.item(i); + String nodeName = node.getNodeName(); + + if (nodeName.equals("type")) { + type = node.getNodeValue(); + } else if (nodeName.equals("sAddr")) { + sAddr = node.getNodeValue(); + } else if (nodeName.equals("bType")) { + bType = node.getNodeValue(); + } else if (nodeName.equals("count")) { + count = Integer.parseInt(node.getNodeValue()); + } + } + + if (bType == null) { + throw new SclParseException("Required attribute \"bType\" not found!"); + } + + NodeList elements = xmlNode.getChildNodes(); + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + if (node.getNodeName().equals("Val")) { + value = node.getTextContent(); + } + } + } + + public String getsAddr() { + return sAddr; + } + + public String getbType() { + return bType; + } + + public String getType() { + return type; + } + + public int getCount() { + return count; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractElement.java b/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractElement.java new file mode 100644 index 0000000..5f78cc8 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractElement.java @@ -0,0 +1,52 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public abstract class AbstractElement { + + private String name = null; + private String desc = null; + + AbstractElement(String name, String desc) { + this.name = name; + this.desc = desc; + } + + AbstractElement(Node xmlNode) throws SclParseException { + NamedNodeMap attributes = xmlNode.getAttributes(); + + Node node = attributes.getNamedItem("name"); + if (node == null) { + throw new SclParseException("Required attribute \"name\" not found!"); + } + name = node.getNodeValue(); + + node = attributes.getNamedItem("desc"); + if (node != null) { + desc = node.getNodeValue(); + } + } + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractType.java b/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractType.java new file mode 100644 index 0000000..63d12ec --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/AbstractType.java @@ -0,0 +1,32 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.Node; + +public abstract class AbstractType { + + public String id = null; + + // attributes not needed: desc + + AbstractType(Node xmlNode) throws SclParseException { + Node idNode = xmlNode.getAttributes().getNamedItem("id"); + if (idNode == null) { + throw new SclParseException("Required attribute \"id\" not found!"); + } + id = idNode.getNodeValue(); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/Bda.java b/src/main/java/com/beanit/iec61850bean/internal/scl/Bda.java new file mode 100644 index 0000000..7184da4 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/Bda.java @@ -0,0 +1,24 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.Node; + +public final class Bda extends AbstractDataAttribute { + + public Bda(Node xmlNode) throws SclParseException { + super(xmlNode); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/Da.java b/src/main/java/com/beanit/iec61850bean/internal/scl/Da.java new file mode 100644 index 0000000..91809da --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/Da.java @@ -0,0 +1,72 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.Fc; +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public final class Da extends AbstractDataAttribute { + + private Fc fc = null; + private boolean dchg = false; + private boolean qchg = false; + private boolean dupd = false; + + public Da(Node xmlNode) throws SclParseException { + + super(xmlNode); + + NamedNodeMap attributes = xmlNode.getAttributes(); + + for (int i = 0; i < attributes.getLength(); i++) { + Node node = attributes.item(i); + String nodeName = node.getNodeName(); + + if (nodeName.equals("fc")) { + fc = Fc.fromString(node.getNodeValue()); + if (fc == null) { + throw new SclParseException("Invalid Functional Constraint"); + } + } else if (nodeName.equals("dchg")) { + dchg = "true".equals(node.getNodeValue()); + } else if (nodeName.equals("qchg")) { + qchg = "true".equals(node.getNodeValue()); + } else if (nodeName.equals("dupd")) { + dupd = "true".equals(node.getNodeValue()); + } + } + + if (fc == null) { + throw new SclParseException("Required attribute \"fc\" not found!"); + } + } + + public Fc getFc() { + return fc; + } + + public boolean isDchg() { + return dchg; + } + + public boolean isQchg() { + return qchg; + } + + public boolean isDupd() { + return dupd; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/DaType.java b/src/main/java/com/beanit/iec61850bean/internal/scl/DaType.java new file mode 100644 index 0000000..b9fa1b0 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/DaType.java @@ -0,0 +1,41 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import java.util.ArrayList; +import java.util.List; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public final class DaType extends AbstractType { + + // attributes not needed: iedType + + public List bdas = new ArrayList<>(); + + public DaType(Node xmlNode) throws SclParseException { + + super(xmlNode); + + NodeList elements = xmlNode.getChildNodes(); + + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + if (node.getNodeName().equals("BDA")) { + bdas.add(new Bda(node)); + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/Do.java b/src/main/java/com/beanit/iec61850bean/internal/scl/Do.java new file mode 100644 index 0000000..3ba6381 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/Do.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public final class Do extends AbstractElement { + + private String type; + + public Do(String name, String desc, String type) { + super(name, desc); + } + + public Do(Node xmlNode) throws SclParseException { + super(xmlNode); + + NamedNodeMap attributes = xmlNode.getAttributes(); + + Node node = attributes.getNamedItem("type"); + + if (node == null) { + throw new SclParseException("Required attribute \"type\" not found!"); + } + + type = node.getNodeValue(); + } + + public String getType() { + return type; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/DoType.java b/src/main/java/com/beanit/iec61850bean/internal/scl/DoType.java new file mode 100644 index 0000000..67bfce6 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/DoType.java @@ -0,0 +1,49 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import java.util.ArrayList; +import java.util.List; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public final class DoType extends AbstractType { + + // attributes not needed: cdc, iedType + + public List das = new ArrayList<>(); + public List sdos = new ArrayList<>(); + + public DoType(Node xmlNode) throws SclParseException { + + super(xmlNode); + + if (xmlNode.getAttributes().getNamedItem("cdc") == null) { + throw new SclParseException("Required attribute \"cdc\" not found in DOType!"); + } + + 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)); + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/EnumType.java b/src/main/java/com/beanit/iec61850bean/internal/scl/EnumType.java new file mode 100644 index 0000000..7de6699 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/EnumType.java @@ -0,0 +1,53 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import java.util.ArrayList; +import java.util.List; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public final class EnumType extends AbstractType { + + public List values; + public int max = 0; + public int min = 0; + + public EnumType(Node xmlNode) throws SclParseException { + super(xmlNode); + + NodeList elements = xmlNode.getChildNodes(); + + values = new ArrayList<>(); + + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + + if (node.getNodeName().equals("EnumVal")) { + EnumVal val = new EnumVal(node); + if (val.getOrd() < min) { + min = val.getOrd(); + } else if (val.getOrd() > max) { + max = val.getOrd(); + } + values.add(val); + } + } + } + + public List getValues() { + return values; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/EnumVal.java b/src/main/java/com/beanit/iec61850bean/internal/scl/EnumVal.java new file mode 100644 index 0000000..6be1024 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/EnumVal.java @@ -0,0 +1,55 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public final class EnumVal { + + private final String id; + private int ord; + + public EnumVal(String id, int ord) { + this.id = id; + this.ord = ord; + } + + public EnumVal(Node xmlNode) throws SclParseException { + id = xmlNode.getTextContent(); + + NamedNodeMap attributes = xmlNode.getAttributes(); + + Node node = attributes.getNamedItem("ord"); + + if (node == null) { + throw new SclParseException("Required attribute \"ord\" not found!"); + } + + try { + ord = Integer.parseInt(node.getNodeValue()); + } catch (NumberFormatException e) { + throw new SclParseException("EnumVal contains invalid \"ord\" number."); + } + } + + public String getId() { + return id; + } + + public int getOrd() { + return ord; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/LnSubDef.java b/src/main/java/com/beanit/iec61850bean/internal/scl/LnSubDef.java new file mode 100644 index 0000000..05fa8e6 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/LnSubDef.java @@ -0,0 +1,28 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.LogicalNode; +import org.w3c.dom.Node; + +public class LnSubDef { + + public Node defXmlNode; + public LogicalNode logicalNode; + + public LnSubDef(Node dataSetDefXmlNode, LogicalNode logicalNode) { + defXmlNode = dataSetDefXmlNode; + this.logicalNode = logicalNode; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/LnType.java b/src/main/java/com/beanit/iec61850bean/internal/scl/LnType.java new file mode 100644 index 0000000..7947ec3 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/LnType.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import java.util.ArrayList; +import java.util.List; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public final class LnType extends AbstractType { + + // attributes not needed: lnClass, iedType + + public List dos = new ArrayList<>(); + + public LnType(Node xmlNode) throws SclParseException { + + super(xmlNode); + + if (xmlNode.getAttributes().getNamedItem("lnClass") == null) { + throw new SclParseException("Required attribute \"lnClass\" not found in LNType!"); + } + + NodeList elements = xmlNode.getChildNodes(); + + for (int i = 0; i < elements.getLength(); i++) { + Node node = elements.item(i); + if (node.getNodeName().equals("DO")) { + dos.add(new Do(node)); + } + } + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/Sdo.java b/src/main/java/com/beanit/iec61850bean/internal/scl/Sdo.java new file mode 100644 index 0000000..f196886 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/Sdo.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +public final class Sdo extends AbstractElement { + + private String type = null; + + public Sdo(String name, String desc, DoType type) { + super(name, desc); + } + + public Sdo(Node xmlNode) throws SclParseException { + super(xmlNode); + + NamedNodeMap attributes = xmlNode.getAttributes(); + + Node node = attributes.getNamedItem("type"); + + if (node == null) { + throw new SclParseException("Required attribute \"type\" not found!"); + } + + type = node.getNodeValue(); + } + + public String getType() { + return type; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/TypeDefinitions.java b/src/main/java/com/beanit/iec61850bean/internal/scl/TypeDefinitions.java new file mode 100644 index 0000000..dd0202c --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/TypeDefinitions.java @@ -0,0 +1,83 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import java.util.ArrayList; + +public final class TypeDefinitions { + + private final ArrayList lnodeTypes = new ArrayList<>(); + private final ArrayList doTypes = new ArrayList<>(); + private final ArrayList daTypes = new ArrayList<>(); + private final ArrayList enumTypes = new ArrayList<>(); + + public TypeDefinitions() {} + + public void putLNodeType(LnType lnodeType) { + lnodeTypes.add(lnodeType); + } + + public void putDOType(DoType doType) { + doTypes.add(doType); + } + + public void putDAType(DaType daType) { + daTypes.add(daType); + } + + public void putEnumType(EnumType enumType) { + enumTypes.add(enumType); + } + + public DaType getDaType(String daType) { + for (DaType datype : daTypes) { + if (datype.id.equals(daType)) { + return datype; + } + } + + return null; + } + + public DoType getDOType(String doType) { + for (DoType dotype : doTypes) { + if (dotype.id.equals(doType)) { + return dotype; + } + } + + return null; + } + + public LnType getLNodeType(String lnType) { + + for (LnType ntype : lnodeTypes) { + if (ntype.id.equals(lnType)) { + return ntype; + } + } + + return null; + } + + public EnumType getEnumType(String enumTypeRef) { + for (EnumType enumType : enumTypes) { + if (enumType.id.equals(enumTypeRef)) { + return enumType; + } + } + + return null; + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/Util.java b/src/main/java/com/beanit/iec61850bean/internal/scl/Util.java new file mode 100644 index 0000000..33b6b84 --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/Util.java @@ -0,0 +1,106 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +import com.beanit.iec61850bean.SclParseException; + +public final class Util { + + static boolean parseBooleanValue(String value) throws SclParseException { + if (value.equals("true")) { + return true; + } else if (value.equals("false")) { + return false; + } else { + throw new SclParseException("Not a boolean value"); + } + } + + public static boolean isBasicType(String bType) throws SclParseException { + if (bType.equals("BOOLEAN")) { + return true; + } + if (bType.equals("INT8")) { + return true; + } + if (bType.equals("INT16")) { + return true; + } + if (bType.equals("INT32")) { + return true; + } + if (bType.equals("INT64")) { + return true; + } + if (bType.equals("INT8U")) { + return true; + } + if (bType.equals("INT16U")) { + return true; + } + if (bType.equals("INT32U")) { + return true; + } + if (bType.equals("FLOAT32")) { + return true; + } + if (bType.equals("FLOAT64")) { + return true; + } + if (bType.equals("Timestamp")) { + return true; + } + if (bType.equals("VisString32")) { + return true; + } + if (bType.equals("VisString64")) { + return true; + } + if (bType.equals("VisString65")) { + return true; + } + if (bType.equals("VisString129")) { + return true; + } + if (bType.equals("VisString255")) { + return true; + } + if (bType.equals("Unicode255")) { + return true; + } + if (bType.equals("Octet64")) { + return true; + } + if (bType.equals("Struct")) { + return false; + } + if (bType.equals("Enum")) { + return true; + } + if (bType.equals("Quality")) { + return true; + } + if (bType.equals("Check")) { + return true; + } + if (bType.equals("Dbpos")) { + return true; + } + if (bType.equals("Tcmd")) { + return true; + } + + throw new SclParseException("Invalid bType: " + bType); + } +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/Value.java b/src/main/java/com/beanit/iec61850bean/internal/scl/Value.java new file mode 100644 index 0000000..55730ca --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/scl/Value.java @@ -0,0 +1,20 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.scl; + +public final class Value { + + public int sGroup; + public String value; +} diff --git a/src/main/java/com/beanit/iec61850bean/internal/util/SequenceNumber.java b/src/main/java/com/beanit/iec61850bean/internal/util/SequenceNumber.java new file mode 100644 index 0000000..67e5d9a --- /dev/null +++ b/src/main/java/com/beanit/iec61850bean/internal/util/SequenceNumber.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019 beanit + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.iec61850bean.internal.util; + +public class SequenceNumber { + + private final int maxValue; + private final int minValue; + private int value; + + public SequenceNumber(int initValue, int minValue, int maxValue) { + assert (initValue >= minValue) && (initValue <= maxValue); + this.minValue = minValue; + this.maxValue = maxValue; + this.value = initValue; + } + + public static int getIncrement(int value, int minValue, int maxValue) { + assert (value >= minValue) && (value <= maxValue); + return (value == maxValue) ? minValue : value + 1; + } + + public int getAndIncrement() { + int oldValue = value; + value = (value == maxValue) ? minValue : value + 1; + return oldValue; + } + + public int get() { + return value; + } + + public void increment() { + value = (value == maxValue) ? minValue : value + 1; + } + + public int incrementAndGet() { + value = (value == maxValue) ? minValue : value + 1; + return value; + } +} diff --git a/src/main/java/com/beanit/josistack/AcseAssociation.java b/src/main/java/com/beanit/josistack/AcseAssociation.java new file mode 100644 index 0000000..8c3edd6 --- /dev/null +++ b/src/main/java/com/beanit/josistack/AcseAssociation.java @@ -0,0 +1,1066 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.josistack; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerAny; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; +import com.beanit.asn1bean.ber.types.string.BerGraphicString; +import com.beanit.josistack.internal.acse.asn1.AAREApdu; +import com.beanit.josistack.internal.acse.asn1.AARQApdu; +import com.beanit.josistack.internal.acse.asn1.ACSEApdu; +import com.beanit.josistack.internal.acse.asn1.ACSERequirements; +import com.beanit.josistack.internal.acse.asn1.AEQualifier; +import com.beanit.josistack.internal.acse.asn1.AEQualifierForm2; +import com.beanit.josistack.internal.acse.asn1.APTitle; +import com.beanit.josistack.internal.acse.asn1.APTitleForm2; +import com.beanit.josistack.internal.acse.asn1.AssociateResult; +import com.beanit.josistack.internal.acse.asn1.AssociateSourceDiagnostic; +import com.beanit.josistack.internal.acse.asn1.AssociationInformation; +import com.beanit.josistack.internal.acse.asn1.AuthenticationValue; +import com.beanit.josistack.internal.acse.asn1.MechanismName; +import com.beanit.josistack.internal.acse.asn1.Myexternal; +import com.beanit.josistack.internal.presentation.asn1.CPAPPDU; +import com.beanit.josistack.internal.presentation.asn1.CPType; +import com.beanit.josistack.internal.presentation.asn1.CalledPresentationSelector; +import com.beanit.josistack.internal.presentation.asn1.CallingPresentationSelector; +import com.beanit.josistack.internal.presentation.asn1.FullyEncodedData; +import com.beanit.josistack.internal.presentation.asn1.ModeSelector; +import com.beanit.josistack.internal.presentation.asn1.PDVList; +import com.beanit.josistack.internal.presentation.asn1.PresentationContextDefinitionList; +import com.beanit.josistack.internal.presentation.asn1.PresentationContextDefinitionResultList; +import com.beanit.josistack.internal.presentation.asn1.PresentationContextIdentifier; +import com.beanit.josistack.internal.presentation.asn1.RespondingPresentationSelector; +import com.beanit.josistack.internal.presentation.asn1.UserData; +import com.beanit.jositransport.ClientTSap; +import com.beanit.jositransport.TConnection; +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeoutException; + +public final class AcseAssociation { + + // private static final Logger logger = LoggerFactory.getLogger(AcseAssociation.class); + + private static final PresentationContextDefinitionList context_list = + new PresentationContextDefinitionList( + new byte[] { + (byte) 0x23, + (byte) 0x30, + (byte) 0x0f, + (byte) 0x02, + (byte) 0x01, + (byte) 0x01, + (byte) 0x06, + (byte) 0x04, + (byte) 0x52, + (byte) 0x01, + (byte) 0x00, + (byte) 0x01, + (byte) 0x30, + (byte) 0x04, + (byte) 0x06, + (byte) 0x02, + (byte) 0x51, + (byte) 0x01, + (byte) 0x30, + (byte) 0x10, + (byte) 0x02, + (byte) 0x01, + (byte) 0x03, + (byte) 0x06, + (byte) 0x05, + (byte) 0x28, + (byte) 0xca, + (byte) 0x22, + (byte) 0x02, + (byte) 0x01, + (byte) 0x30, + (byte) 0x04, + (byte) 0x06, + (byte) 0x02, + (byte) 0x51, + (byte) 0x01 + }); + private static final PresentationContextIdentifier acsePresentationContextId = + new PresentationContextIdentifier(new byte[] {(byte) 0x01, (byte) 0x01}); + private static final ModeSelector normalModeSelector = new ModeSelector(); + private static final PresentationContextDefinitionResultList presentationResultList = + new PresentationContextDefinitionResultList( + new byte[] { + (byte) 0x12, + (byte) 0x30, + (byte) 0x07, + (byte) 0x80, + (byte) 0x01, + (byte) 0x00, + (byte) 0x81, + (byte) 0x02, + (byte) 0x51, + (byte) 0x01, + (byte) 0x30, + (byte) 0x07, + (byte) 0x80, + (byte) 0x01, + (byte) 0x00, + (byte) 0x81, + (byte) 0x02, + (byte) 0x51, + (byte) 0x01 + }); + private static final AssociateResult aareAccepted = + new AssociateResult(new byte[] {(byte) 0x01, (byte) 0x00}); + private static final AssociateSourceDiagnostic associateSourceDiagnostic = + new AssociateSourceDiagnostic( + new byte[] {(byte) 0xa1, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x00}); + // is always equal to 1.0.9506.2.3 (MMS) + private static final BerObjectIdentifier application_context_name = + new BerObjectIdentifier( + new byte[] { + (byte) 0x05, (byte) 0x28, (byte) 0xca, (byte) 0x22, (byte) 0x02, (byte) 0x03 + }); + private static final BerObjectIdentifier directReference = + new BerObjectIdentifier(new byte[] {(byte) 0x02, (byte) 0x51, (byte) 0x01}); + private static final BerInteger indirectReference = + new BerInteger(new byte[] {(byte) 0x01, (byte) 0x03}); + private static final MechanismName default_mechanism_name = + new MechanismName(new byte[] {0x03, 0x52, 0x03, 0x01}); + + static { + normalModeSelector.setModeValue(new BerInteger(BigInteger.ONE)); + } + + private final RespondingPresentationSelector pSelLocalBerOctetString; + private boolean connected = false; + private TConnection tConnection; + private ByteBuffer associateResponseAPDU = null; + + AcseAssociation(TConnection tConnection, byte[] pSelLocal) { + this.tConnection = tConnection; + pSelLocalBerOctetString = new RespondingPresentationSelector(pSelLocal); + } + + private static ByteBuffer decodePConResponse(ByteBuffer ppdu) throws IOException { + + CPAPPDU cpa_ppdu = new CPAPPDU(); + InputStream iStream = new ByteBufferInputStream(ppdu); + cpa_ppdu.decode(iStream); + + iStream = + new ByteArrayInputStream( + cpa_ppdu + .getNormalModeParameters() + .getUserData() + .getFullyEncodedData() + .getPDVList() + .get(0) + .getPresentationDataValues() + .getSingleASN1Type() + .value); + + ACSEApdu acseApdu = new ACSEApdu(); + acseApdu.decode(iStream, null); + return ByteBuffer.wrap( + acseApdu + .getAare() + .getUserInformation() + .getMyexternal() + .get(0) + .getEncoding() + .getSingleASN1Type() + .value); + } + + private static UserData getPresentationUserDataField(byte[] userDataBytes) { + PDVList.PresentationDataValues presDataValues = new PDVList.PresentationDataValues(); + presDataValues.setSingleASN1Type(new BerAny(userDataBytes)); + PDVList pdvList = new PDVList(); + pdvList.setPresentationContextIdentifier(acsePresentationContextId); + pdvList.setPresentationDataValues(presDataValues); + + FullyEncodedData fullyEncodedData = new FullyEncodedData(); + List pdvListList = fullyEncodedData.getPDVList(); + pdvListList.add(pdvList); + + UserData userData = new UserData(); + userData.setFullyEncodedData(fullyEncodedData); + return userData; + } + + public static String getSPDUTypeString(byte spduType) { + switch (spduType) { + case 0: + return "EXCEPTION REPORT (ER)"; + case 1: + return "DATA TRANSFER (DT)"; + case 2: + return "PLEASE TOKENS (PT)"; + case 5: + return "EXPEDITED (EX)"; + case 7: + return "PREPARE (PR)"; + case 8: + return "NOT FINISHED (NF)"; + case 9: + return "FINISH (FN)"; + case 10: + return "DISCONNECT (DN)"; + case 12: + return "REFUSE (RF)"; + case 13: + return "CONNECT (CN)"; + case 14: + return "ACCEPT (AC)"; + case 15: + return "CONNECT DATA OVERFLOW (CDO)"; + case 16: + return "OVERFLOW ACCEPT (OA)"; + case 21: + return "GIVE TOKENS CONFIRM (GTC)"; + case 22: + return "GIVE TOKENS ACK (GTA)"; + case 25: + return "ABORT (AB)"; + case 26: + return "ABORT ACCEPT (AA)"; + case 29: + return "ACTIVITY RESUME (AR)"; + case 33: + return "TYPED DATA (TD)"; + case 34: + return "RESYNCHRONIZE ACK (RA)"; + case 41: + return "MAJOR SYNC POINT (MAP)"; + case 42: + return "MAJOR SYNC ACK (MAA)"; + case 45: + return "ACTIVITY START (AS)"; + case 48: + return "EXCEPTION DATA (ED)"; + case 49: + return "MINOR SYNC POINT (MIP)"; + case 50: + return "MINOR SYNC ACK (MIA)"; + case 53: + return "RESYNCHRONIZE (RS)"; + case 57: + return "ACTIVITY DISCARD (AD)"; + case 58: + return "ACTIVITY DISCARD ACK (ADA)"; + case 61: + return "CAPABILITY DATA (CD)"; + case 62: + return "CAPABILITY DATA ACK (CDA)"; + case 64: + return "UNIT DATA (UD)"; + default: + return ""; + } + } + + /** + * A server that got an Association Request Indication may use this function to accept the + * association. + * + * @param payload the payload to send with the accept message + * @throws IOException if an error occures accepting the association + */ + public void accept(ByteBuffer payload) throws IOException { + + BerAny anyPayload = + new BerAny( + Arrays.copyOfRange( + payload.array(), payload.arrayOffset() + payload.position(), payload.limit())); + + Myexternal.Encoding encoding = new Myexternal.Encoding(); + encoding.setSingleASN1Type(anyPayload); + + Myexternal myExternal = new Myexternal(); + myExternal.setDirectReference(directReference); + myExternal.setIndirectReference(indirectReference); + myExternal.setEncoding(encoding); + + AssociationInformation userInformation = new AssociationInformation(); + List externalList = userInformation.getMyexternal(); + externalList.add(myExternal); + + AAREApdu aare = new AAREApdu(); + aare.setApplicationContextName(application_context_name); + aare.setResult(aareAccepted); + aare.setResultSourceDiagnostic(associateSourceDiagnostic); + aare.setUserInformation(userInformation); + + ACSEApdu acse = new ACSEApdu(); + acse.setAare(aare); + + ReverseByteArrayOutputStream reverseOStream = new ReverseByteArrayOutputStream(100, true); + acse.encode(reverseOStream); + + UserData userData = getPresentationUserDataField(reverseOStream.getArray()); + CPAPPDU.NormalModeParameters normalModeParameters = new CPAPPDU.NormalModeParameters(); + normalModeParameters.setRespondingPresentationSelector(pSelLocalBerOctetString); + normalModeParameters.setPresentationContextDefinitionResultList(presentationResultList); + normalModeParameters.setUserData(userData); + + CPAPPDU cpaPPdu = new CPAPPDU(); + cpaPPdu.setModeSelector(normalModeSelector); + cpaPPdu.setNormalModeParameters(normalModeParameters); + + reverseOStream.reset(); + cpaPPdu.encode(reverseOStream, true); + + List ssduList = new ArrayList<>(); + List ssduOffsets = new ArrayList<>(); + List ssduLengths = new ArrayList<>(); + + ssduList.add(reverseOStream.buffer); + ssduOffsets.add(reverseOStream.index + 1); + ssduLengths.add(reverseOStream.buffer.length - (reverseOStream.index + 1)); + + writeSessionAccept(ssduList, ssduOffsets, ssduLengths); + + connected = true; + } + + private void writeSessionAccept( + List ssdu, List ssduOffsets, List ssduLengths) throws IOException { + byte[] sduAcceptHeader = new byte[20]; + int idx = 0; + + int ssduLength = 0; + for (int ssduElementLength : ssduLengths) { + ssduLength += ssduElementLength; + } + + // write ISO 8327-1 Header + // SPDU Type: ACCEPT (14) + sduAcceptHeader[idx++] = 0x0e; + // Length: length of session user data + 22 ( header data after length + // field ) + sduAcceptHeader[idx++] = (byte) ((ssduLength + 18) & 0xff); + + // -- start Connect Accept Item + // Parameter type: Connect Accept Item (5) + sduAcceptHeader[idx++] = 0x05; + // Parameter length + sduAcceptHeader[idx++] = 0x06; + + // Protocol options: + // Parameter Type: Protocol Options (19) + sduAcceptHeader[idx++] = 0x13; + // Parameter length + sduAcceptHeader[idx++] = 0x01; + // flags: (.... ...0 = Able to receive extended concatenated SPDU: + // False) + sduAcceptHeader[idx++] = 0x00; + + // Version number: + // Parameter type: Version Number (22) + sduAcceptHeader[idx++] = 0x16; + // Parameter length + sduAcceptHeader[idx++] = 0x01; + // flags: (.... ..1. = Protocol Version 2: True) + sduAcceptHeader[idx++] = 0x02; + // -- end Connect Accept Item + + // Session Requirement + // Parameter type: Session Requirement (20) + sduAcceptHeader[idx++] = 0x14; + // Parameter length + sduAcceptHeader[idx++] = 0x02; + // flags: (.... .... .... ..1. = Duplex functional unit: True) + sduAcceptHeader[idx++] = 0x00; + sduAcceptHeader[idx++] = 0x02; + + // Called Session Selector + // Parameter type: Called Session Selector (52) + sduAcceptHeader[idx++] = 0x34; + // Parameter length + sduAcceptHeader[idx++] = 0x02; + // Called Session Selector + sduAcceptHeader[idx++] = 0x00; + sduAcceptHeader[idx++] = 0x01; + + // Session user data + // Parameter type: Session user data (193) + sduAcceptHeader[idx++] = (byte) 0xc1; + + // Parameter length + sduAcceptHeader[idx] = (byte) ssduLength; + + ssdu.add(0, sduAcceptHeader); + ssduOffsets.add(0, 0); + ssduLengths.add(0, sduAcceptHeader.length); + + tConnection.send(ssdu, ssduOffsets, ssduLengths); + } + + public ByteBuffer getAssociateResponseAPdu() { + ByteBuffer returnBuffer = associateResponseAPDU; + associateResponseAPDU = null; + return returnBuffer; + } + + void startAssociation( + ByteBuffer payload, + InetAddress address, + int port, + InetAddress localAddr, + int localPort, + String authenticationParameter, + byte[] sSelRemote, + byte[] sSelLocal, + byte[] pSelRemote, + ClientTSap tSAP, + int[] apTitleCalled, + int[] apTitleCalling, + int aeQualifierCalled, + int aeQualifierCalling) + throws IOException { + if (connected) { + throw new IOException(); + } + + APTitle called_ap_title = new APTitle(); + called_ap_title.setApTitleForm2(new APTitleForm2(apTitleCalled)); + APTitle calling_ap_title = new APTitle(); + calling_ap_title.setApTitleForm2(new APTitleForm2(apTitleCalling)); + + AEQualifier called_ae_qualifier = new AEQualifier(); + called_ae_qualifier.setAeQualifierForm2(new AEQualifierForm2(aeQualifierCalled)); + AEQualifier calling_ae_qualifier = new AEQualifier(); + calling_ae_qualifier.setAeQualifierForm2(new AEQualifierForm2(aeQualifierCalling)); + + Myexternal.Encoding encoding = new Myexternal.Encoding(); + encoding.setSingleASN1Type( + new BerAny( + Arrays.copyOfRange( + payload.array(), payload.arrayOffset() + payload.position(), payload.limit()))); + + Myexternal myExternal = new Myexternal(); + myExternal.setDirectReference(directReference); + myExternal.setIndirectReference(indirectReference); + myExternal.setEncoding(encoding); + + AssociationInformation userInformation = new AssociationInformation(); + List externalList = userInformation.getMyexternal(); + externalList.add(myExternal); + + ACSERequirements sender_acse_requirements = null; + MechanismName mechanism_name = null; + AuthenticationValue authentication_value = null; + if (authenticationParameter != null) { + sender_acse_requirements = + new ACSERequirements(new byte[] {(byte) 0x02, (byte) 0x07, (byte) 0x80}); + mechanism_name = default_mechanism_name; + authentication_value = new AuthenticationValue(); + authentication_value.setCharstring( + new BerGraphicString(authenticationParameter.getBytes(UTF_8))); + } + + AARQApdu aarq = new AARQApdu(); + aarq.setApplicationContextName(application_context_name); + aarq.setCalledAPTitle(called_ap_title); + aarq.setCalledAEQualifier(called_ae_qualifier); + aarq.setCallingAPTitle(calling_ap_title); + aarq.setCallingAEQualifier(calling_ae_qualifier); + aarq.setSenderAcseRequirements(sender_acse_requirements); + aarq.setMechanismName(mechanism_name); + aarq.setCallingAuthenticationValue(authentication_value); + aarq.setUserInformation(userInformation); + + ACSEApdu acse = new ACSEApdu(); + acse.setAarq(aarq); + + ReverseByteArrayOutputStream reverseOStream = new ReverseByteArrayOutputStream(200, true); + acse.encode(reverseOStream); + + UserData userData = getPresentationUserDataField(reverseOStream.getArray()); + + CPType.NormalModeParameters normalModeParameter = new CPType.NormalModeParameters(); + normalModeParameter.setCallingPresentationSelector( + new CallingPresentationSelector(pSelLocalBerOctetString.value)); + normalModeParameter.setCalledPresentationSelector(new CalledPresentationSelector(pSelRemote)); + normalModeParameter.setPresentationContextDefinitionList(context_list); + normalModeParameter.setUserData(userData); + + CPType cpType = new CPType(); + cpType.setModeSelector(normalModeSelector); + cpType.setNormalModeParameters(normalModeParameter); + + reverseOStream.reset(); + cpType.encode(reverseOStream, true); + + List ssduList = new ArrayList<>(); + List ssduOffsets = new ArrayList<>(); + List ssduLengths = new ArrayList<>(); + + ssduList.add(reverseOStream.buffer); + ssduOffsets.add(reverseOStream.index + 1); + ssduLengths.add(reverseOStream.buffer.length - (reverseOStream.index + 1)); + + ByteBuffer res = + startSConnection( + ssduList, + ssduOffsets, + ssduLengths, + address, + port, + localAddr, + localPort, + tSAP, + sSelRemote, + sSelLocal); + + associateResponseAPDU = decodePConResponse(res); + } + + private ByteBuffer startSConnection( + List ssduList, + List ssduOffsets, + List ssduLengths, + InetAddress address, + int port, + InetAddress localAddr, + int localPort, + ClientTSap tSAP, + byte[] sSelRemote, + byte[] sSelLocal) + throws IOException { + if (connected) { + throw new IOException(); + } + + byte[] spduHeader = new byte[24]; + int idx = 0; + // byte[] res = null; + + int ssduLength = 0; + for (int ssduElementLength : ssduLengths) { + ssduLength += ssduElementLength; + } + + // write ISO 8327-1 Header + // SPDU Type: CONNECT (13) + spduHeader[idx++] = 0x0d; + // Length: length of session user data + 22 ( header data after + // length field ) + spduHeader[idx++] = (byte) ((ssduLength + 22) & 0xff); + + // -- start Connect Accept Item + // Parameter type: Connect Accept Item (5) + spduHeader[idx++] = 0x05; + // Parameter length + spduHeader[idx++] = 0x06; + + // Protocol options: + // Parameter Type: Protocol Options (19) + spduHeader[idx++] = 0x13; + // Parameter length + spduHeader[idx++] = 0x01; + // flags: (.... ...0 = Able to receive extended concatenated SPDU: + // False) + spduHeader[idx++] = 0x00; + + // Version number: + // Parameter type: Version Number (22) + spduHeader[idx++] = 0x16; + // Parameter length + spduHeader[idx++] = 0x01; + // flags: (.... ..1. = Protocol Version 2: True) + spduHeader[idx++] = 0x02; + // -- end Connect Accept Item + + // Session Requirement + // Parameter type: Session Requirement (20) + spduHeader[idx++] = 0x14; + // Parameter length + spduHeader[idx++] = 0x02; + // flags: (.... .... .... ..1. = Duplex functional unit: True) + spduHeader[idx++] = 0x00; + spduHeader[idx++] = 0x02; + + // Calling Session Selector + // Parameter type: Calling Session Selector (51) + spduHeader[idx++] = 0x33; + // Parameter length + spduHeader[idx++] = 0x02; + // Calling Session Selector + spduHeader[idx++] = sSelRemote[0]; + spduHeader[idx++] = sSelRemote[1]; + + // Called Session Selector + // Parameter type: Called Session Selector (52) + spduHeader[idx++] = 0x34; + // Parameter length + spduHeader[idx++] = 0x02; + // Called Session Selector + spduHeader[idx++] = sSelLocal[0]; + spduHeader[idx++] = sSelLocal[1]; + + // Session user data + // Parameter type: Session user data (193) + spduHeader[idx++] = (byte) 0xc1; + // Parameter length + spduHeader[idx] = (byte) (ssduLength & 0xff); + // write session user data + + ssduList.add(0, spduHeader); + ssduOffsets.add(0, 0); + ssduLengths.add(0, spduHeader.length); + + tConnection = tSAP.connectTo(address, port, localAddr, localPort); + + tConnection.send(ssduList, ssduOffsets, ssduLengths); + + // TODO how much should be allocated here? + ByteBuffer pduBuffer = ByteBuffer.allocate(500); + + try { + tConnection.receive(pduBuffer); + } catch (TimeoutException e) { + throw new IOException("ResponseTimeout waiting for connection response.", e); + } + + // read ISO 8327-1 Header + // SPDU Type: ACCEPT (14) + byte spduType = pduBuffer.get(); + if (spduType != 0x0e) { + throw new IOException( + "ISO 8327-1 header wrong SPDU type, expected ACCEPT (14), got " + + getSPDUTypeString(spduType) + + " (" + + spduType + + ")"); + } + pduBuffer.get(); // skip length byte + + parameter_loop: + while (true) { + // read parameter type + int parameterType = pduBuffer.get() & 0xff; + // read parameter length + int parameterLength = pduBuffer.get() & 0xff; + + switch (parameterType) { + // Connect Accept Item (5) + case 0x05: + int bytesToRead = parameterLength; + while (bytesToRead > 0) { + // read parameter type + int ca_parameterType = pduBuffer.get(); + // read parameter length + // int ca_parameterLength = res[idx++]; + pduBuffer.get(); + + bytesToRead -= 2; + + switch (ca_parameterType & 0xff) { + // Protocol Options (19) + case 0x13: + // flags: .... ...0 = Able to receive extended + // concatenated SPDU: False + byte protocolOptions = pduBuffer.get(); + if (protocolOptions != 0x00) { + throw new IOException( + "SPDU Connect Accept Item/Protocol Options is " + + protocolOptions + + ", expected 0"); + } + + bytesToRead--; + break; + // Version Number + case 0x16: + // flags .... ..1. = Protocol Version 2: True + byte versionNumber = pduBuffer.get(); + if (versionNumber != 0x02) { + throw new IOException( + "SPDU Connect Accept Item/Version Number is " + + versionNumber + + ", expected 2"); + } + + bytesToRead--; + break; + default: + throw new IOException( + "SPDU Connect Accept Item: parameter not implemented: " + ca_parameterType); + } + } + break; + // Session Requirement (20) + case 0x14: + // flags: (.... .... .... ..1. = Duplex functional unit: True) + long sessionRequirement = extractInteger(pduBuffer, parameterLength); + if (sessionRequirement != 0x02) { + throw new IOException( + "SPDU header parameter 'Session Requirement (20)' is " + + sessionRequirement + + ", expected 2"); + } + break; + // Calling Session Selector (51) + case 0x33: + long css = extractInteger(pduBuffer, parameterLength); + if (css != 0x01) { + throw new IOException( + "SPDU header parameter 'Calling Session Selector (51)' is " + css + ", expected 1"); + } + break; + // Called Session Selector (52) + case 0x34: + long calledSessionSelector = extractInteger(pduBuffer, parameterLength); + if (calledSessionSelector != 0x01) { + throw new IOException( + "SPDU header parameter 'Called Session Selector (52)' is " + + calledSessionSelector + + ", expected 1"); + } + break; + // Session user data (193) + case 0xc1: + break parameter_loop; + default: + throw new IOException("SPDU header parameter type " + parameterType + " not implemented"); + } + } + + // got correct ACCEPT (AC) from the server + + connected = true; + + return pduBuffer; + } + + public void send(ByteBuffer payload) throws IOException { + + List ssduList = new ArrayList<>(); + List ssduOffsets = new ArrayList<>(); + List ssduLengths = new ArrayList<>(); + + encodePresentationLayer(payload, ssduList, ssduOffsets, ssduLengths); + + encodeSessionLayer(ssduList, ssduOffsets, ssduLengths); + + tConnection.send(ssduList, ssduOffsets, ssduLengths); + } + + private void encodePresentationLayer( + ByteBuffer payload, + List ssduList, + List ssduOffsets, + List ssduLengths) + throws IOException { + PDVList pdv_list = new PDVList(); + pdv_list.setPresentationContextIdentifier(new PresentationContextIdentifier(3L)); + + PDVList.PresentationDataValues presentationDataValues = new PDVList.PresentationDataValues(); + presentationDataValues.setSingleASN1Type( + new BerAny( + Arrays.copyOfRange( + payload.array(), payload.arrayOffset() + payload.position(), payload.limit()))); + pdv_list.setPresentationDataValues(presentationDataValues); + + FullyEncodedData fully_encoded_data = new FullyEncodedData(); + List pdv_list_list = fully_encoded_data.getPDVList(); + pdv_list_list.add(pdv_list); + + UserData user_data = new UserData(); + user_data.setFullyEncodedData(fully_encoded_data); + + ReverseByteArrayOutputStream reverseOStream = new ReverseByteArrayOutputStream(200, true); + user_data.encode(reverseOStream); + + ssduList.add(reverseOStream.buffer); + ssduOffsets.add(reverseOStream.index + 1); + ssduLengths.add(reverseOStream.buffer.length - (reverseOStream.index + 1)); + } + + private void encodeSessionLayer( + List ssduList, List ssduOffsets, List ssduLengths) { + + byte[] spduHeader = new byte[4]; + // --write iso 8327-1 Header-- + // write SPDU Type: give tokens PDU + spduHeader[0] = 0x01; + // length 0 + spduHeader[1] = 0; + // write SPDU Type: DATA TRANSFER (DT) + spduHeader[2] = 0x01; + // length 0 + spduHeader[3] = 0; + + ssduList.add(0, spduHeader); + ssduOffsets.add(0, 0); + ssduLengths.add(0, spduHeader.length); + } + + /** + * Listens for a new PDU and writes it into the given buffer. Decodes all ACSE and lower layer + * headers. The resulting buffer's position points to the beginning of the ACSE SDU. The limit + * will point to the byte after the last byte of the ACSE SDU. + * + * @param pduBuffer buffer to write the received pdu into + * @return the received PDU + * @throws DecodingException if a decoding error occurs + * @throws IOException if a non recoverable error occurs. Afterwards the association should be + * closed by the user + * @throws TimeoutException if a timeout occurs + */ + public byte[] receive(ByteBuffer pduBuffer) + throws DecodingException, IOException, TimeoutException { + if (!connected) { + throw new IllegalStateException("ACSE Association not connected"); + } + tConnection.receive(pduBuffer); + + decodeSessionLayer(pduBuffer); + + return decodePresentationLayer(pduBuffer); + } + + private byte[] decodePresentationLayer(ByteBuffer pduBuffer) throws DecodingException { + // decode PPDU header + UserData user_data = new UserData(); + + try { + user_data.decode(new ByteBufferInputStream(pduBuffer), null); + } catch (IOException e) { + throw new DecodingException("error decoding PPDU header", e); + } + + return user_data + .getFullyEncodedData() + .getPDVList() + .get(0) + .getPresentationDataValues() + .getSingleASN1Type() + .value; + } + + private void decodeSessionLayer(ByteBuffer pduBuffer) throws EOFException, DecodingException { + int firstByte = pduBuffer.get(); + + if (firstByte == 25) { + // got an ABORT SPDU + throw new EOFException("Received an ABORT SPDU"); + } + + // -- read ISO 8327-1 header + // SPDU type: Give tokens PDU (1) + if (firstByte != 0x01) { + throw new DecodingException("SPDU header syntax errror: first SPDU type not 1"); + } + // length + if (pduBuffer.get() != 0) { + throw new DecodingException("SPDU header syntax errror: first SPDU type length not 0"); + } + // SPDU Type: DATA TRANSFER (DT) SPDU (1) + if (pduBuffer.get() != 0x01) { + throw new DecodingException("SPDU header syntax errror: second SPDU type not 1"); + } + // length + if (pduBuffer.get() != 0) { + throw new DecodingException("SPDU header syntax errror: second SPDU type length not 0"); + } + } + + /** + * Disconnects by sending a disconnect request at the Transport Layer and then closing the socket. + */ + public void disconnect() { + connected = false; + if (tConnection != null) { + tConnection.disconnect(); + } + } + + /** Closes the connection simply by closing the socket. */ + public void close() { + connected = false; + if (tConnection != null) { + tConnection.close(); + } + } + + private long extractInteger(ByteBuffer buffer, int size) throws IOException { + switch (size) { + case 1: + return buffer.get(); + case 2: + return buffer.getShort(); + case 4: + return buffer.getInt(); + case 8: + return buffer.getLong(); + default: + throw new IOException("invalid length for reading numeric value"); + } + } + + ByteBuffer listenForCn(ByteBuffer pduBuffer) throws IOException, TimeoutException { + if (connected) { + throw new IllegalStateException("ACSE Association is already connected"); + } + int parameter; + int parameterLength; + + tConnection.receive(pduBuffer); + // start reading ISO 8327-1 header + // SPDU Type: CONNECT (CN) SPDU (13) + byte spduType = pduBuffer.get(); + if (spduType != 0x0d) { + throw new IOException( + "ISO 8327-1 header wrong SPDU type, expected CONNECT (13), got " + + getSPDUTypeString(spduType) + + " (" + + spduType + + ")"); + } + pduBuffer.get(); // skip lenght byte + + parameter_loop: + while (true) { + // read parameter code + parameter = pduBuffer.get() & 0xff; + // read parameter length + parameterLength = pduBuffer.get() & 0xff; + switch (parameter) { + // Connect Accept Item (5) + case 0x05: + int bytesToRead = parameterLength; + while (bytesToRead > 0) { + // read parameter type + int ca_parameterType = pduBuffer.get(); + // read parameter length + pduBuffer.get(); + + bytesToRead -= 2; + + switch (ca_parameterType & 0xff) { + // Protocol Options (19) + case 0x13: + // flags: .... ...0 = Able to receive extended + // concatenated SPDU: False + byte protocolOptions = pduBuffer.get(); + if (protocolOptions != 0x00) { + throw new IOException( + "SPDU Connect Accept Item/Protocol Options is " + + protocolOptions + + ", expected 0"); + } + + bytesToRead--; + break; + // Version Number + case 0x16: + // flags .... ..1. = Protocol Version 2: True + byte versionNumber = pduBuffer.get(); + if (versionNumber != 0x02) { + throw new IOException( + "SPDU Connect Accept Item/Version Number is " + + versionNumber + + ", expected 2"); + } + + bytesToRead--; + break; + default: + throw new IOException( + "SPDU Connect Accept Item: parameter not implemented: " + ca_parameterType); + } + } + break; + // Session Requirement (20) + case 0x14: + // flags: (.... .... .... ..1. = Duplex functional unit: True) + long sessionRequirement = extractInteger(pduBuffer, parameterLength); + if (sessionRequirement != 0x02) { + throw new IOException( + "SPDU header parameter 'Session Requirement (20)' is " + + sessionRequirement + + ", expected 2"); + } + break; + // Calling Session Selector (51) + case 0x33: + extractInteger(pduBuffer, parameterLength); + break; + // Called Session Selector (52) + case 0x34: + long calledSessionSelector = extractInteger(pduBuffer, parameterLength); + if (calledSessionSelector != 0x01) { + throw new IOException( + "SPDU header parameter 'Called Session Selector (52)' is " + + calledSessionSelector + + ", expected 1"); + } + break; + // Session user data (193) + case 0xc1: + break parameter_loop; + default: + throw new IOException("SPDU header parameter type " + parameter + " not implemented"); + } + } + + CPType cpType = new CPType(); + InputStream iStream = new ByteBufferInputStream(pduBuffer); + cpType.decode(iStream, true); + + iStream = + new ByteArrayInputStream( + cpType + .getNormalModeParameters() + .getUserData() + .getFullyEncodedData() + .getPDVList() + .get(0) + .getPresentationDataValues() + .getSingleASN1Type() + .value); + + ACSEApdu acseApdu = new ACSEApdu(); + acseApdu.decode(iStream, null); + return ByteBuffer.wrap( + acseApdu + .getAarq() + .getUserInformation() + .getMyexternal() + .get(0) + .getEncoding() + .getSingleASN1Type() + .value); + } + + public int getMessageTimeout() { + return tConnection.getMessageTimeout(); + } + + public void setMessageTimeout(int i) { + tConnection.setMessageTimeout(i); + } +} diff --git a/src/main/java/com/beanit/josistack/AcseAssociationListener.java b/src/main/java/com/beanit/josistack/AcseAssociationListener.java new file mode 100644 index 0000000..7d8f358 --- /dev/null +++ b/src/main/java/com/beanit/josistack/AcseAssociationListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.josistack; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public interface AcseAssociationListener { + + void connectionIndication(AcseAssociation acseAssociation, ByteBuffer data); + + void serverStoppedListeningIndication(IOException e); +} diff --git a/src/main/java/com/beanit/josistack/ByteBufferInputStream.java b/src/main/java/com/beanit/josistack/ByteBufferInputStream.java new file mode 100644 index 0000000..2433b68 --- /dev/null +++ b/src/main/java/com/beanit/josistack/ByteBufferInputStream.java @@ -0,0 +1,56 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.josistack; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +/** + * Simple InputStream wrapper around a {@link ByteBuffer} object + * + * @author Karsten Mueller-Bier + */ +public final class ByteBufferInputStream extends InputStream { + + private final ByteBuffer buf; + + public ByteBufferInputStream(ByteBuffer buf) { + this.buf = buf; + } + + @Override + public int read() throws IOException { + if (buf.hasRemaining() == false) { + return -1; + } + return buf.get() & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (buf.hasRemaining() == false) { + return -1; + } + int size = Math.min(len, available()); + + buf.get(b, off, size); + return size; + } + + @Override + public int available() throws IOException { + return buf.limit() - buf.position(); + } +} diff --git a/src/main/java/com/beanit/josistack/ClientAcseSap.java b/src/main/java/com/beanit/josistack/ClientAcseSap.java new file mode 100644 index 0000000..82bc537 --- /dev/null +++ b/src/main/java/com/beanit/josistack/ClientAcseSap.java @@ -0,0 +1,116 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.josistack; + +import com.beanit.jositransport.ClientTSap; +import java.io.IOException; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import javax.net.SocketFactory; + +/** + * This class implements the Service Access Point (SAP) for the Application Control Service Element + * (ACSE) protocol as defined by ISO 8650 or ITU X.217/X.227. The ACSE provides services for + * establishing and releasing application-associations. The class also realizes the lower ISO + * Presentation Layer as defined by ISO 8823/ITU X226 and the ISO Session Layer as defined by + * 8327/ITU X.225. + */ +public final class ClientAcseSap { + + static final byte[] P_SEL_DEFAULT = {0, 0, 0, 1}; + static final byte[] S_SEL_DEFAULT = {0, 1}; + public ClientTSap tSap = null; + public byte[] pSelRemote = P_SEL_DEFAULT; + public byte[] pSelLocal = P_SEL_DEFAULT; + public byte[] sSelRemote = S_SEL_DEFAULT; + public byte[] sSelLocal = S_SEL_DEFAULT; + + private int[] apTitleCalled = new int[] {1, 1, 999, 1, 1}; + private int[] apTitleCalling = new int[] {1, 1, 999, 1}; + private int aeQualifierCalled = 12; + private int aeQualifierCalling = 12; + + /** + * Use this constructor to create a client ACSE Service Access Point (SAP) that will start + * connections to remote ACSE SAPs. Once constructed the AcseSAP contains a public TSAP that can + * be accessed to set its configuration. + */ + public ClientAcseSap() { + tSap = new ClientTSap(); + } + + public ClientAcseSap(SocketFactory socketFactory) { + tSap = new ClientTSap(socketFactory); + } + + public void setApTitleCalled(int[] title) { + this.apTitleCalled = title; + } + + public void setApTitleCalling(int[] title) { + this.apTitleCalling = title; + } + + public void setAeQualifierCalled(int qualifier) { + this.aeQualifierCalled = qualifier; + } + + public void setAeQualifierCalling(int qualifier) { + this.aeQualifierCalling = qualifier; + } + + /** + * Associate to a remote ServerAcseSAP that is listening at the destination address. + * + * @param address remote InetAddress + * @param port remote port + * @param localAddr local InetAddress + * @param localPort local port + * @param authenticationParameter an authentication parameter + * @param apdu the payload to send with the association request + * @return the association object + * @throws IOException if an error occurs connecting + */ + public AcseAssociation associate( + InetAddress address, + int port, + InetAddress localAddr, + int localPort, + String authenticationParameter, + ByteBuffer apdu) + throws IOException { + AcseAssociation acseAssociation = new AcseAssociation(null, pSelLocal); + try { + acseAssociation.startAssociation( + apdu, + address, + port, + localAddr, + localPort, + authenticationParameter, + sSelRemote, + sSelLocal, + pSelRemote, + tSap, + apTitleCalled, + apTitleCalling, + aeQualifierCalled, + aeQualifierCalling); + } catch (IOException e) { + acseAssociation.disconnect(); + throw e; + } + return acseAssociation; + } +} diff --git a/src/main/java/com/beanit/josistack/DecodingException.java b/src/main/java/com/beanit/josistack/DecodingException.java new file mode 100644 index 0000000..9aaef12 --- /dev/null +++ b/src/main/java/com/beanit/josistack/DecodingException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.josistack; + +public final class DecodingException extends Exception { + + private static final long serialVersionUID = -4102153710148894434L; + + public DecodingException() { + super(); + } + + public DecodingException(String s) { + super(s); + } + + public DecodingException(Throwable cause) { + super(cause); + } + + public DecodingException(String s, Throwable cause) { + super(s, cause); + } +} diff --git a/src/main/java/com/beanit/josistack/ServerAcseSap.java b/src/main/java/com/beanit/josistack/ServerAcseSap.java new file mode 100644 index 0000000..3c5721b --- /dev/null +++ b/src/main/java/com/beanit/josistack/ServerAcseSap.java @@ -0,0 +1,126 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.josistack; + +import com.beanit.jositransport.ServerTSap; +import com.beanit.jositransport.TConnection; +import com.beanit.jositransport.TConnectionListener; +import java.io.IOException; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.concurrent.TimeoutException; +import javax.net.ServerSocketFactory; + +/** + * This class implements the server Service Access Point (SAP) for the Application Control Service + * Element (ACSE) protocol as defined by ISO 8650 or ITU X.217/X.227. The ACSE provides services for + * establishing and releasing application-associations. The class also realizes the lower ISO + * Presentation Layer as defined by ISO 8823/ITU X226 and the ISO Session Layer as defined by + * 8327/ITU X.225. + */ +public final class ServerAcseSap implements TConnectionListener { + + public ServerTSap serverTSap = null; + public byte[] pSelLocal = ClientAcseSap.P_SEL_DEFAULT; + private AcseAssociationListener associationListener = null; + + /** + * Use this constructor to create a server ACSE SAP that listens on a fixed port. + * + * @param port the local port listen on + * @param backlog the backlog + * @param bindAddr the InetAddress to bind to + * @param associationListener the AssociationListener that will be notified when remote clients + * have associated. Once constructed the AcseSAP contains a public TSAP that can be accessed + * to set its configuration. + */ + public ServerAcseSap( + int port, int backlog, InetAddress bindAddr, AcseAssociationListener associationListener) { + this(port, backlog, bindAddr, associationListener, ServerSocketFactory.getDefault()); + } + + /** + * Use this constructor to create a server ACSE SAP that listens on a fixed port. The server + * socket is created with the given socket factory. + * + * @param port the local port listen on + * @param backlog the backlog + * @param bindAddr the InetAddress to bind to + * @param associationListener the AssociationListener that will be notified when remote clients + * have associated. Once constructed the AcseSAP contains a public TSAP that can be accessed + * to set its configuration. + * @param serverSocketFactory the server socket factory to create the socket + */ + public ServerAcseSap( + int port, + int backlog, + InetAddress bindAddr, + AcseAssociationListener associationListener, + ServerSocketFactory serverSocketFactory) { + this.associationListener = associationListener; + serverTSap = new ServerTSap(port, backlog, bindAddr, this, serverSocketFactory); + } + + /** + * Start listening for incoming connections. Only for server SAPs. + * + * @throws IOException if an error occures starting to listen + */ + public void startListening() throws IOException { + if (associationListener == null || serverTSap == null) { + throw new IllegalStateException( + "AcseSAP is unable to listen because it was not initialized."); + } + serverTSap.startListening(); + } + + public void stopListening() { + serverTSap.stopListening(); + } + + /** This function is internal and should not be called by users of this class. */ + @Override + public void serverStoppedListeningIndication(IOException e) { + associationListener.serverStoppedListeningIndication(e); + } + + /** This function is internal and should not be called by users of this class. */ + @Override + public void connectionIndication(TConnection tConnection) { + + try { + + AcseAssociation acseAssociation = new AcseAssociation(tConnection, pSelLocal); + + ByteBuffer asdu = ByteBuffer.allocate(1000); + try { + asdu = acseAssociation.listenForCn(asdu); + } catch (IOException e) { + // Server: Connection unsuccessful. + tConnection.close(); + return; + } catch (TimeoutException e) { + // Illegal state: Timeout should not occur here + tConnection.close(); + return; + } + + associationListener.connectionIndication(acseAssociation, asdu); + + } catch (Exception e) { + // Association closed because of an unexpected exception. + tConnection.close(); + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AAREApdu.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AAREApdu.java new file mode 100644 index 0000000..fade08f --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AAREApdu.java @@ -0,0 +1,613 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AAREApdu implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.APPLICATION_CLASS, BerTag.CONSTRUCTED, 1); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerBitString protocolVersion = null; + private BerObjectIdentifier applicationContextName = null; + private AssociateResult result = null; + private AssociateSourceDiagnostic resultSourceDiagnostic = null; + private APTitle respondingAPTitle = null; + private AEQualifier respondingAEQualifier = null; + private APInvocationIdentifier respondingAPInvocationIdentifier = null; + private AEInvocationIdentifier respondingAEInvocationIdentifier = null; + private ACSERequirements responderAcseRequirements = null; + private MechanismName mechanismName = null; + private AuthenticationValue respondingAuthenticationValue = null; + private ApplicationContextNameList applicationContextNameList = null; + private ImplementationData implementationInformation = null; + private AssociationInformation userInformation = null; + + public AAREApdu() {} + + public AAREApdu(byte[] code) { + this.code = code; + } + + public BerBitString getProtocolVersion() { + return protocolVersion; + } + + public void setProtocolVersion(BerBitString protocolVersion) { + this.protocolVersion = protocolVersion; + } + + public BerObjectIdentifier getApplicationContextName() { + return applicationContextName; + } + + public void setApplicationContextName(BerObjectIdentifier applicationContextName) { + this.applicationContextName = applicationContextName; + } + + public AssociateResult getResult() { + return result; + } + + public void setResult(AssociateResult result) { + this.result = result; + } + + public AssociateSourceDiagnostic getResultSourceDiagnostic() { + return resultSourceDiagnostic; + } + + public void setResultSourceDiagnostic(AssociateSourceDiagnostic resultSourceDiagnostic) { + this.resultSourceDiagnostic = resultSourceDiagnostic; + } + + public APTitle getRespondingAPTitle() { + return respondingAPTitle; + } + + public void setRespondingAPTitle(APTitle respondingAPTitle) { + this.respondingAPTitle = respondingAPTitle; + } + + public AEQualifier getRespondingAEQualifier() { + return respondingAEQualifier; + } + + public void setRespondingAEQualifier(AEQualifier respondingAEQualifier) { + this.respondingAEQualifier = respondingAEQualifier; + } + + public APInvocationIdentifier getRespondingAPInvocationIdentifier() { + return respondingAPInvocationIdentifier; + } + + public void setRespondingAPInvocationIdentifier( + APInvocationIdentifier respondingAPInvocationIdentifier) { + this.respondingAPInvocationIdentifier = respondingAPInvocationIdentifier; + } + + public AEInvocationIdentifier getRespondingAEInvocationIdentifier() { + return respondingAEInvocationIdentifier; + } + + public void setRespondingAEInvocationIdentifier( + AEInvocationIdentifier respondingAEInvocationIdentifier) { + this.respondingAEInvocationIdentifier = respondingAEInvocationIdentifier; + } + + public ACSERequirements getResponderAcseRequirements() { + return responderAcseRequirements; + } + + public void setResponderAcseRequirements(ACSERequirements responderAcseRequirements) { + this.responderAcseRequirements = responderAcseRequirements; + } + + public MechanismName getMechanismName() { + return mechanismName; + } + + public void setMechanismName(MechanismName mechanismName) { + this.mechanismName = mechanismName; + } + + public AuthenticationValue getRespondingAuthenticationValue() { + return respondingAuthenticationValue; + } + + public void setRespondingAuthenticationValue(AuthenticationValue respondingAuthenticationValue) { + this.respondingAuthenticationValue = respondingAuthenticationValue; + } + + public ApplicationContextNameList getApplicationContextNameList() { + return applicationContextNameList; + } + + public void setApplicationContextNameList(ApplicationContextNameList applicationContextNameList) { + this.applicationContextNameList = applicationContextNameList; + } + + public ImplementationData getImplementationInformation() { + return implementationInformation; + } + + public void setImplementationInformation(ImplementationData implementationInformation) { + this.implementationInformation = implementationInformation; + } + + public AssociationInformation getUserInformation() { + return userInformation; + } + + public void setUserInformation(AssociationInformation userInformation) { + this.userInformation = userInformation; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + if (userInformation != null) { + codeLength += userInformation.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 30 + reverseOS.write(0xBE); + codeLength += 1; + } + + if (implementationInformation != null) { + codeLength += implementationInformation.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 29 + reverseOS.write(0x9D); + codeLength += 1; + } + + if (applicationContextNameList != null) { + codeLength += applicationContextNameList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 11 + reverseOS.write(0xAB); + codeLength += 1; + } + + if (respondingAuthenticationValue != null) { + sublength = respondingAuthenticationValue.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 10 + reverseOS.write(0xAA); + codeLength += 1; + } + + if (mechanismName != null) { + codeLength += mechanismName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 9 + reverseOS.write(0x89); + codeLength += 1; + } + + if (responderAcseRequirements != null) { + codeLength += responderAcseRequirements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 8 + reverseOS.write(0x88); + codeLength += 1; + } + + if (respondingAEInvocationIdentifier != null) { + sublength = respondingAEInvocationIdentifier.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 7 + reverseOS.write(0xA7); + codeLength += 1; + } + + if (respondingAPInvocationIdentifier != null) { + sublength = respondingAPInvocationIdentifier.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 6 + reverseOS.write(0xA6); + codeLength += 1; + } + + if (respondingAEQualifier != null) { + sublength = respondingAEQualifier.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 5 + reverseOS.write(0xA5); + codeLength += 1; + } + + if (respondingAPTitle != null) { + sublength = respondingAPTitle.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + } + + sublength = resultSourceDiagnostic.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 3 + reverseOS.write(0xA3); + codeLength += 1; + + sublength = result.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + + sublength = applicationContextName.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + if (protocolVersion != null) { + codeLength += protocolVersion.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + protocolVersion = new BerBitString(); + vByteCount += protocolVersion.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + vByteCount += length.decode(is); + applicationContextName = new BerObjectIdentifier(); + vByteCount += applicationContextName.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + vByteCount += length.decode(is); + result = new AssociateResult(); + vByteCount += result.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 3)) { + vByteCount += length.decode(is); + resultSourceDiagnostic = new AssociateSourceDiagnostic(); + vByteCount += resultSourceDiagnostic.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + vByteCount += length.decode(is); + respondingAPTitle = new APTitle(); + vByteCount += respondingAPTitle.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 5)) { + vByteCount += length.decode(is); + respondingAEQualifier = new AEQualifier(); + vByteCount += respondingAEQualifier.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 6)) { + vByteCount += length.decode(is); + respondingAPInvocationIdentifier = new APInvocationIdentifier(); + vByteCount += respondingAPInvocationIdentifier.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 7)) { + vByteCount += length.decode(is); + respondingAEInvocationIdentifier = new AEInvocationIdentifier(); + vByteCount += respondingAEInvocationIdentifier.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 8)) { + responderAcseRequirements = new ACSERequirements(); + vByteCount += responderAcseRequirements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 9)) { + mechanismName = new MechanismName(); + vByteCount += mechanismName.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 10)) { + vByteCount += length.decode(is); + respondingAuthenticationValue = new AuthenticationValue(); + vByteCount += respondingAuthenticationValue.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 11)) { + applicationContextNameList = new ApplicationContextNameList(); + vByteCount += applicationContextNameList.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 29)) { + implementationInformation = new ImplementationData(); + vByteCount += implementationInformation.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 30)) { + userInformation = new AssociationInformation(); + vByteCount += userInformation.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (protocolVersion != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("protocolVersion: ").append(protocolVersion); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (applicationContextName != null) { + sb.append("applicationContextName: ").append(applicationContextName); + } else { + sb.append("applicationContextName: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (result != null) { + sb.append("result: ").append(result); + } else { + sb.append("result: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (resultSourceDiagnostic != null) { + sb.append("resultSourceDiagnostic: "); + resultSourceDiagnostic.appendAsString(sb, indentLevel + 1); + } else { + sb.append("resultSourceDiagnostic: "); + } + + if (respondingAPTitle != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("respondingAPTitle: "); + respondingAPTitle.appendAsString(sb, indentLevel + 1); + } + + if (respondingAEQualifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("respondingAEQualifier: "); + respondingAEQualifier.appendAsString(sb, indentLevel + 1); + } + + if (respondingAPInvocationIdentifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("respondingAPInvocationIdentifier: ").append(respondingAPInvocationIdentifier); + } + + if (respondingAEInvocationIdentifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("respondingAEInvocationIdentifier: ").append(respondingAEInvocationIdentifier); + } + + if (responderAcseRequirements != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("responderAcseRequirements: ").append(responderAcseRequirements); + } + + if (mechanismName != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("mechanismName: ").append(mechanismName); + } + + if (respondingAuthenticationValue != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("respondingAuthenticationValue: "); + respondingAuthenticationValue.appendAsString(sb, indentLevel + 1); + } + + if (applicationContextNameList != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("applicationContextNameList: "); + applicationContextNameList.appendAsString(sb, indentLevel + 1); + } + + if (implementationInformation != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("implementationInformation: ").append(implementationInformation); + } + + if (userInformation != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userInformation: "); + userInformation.appendAsString(sb, indentLevel + 1); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AARQApdu.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AARQApdu.java new file mode 100644 index 0000000..aa58c69 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AARQApdu.java @@ -0,0 +1,690 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AARQApdu implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.APPLICATION_CLASS, BerTag.CONSTRUCTED, 0); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerBitString protocolVersion = null; + private BerObjectIdentifier applicationContextName = null; + private APTitle calledAPTitle = null; + private AEQualifier calledAEQualifier = null; + private APInvocationIdentifier calledAPInvocationIdentifier = null; + private AEInvocationIdentifier calledAEInvocationIdentifier = null; + private APTitle callingAPTitle = null; + private AEQualifier callingAEQualifier = null; + private APInvocationIdentifier callingAPInvocationIdentifier = null; + private AEInvocationIdentifier callingAEInvocationIdentifier = null; + private ACSERequirements senderAcseRequirements = null; + private MechanismName mechanismName = null; + private AuthenticationValue callingAuthenticationValue = null; + private ApplicationContextNameList applicationContextNameList = null; + private ImplementationData implementationInformation = null; + private AssociationInformation userInformation = null; + + public AARQApdu() {} + + public AARQApdu(byte[] code) { + this.code = code; + } + + public BerBitString getProtocolVersion() { + return protocolVersion; + } + + public void setProtocolVersion(BerBitString protocolVersion) { + this.protocolVersion = protocolVersion; + } + + public BerObjectIdentifier getApplicationContextName() { + return applicationContextName; + } + + public void setApplicationContextName(BerObjectIdentifier applicationContextName) { + this.applicationContextName = applicationContextName; + } + + public APTitle getCalledAPTitle() { + return calledAPTitle; + } + + public void setCalledAPTitle(APTitle calledAPTitle) { + this.calledAPTitle = calledAPTitle; + } + + public AEQualifier getCalledAEQualifier() { + return calledAEQualifier; + } + + public void setCalledAEQualifier(AEQualifier calledAEQualifier) { + this.calledAEQualifier = calledAEQualifier; + } + + public APInvocationIdentifier getCalledAPInvocationIdentifier() { + return calledAPInvocationIdentifier; + } + + public void setCalledAPInvocationIdentifier(APInvocationIdentifier calledAPInvocationIdentifier) { + this.calledAPInvocationIdentifier = calledAPInvocationIdentifier; + } + + public AEInvocationIdentifier getCalledAEInvocationIdentifier() { + return calledAEInvocationIdentifier; + } + + public void setCalledAEInvocationIdentifier(AEInvocationIdentifier calledAEInvocationIdentifier) { + this.calledAEInvocationIdentifier = calledAEInvocationIdentifier; + } + + public APTitle getCallingAPTitle() { + return callingAPTitle; + } + + public void setCallingAPTitle(APTitle callingAPTitle) { + this.callingAPTitle = callingAPTitle; + } + + public AEQualifier getCallingAEQualifier() { + return callingAEQualifier; + } + + public void setCallingAEQualifier(AEQualifier callingAEQualifier) { + this.callingAEQualifier = callingAEQualifier; + } + + public APInvocationIdentifier getCallingAPInvocationIdentifier() { + return callingAPInvocationIdentifier; + } + + public void setCallingAPInvocationIdentifier( + APInvocationIdentifier callingAPInvocationIdentifier) { + this.callingAPInvocationIdentifier = callingAPInvocationIdentifier; + } + + public AEInvocationIdentifier getCallingAEInvocationIdentifier() { + return callingAEInvocationIdentifier; + } + + public void setCallingAEInvocationIdentifier( + AEInvocationIdentifier callingAEInvocationIdentifier) { + this.callingAEInvocationIdentifier = callingAEInvocationIdentifier; + } + + public ACSERequirements getSenderAcseRequirements() { + return senderAcseRequirements; + } + + public void setSenderAcseRequirements(ACSERequirements senderAcseRequirements) { + this.senderAcseRequirements = senderAcseRequirements; + } + + public MechanismName getMechanismName() { + return mechanismName; + } + + public void setMechanismName(MechanismName mechanismName) { + this.mechanismName = mechanismName; + } + + public AuthenticationValue getCallingAuthenticationValue() { + return callingAuthenticationValue; + } + + public void setCallingAuthenticationValue(AuthenticationValue callingAuthenticationValue) { + this.callingAuthenticationValue = callingAuthenticationValue; + } + + public ApplicationContextNameList getApplicationContextNameList() { + return applicationContextNameList; + } + + public void setApplicationContextNameList(ApplicationContextNameList applicationContextNameList) { + this.applicationContextNameList = applicationContextNameList; + } + + public ImplementationData getImplementationInformation() { + return implementationInformation; + } + + public void setImplementationInformation(ImplementationData implementationInformation) { + this.implementationInformation = implementationInformation; + } + + public AssociationInformation getUserInformation() { + return userInformation; + } + + public void setUserInformation(AssociationInformation userInformation) { + this.userInformation = userInformation; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + int sublength; + + if (userInformation != null) { + codeLength += userInformation.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 30 + reverseOS.write(0xBE); + codeLength += 1; + } + + if (implementationInformation != null) { + codeLength += implementationInformation.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 29 + reverseOS.write(0x9D); + codeLength += 1; + } + + if (applicationContextNameList != null) { + codeLength += applicationContextNameList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 13 + reverseOS.write(0xAD); + codeLength += 1; + } + + if (callingAuthenticationValue != null) { + sublength = callingAuthenticationValue.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 12 + reverseOS.write(0xAC); + codeLength += 1; + } + + if (mechanismName != null) { + codeLength += mechanismName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 11 + reverseOS.write(0x8B); + codeLength += 1; + } + + if (senderAcseRequirements != null) { + codeLength += senderAcseRequirements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 10 + reverseOS.write(0x8A); + codeLength += 1; + } + + if (callingAEInvocationIdentifier != null) { + sublength = callingAEInvocationIdentifier.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 9 + reverseOS.write(0xA9); + codeLength += 1; + } + + if (callingAPInvocationIdentifier != null) { + sublength = callingAPInvocationIdentifier.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 8 + reverseOS.write(0xA8); + codeLength += 1; + } + + if (callingAEQualifier != null) { + sublength = callingAEQualifier.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 7 + reverseOS.write(0xA7); + codeLength += 1; + } + + if (callingAPTitle != null) { + sublength = callingAPTitle.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 6 + reverseOS.write(0xA6); + codeLength += 1; + } + + if (calledAEInvocationIdentifier != null) { + sublength = calledAEInvocationIdentifier.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 5 + reverseOS.write(0xA5); + codeLength += 1; + } + + if (calledAPInvocationIdentifier != null) { + sublength = calledAPInvocationIdentifier.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + } + + if (calledAEQualifier != null) { + sublength = calledAEQualifier.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 3 + reverseOS.write(0xA3); + codeLength += 1; + } + + if (calledAPTitle != null) { + sublength = calledAPTitle.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + } + + sublength = applicationContextName.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + + if (protocolVersion != null) { + codeLength += protocolVersion.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + protocolVersion = new BerBitString(); + vByteCount += protocolVersion.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + vByteCount += length.decode(is); + applicationContextName = new BerObjectIdentifier(); + vByteCount += applicationContextName.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + vByteCount += length.decode(is); + calledAPTitle = new APTitle(); + vByteCount += calledAPTitle.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 3)) { + vByteCount += length.decode(is); + calledAEQualifier = new AEQualifier(); + vByteCount += calledAEQualifier.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + vByteCount += length.decode(is); + calledAPInvocationIdentifier = new APInvocationIdentifier(); + vByteCount += calledAPInvocationIdentifier.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 5)) { + vByteCount += length.decode(is); + calledAEInvocationIdentifier = new AEInvocationIdentifier(); + vByteCount += calledAEInvocationIdentifier.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 6)) { + vByteCount += length.decode(is); + callingAPTitle = new APTitle(); + vByteCount += callingAPTitle.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 7)) { + vByteCount += length.decode(is); + callingAEQualifier = new AEQualifier(); + vByteCount += callingAEQualifier.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 8)) { + vByteCount += length.decode(is); + callingAPInvocationIdentifier = new APInvocationIdentifier(); + vByteCount += callingAPInvocationIdentifier.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 9)) { + vByteCount += length.decode(is); + callingAEInvocationIdentifier = new AEInvocationIdentifier(); + vByteCount += callingAEInvocationIdentifier.decode(is, true); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 10)) { + senderAcseRequirements = new ACSERequirements(); + vByteCount += senderAcseRequirements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 11)) { + mechanismName = new MechanismName(); + vByteCount += mechanismName.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 12)) { + vByteCount += length.decode(is); + callingAuthenticationValue = new AuthenticationValue(); + vByteCount += callingAuthenticationValue.decode(is, null); + vByteCount += length.readEocIfIndefinite(is); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 13)) { + applicationContextNameList = new ApplicationContextNameList(); + vByteCount += applicationContextNameList.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 29)) { + implementationInformation = new ImplementationData(); + vByteCount += implementationInformation.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 30)) { + userInformation = new AssociationInformation(); + vByteCount += userInformation.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (protocolVersion != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("protocolVersion: ").append(protocolVersion); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (applicationContextName != null) { + sb.append("applicationContextName: ").append(applicationContextName); + } else { + sb.append("applicationContextName: "); + } + + if (calledAPTitle != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("calledAPTitle: "); + calledAPTitle.appendAsString(sb, indentLevel + 1); + } + + if (calledAEQualifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("calledAEQualifier: "); + calledAEQualifier.appendAsString(sb, indentLevel + 1); + } + + if (calledAPInvocationIdentifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("calledAPInvocationIdentifier: ").append(calledAPInvocationIdentifier); + } + + if (calledAEInvocationIdentifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("calledAEInvocationIdentifier: ").append(calledAEInvocationIdentifier); + } + + if (callingAPTitle != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("callingAPTitle: "); + callingAPTitle.appendAsString(sb, indentLevel + 1); + } + + if (callingAEQualifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("callingAEQualifier: "); + callingAEQualifier.appendAsString(sb, indentLevel + 1); + } + + if (callingAPInvocationIdentifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("callingAPInvocationIdentifier: ").append(callingAPInvocationIdentifier); + } + + if (callingAEInvocationIdentifier != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("callingAEInvocationIdentifier: ").append(callingAEInvocationIdentifier); + } + + if (senderAcseRequirements != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("senderAcseRequirements: ").append(senderAcseRequirements); + } + + if (mechanismName != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("mechanismName: ").append(mechanismName); + } + + if (callingAuthenticationValue != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("callingAuthenticationValue: "); + callingAuthenticationValue.appendAsString(sb, indentLevel + 1); + } + + if (applicationContextNameList != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("applicationContextNameList: "); + applicationContextNameList.appendAsString(sb, indentLevel + 1); + } + + if (implementationInformation != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("implementationInformation: ").append(implementationInformation); + } + + if (userInformation != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userInformation: "); + userInformation.appendAsString(sb, indentLevel + 1); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/ACSEApdu.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/ACSEApdu.java new file mode 100644 index 0000000..f4ba6f7 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/ACSEApdu.java @@ -0,0 +1,182 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ACSEApdu implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private AARQApdu aarq = null; + private AAREApdu aare = null; + private RLRQApdu rlrq = null; + private RLREApdu rlre = null; + + public ACSEApdu() {} + + public ACSEApdu(byte[] code) { + this.code = code; + } + + public AARQApdu getAarq() { + return aarq; + } + + public void setAarq(AARQApdu aarq) { + this.aarq = aarq; + } + + public AAREApdu getAare() { + return aare; + } + + public void setAare(AAREApdu aare) { + this.aare = aare; + } + + public RLRQApdu getRlrq() { + return rlrq; + } + + public void setRlrq(RLRQApdu rlrq) { + this.rlrq = rlrq; + } + + public RLREApdu getRlre() { + return rlre; + } + + public void setRlre(RLREApdu rlre) { + this.rlre = rlre; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (rlre != null) { + codeLength += rlre.encode(reverseOS, true); + return codeLength; + } + + if (rlrq != null) { + codeLength += rlrq.encode(reverseOS, true); + return codeLength; + } + + if (aare != null) { + codeLength += aare.encode(reverseOS, true); + return codeLength; + } + + if (aarq != null) { + codeLength += aarq.encode(reverseOS, true); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(AARQApdu.tag)) { + aarq = new AARQApdu(); + tlvByteCount += aarq.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(AAREApdu.tag)) { + aare = new AAREApdu(); + tlvByteCount += aare.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(RLRQApdu.tag)) { + rlrq = new RLRQApdu(); + tlvByteCount += rlrq.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(RLREApdu.tag)) { + rlre = new RLREApdu(); + tlvByteCount += rlre.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (aarq != null) { + sb.append("aarq: "); + aarq.appendAsString(sb, indentLevel + 1); + return; + } + + if (aare != null) { + sb.append("aare: "); + aare.appendAsString(sb, indentLevel + 1); + return; + } + + if (rlrq != null) { + sb.append("rlrq: "); + rlrq.appendAsString(sb, indentLevel + 1); + return; + } + + if (rlre != null) { + sb.append("rlre: "); + rlre.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/ACSERequirements.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/ACSERequirements.java new file mode 100644 index 0000000..ee9ccc3 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/ACSERequirements.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerBitString; + +public class ACSERequirements extends BerBitString { + + private static final long serialVersionUID = 1L; + + public ACSERequirements() {} + + public ACSERequirements(byte[] code) { + super(code); + } + + public ACSERequirements(byte[] value, int numBits) { + super(value, numBits); + } + + public ACSERequirements(boolean[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AEInvocationIdentifier.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AEInvocationIdentifier.java new file mode 100644 index 0000000..df41a35 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AEInvocationIdentifier.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class AEInvocationIdentifier extends BerInteger { + + private static final long serialVersionUID = 1L; + + public AEInvocationIdentifier() {} + + public AEInvocationIdentifier(byte[] code) { + super(code); + } + + public AEInvocationIdentifier(BigInteger value) { + super(value); + } + + public AEInvocationIdentifier(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AEQualifier.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AEQualifier.java new file mode 100644 index 0000000..bf22860 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AEQualifier.java @@ -0,0 +1,103 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AEQualifier implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private AEQualifierForm2 aeQualifierForm2 = null; + + public AEQualifier() {} + + public AEQualifier(byte[] code) { + this.code = code; + } + + public AEQualifierForm2 getAeQualifierForm2() { + return aeQualifierForm2; + } + + public void setAeQualifierForm2(AEQualifierForm2 aeQualifierForm2) { + this.aeQualifierForm2 = aeQualifierForm2; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (aeQualifierForm2 != null) { + codeLength += aeQualifierForm2.encode(reverseOS, true); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(AEQualifierForm2.tag)) { + aeQualifierForm2 = new AEQualifierForm2(); + tlvByteCount += aeQualifierForm2.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (aeQualifierForm2 != null) { + sb.append("aeQualifierForm2: ").append(aeQualifierForm2); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AEQualifierForm2.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AEQualifierForm2.java new file mode 100644 index 0000000..1eb7d80 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AEQualifierForm2.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class AEQualifierForm2 extends BerInteger { + + private static final long serialVersionUID = 1L; + + public AEQualifierForm2() {} + + public AEQualifierForm2(byte[] code) { + super(code); + } + + public AEQualifierForm2(BigInteger value) { + super(value); + } + + public AEQualifierForm2(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AETitle.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AETitle.java new file mode 100644 index 0000000..208dfb3 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AETitle.java @@ -0,0 +1,103 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AETitle implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private AETitleForm2 aeTitleForm2 = null; + + public AETitle() {} + + public AETitle(byte[] code) { + this.code = code; + } + + public AETitleForm2 getAeTitleForm2() { + return aeTitleForm2; + } + + public void setAeTitleForm2(AETitleForm2 aeTitleForm2) { + this.aeTitleForm2 = aeTitleForm2; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (aeTitleForm2 != null) { + codeLength += aeTitleForm2.encode(reverseOS, true); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(AETitleForm2.tag)) { + aeTitleForm2 = new AETitleForm2(); + tlvByteCount += aeTitleForm2.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (aeTitleForm2 != null) { + sb.append("aeTitleForm2: ").append(aeTitleForm2); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AETitleForm2.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AETitleForm2.java new file mode 100644 index 0000000..42215bb --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AETitleForm2.java @@ -0,0 +1,22 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; + +public class AETitleForm2 extends BerObjectIdentifier { + + private static final long serialVersionUID = 1L; + + public AETitleForm2() {} + + public AETitleForm2(byte[] code) { + super(code); + } + + public AETitleForm2(int[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/APInvocationIdentifier.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/APInvocationIdentifier.java new file mode 100644 index 0000000..1c4c4c1 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/APInvocationIdentifier.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class APInvocationIdentifier extends BerInteger { + + private static final long serialVersionUID = 1L; + + public APInvocationIdentifier() {} + + public APInvocationIdentifier(byte[] code) { + super(code); + } + + public APInvocationIdentifier(BigInteger value) { + super(value); + } + + public APInvocationIdentifier(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/APTitle.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/APTitle.java new file mode 100644 index 0000000..de1e497 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/APTitle.java @@ -0,0 +1,103 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class APTitle implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private APTitleForm2 apTitleForm2 = null; + + public APTitle() {} + + public APTitle(byte[] code) { + this.code = code; + } + + public APTitleForm2 getApTitleForm2() { + return apTitleForm2; + } + + public void setApTitleForm2(APTitleForm2 apTitleForm2) { + this.apTitleForm2 = apTitleForm2; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (apTitleForm2 != null) { + codeLength += apTitleForm2.encode(reverseOS, true); + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(APTitleForm2.tag)) { + apTitleForm2 = new APTitleForm2(); + tlvByteCount += apTitleForm2.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (apTitleForm2 != null) { + sb.append("apTitleForm2: ").append(apTitleForm2); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/APTitleForm2.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/APTitleForm2.java new file mode 100644 index 0000000..4c10736 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/APTitleForm2.java @@ -0,0 +1,22 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; + +public class APTitleForm2 extends BerObjectIdentifier { + + private static final long serialVersionUID = 1L; + + public APTitleForm2() {} + + public APTitleForm2(byte[] code) { + super(code); + } + + public APTitleForm2(int[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/ApplicationContextName.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/ApplicationContextName.java new file mode 100644 index 0000000..a9709c9 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/ApplicationContextName.java @@ -0,0 +1,22 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; + +public class ApplicationContextName extends BerObjectIdentifier { + + private static final long serialVersionUID = 1L; + + public ApplicationContextName() {} + + public ApplicationContextName(byte[] code) { + super(code); + } + + public ApplicationContextName(int[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/ApplicationContextNameList.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/ApplicationContextNameList.java new file mode 100644 index 0000000..56aeae0 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/ApplicationContextNameList.java @@ -0,0 +1,153 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ApplicationContextNameList implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ApplicationContextNameList() { + seqOf = new ArrayList(); + } + + public ApplicationContextNameList(byte[] code) { + this.code = code; + } + + public List getApplicationContextName() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(ApplicationContextName.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + ApplicationContextName element = new ApplicationContextName(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + sb.append(it.next()); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append(it.next()); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociateResult.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociateResult.java new file mode 100644 index 0000000..4ee88e5 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociateResult.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class AssociateResult extends BerInteger { + + private static final long serialVersionUID = 1L; + + public AssociateResult() {} + + public AssociateResult(byte[] code) { + super(code); + } + + public AssociateResult(BigInteger value) { + super(value); + } + + public AssociateResult(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociateSourceDiagnostic.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociateSourceDiagnostic.java new file mode 100644 index 0000000..da65d42 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociateSourceDiagnostic.java @@ -0,0 +1,148 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AssociateSourceDiagnostic implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerInteger acseServiceUser = null; + private BerInteger acseServiceProvider = null; + + public AssociateSourceDiagnostic() {} + + public AssociateSourceDiagnostic(byte[] code) { + this.code = code; + } + + public BerInteger getAcseServiceUser() { + return acseServiceUser; + } + + public void setAcseServiceUser(BerInteger acseServiceUser) { + this.acseServiceUser = acseServiceUser; + } + + public BerInteger getAcseServiceProvider() { + return acseServiceProvider; + } + + public void setAcseServiceProvider(BerInteger acseServiceProvider) { + this.acseServiceProvider = acseServiceProvider; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (acseServiceProvider != null) { + sublength = acseServiceProvider.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + return codeLength; + } + + if (acseServiceUser != null) { + sublength = acseServiceUser.encode(reverseOS, true); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + reverseOS.write(0xA1); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + acseServiceUser = new BerInteger(); + tlvByteCount += acseServiceUser.decode(is, true); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + acseServiceProvider = new BerInteger(); + tlvByteCount += acseServiceProvider.decode(is, true); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (acseServiceUser != null) { + sb.append("acseServiceUser: ").append(acseServiceUser); + return; + } + + if (acseServiceProvider != null) { + sb.append("acseServiceProvider: ").append(acseServiceProvider); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociationInformation.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociationInformation.java new file mode 100644 index 0000000..ee74265 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AssociationInformation.java @@ -0,0 +1,153 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class AssociationInformation implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public AssociationInformation() { + seqOf = new ArrayList(); + } + + public AssociationInformation(byte[] code) { + this.code = code; + } + + public List getMyexternal() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(Myexternal.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + Myexternal element = new Myexternal(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/AuthenticationValue.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/AuthenticationValue.java new file mode 100644 index 0000000..f2173a2 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/AuthenticationValue.java @@ -0,0 +1,165 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.asn1bean.ber.types.BerType; +import com.beanit.asn1bean.ber.types.string.BerGraphicString; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class AuthenticationValue implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerGraphicString charstring = null; + private BerBitString bitstring = null; + private Myexternal2 external = null; + + public AuthenticationValue() {} + + public AuthenticationValue(byte[] code) { + this.code = code; + } + + public BerGraphicString getCharstring() { + return charstring; + } + + public void setCharstring(BerGraphicString charstring) { + this.charstring = charstring; + } + + public BerBitString getBitstring() { + return bitstring; + } + + public void setBitstring(BerBitString bitstring) { + this.bitstring = bitstring; + } + + public Myexternal2 getExternal() { + return external; + } + + public void setExternal(Myexternal2 external) { + this.external = external; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (external != null) { + codeLength += external.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + return codeLength; + } + + if (bitstring != null) { + codeLength += bitstring.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (charstring != null) { + codeLength += charstring.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + charstring = new BerGraphicString(); + tlvByteCount += charstring.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + bitstring = new BerBitString(); + tlvByteCount += bitstring.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + external = new Myexternal2(); + tlvByteCount += external.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (charstring != null) { + sb.append("charstring: ").append(charstring); + return; + } + + if (bitstring != null) { + sb.append("bitstring: ").append(bitstring); + return; + } + + if (external != null) { + sb.append("external: "); + external.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/ImplementationData.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/ImplementationData.java new file mode 100644 index 0000000..b0621f4 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/ImplementationData.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.string.BerGraphicString; + +public class ImplementationData extends BerGraphicString { + + private static final long serialVersionUID = 1L; + + public ImplementationData() {} + + public ImplementationData(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/MechanismName.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/MechanismName.java new file mode 100644 index 0000000..ed70f7a --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/MechanismName.java @@ -0,0 +1,22 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; + +public class MechanismName extends BerObjectIdentifier { + + private static final long serialVersionUID = 1L; + + public MechanismName() {} + + public MechanismName(byte[] code) { + super(code); + } + + public MechanismName(int[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/Myexternal.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/Myexternal.java new file mode 100644 index 0000000..d1b269a --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/Myexternal.java @@ -0,0 +1,362 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerAny; +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; +import com.beanit.asn1bean.ber.types.BerOctetString; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class Myexternal implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 8); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerObjectIdentifier directReference = null; + private BerInteger indirectReference = null; + private Encoding encoding = null; + + public Myexternal() {} + + public Myexternal(byte[] code) { + this.code = code; + } + + public BerObjectIdentifier getDirectReference() { + return directReference; + } + + public void setDirectReference(BerObjectIdentifier directReference) { + this.directReference = directReference; + } + + public BerInteger getIndirectReference() { + return indirectReference; + } + + public void setIndirectReference(BerInteger indirectReference) { + this.indirectReference = indirectReference; + } + + public Encoding getEncoding() { + return encoding; + } + + public void setEncoding(Encoding encoding) { + this.encoding = encoding; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += encoding.encode(reverseOS); + + if (indirectReference != null) { + codeLength += indirectReference.encode(reverseOS, true); + } + + if (directReference != null) { + codeLength += directReference.encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerObjectIdentifier.tag)) { + directReference = new BerObjectIdentifier(); + vByteCount += directReference.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerInteger.tag)) { + indirectReference = new BerInteger(); + vByteCount += indirectReference.decode(is, false); + vByteCount += berTag.decode(is); + } + + encoding = new Encoding(); + numDecodedBytes = encoding.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (directReference != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("directReference: ").append(directReference); + firstSelectedElement = false; + } + + if (indirectReference != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("indirectReference: ").append(indirectReference); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (encoding != null) { + sb.append("encoding: "); + encoding.appendAsString(sb, indentLevel + 1); + } else { + sb.append("encoding: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class Encoding implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerAny singleASN1Type = null; + private BerOctetString octetAligned = null; + private BerBitString arbitrary = null; + + public Encoding() {} + + public Encoding(byte[] code) { + this.code = code; + } + + public BerAny getSingleASN1Type() { + return singleASN1Type; + } + + public void setSingleASN1Type(BerAny singleASN1Type) { + this.singleASN1Type = singleASN1Type; + } + + public BerOctetString getOctetAligned() { + return octetAligned; + } + + public void setOctetAligned(BerOctetString octetAligned) { + this.octetAligned = octetAligned; + } + + public BerBitString getArbitrary() { + return arbitrary; + } + + public void setArbitrary(BerBitString arbitrary) { + this.arbitrary = arbitrary; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (arbitrary != null) { + codeLength += arbitrary.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (octetAligned != null) { + codeLength += octetAligned.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (singleASN1Type != null) { + sublength = singleASN1Type.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + singleASN1Type = new BerAny(); + tlvByteCount += singleASN1Type.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + octetAligned = new BerOctetString(); + tlvByteCount += octetAligned.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + arbitrary = new BerBitString(); + tlvByteCount += arbitrary.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (singleASN1Type != null) { + sb.append("singleASN1Type: ").append(singleASN1Type); + return; + } + + if (octetAligned != null) { + sb.append("octetAligned: ").append(octetAligned); + return; + } + + if (arbitrary != null) { + sb.append("arbitrary: ").append(arbitrary); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/Myexternal2.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/Myexternal2.java new file mode 100644 index 0000000..7335085 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/Myexternal2.java @@ -0,0 +1,362 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerAny; +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; +import com.beanit.asn1bean.ber.types.BerOctetString; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class Myexternal2 implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 8); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerObjectIdentifier directReference = null; + private BerInteger indirectReference = null; + private Encoding encoding = null; + + public Myexternal2() {} + + public Myexternal2(byte[] code) { + this.code = code; + } + + public BerObjectIdentifier getDirectReference() { + return directReference; + } + + public void setDirectReference(BerObjectIdentifier directReference) { + this.directReference = directReference; + } + + public BerInteger getIndirectReference() { + return indirectReference; + } + + public void setIndirectReference(BerInteger indirectReference) { + this.indirectReference = indirectReference; + } + + public Encoding getEncoding() { + return encoding; + } + + public void setEncoding(Encoding encoding) { + this.encoding = encoding; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += encoding.encode(reverseOS); + + if (indirectReference != null) { + codeLength += indirectReference.encode(reverseOS, true); + } + + if (directReference != null) { + codeLength += directReference.encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerObjectIdentifier.tag)) { + directReference = new BerObjectIdentifier(); + vByteCount += directReference.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerInteger.tag)) { + indirectReference = new BerInteger(); + vByteCount += indirectReference.decode(is, false); + vByteCount += berTag.decode(is); + } + + encoding = new Encoding(); + numDecodedBytes = encoding.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (directReference != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("directReference: ").append(directReference); + firstSelectedElement = false; + } + + if (indirectReference != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("indirectReference: ").append(indirectReference); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (encoding != null) { + sb.append("encoding: "); + encoding.appendAsString(sb, indentLevel + 1); + } else { + sb.append("encoding: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class Encoding implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerAny singleASN1Type = null; + private BerOctetString octetAligned = null; + private BerBitString arbitrary = null; + + public Encoding() {} + + public Encoding(byte[] code) { + this.code = code; + } + + public BerAny getSingleASN1Type() { + return singleASN1Type; + } + + public void setSingleASN1Type(BerAny singleASN1Type) { + this.singleASN1Type = singleASN1Type; + } + + public BerOctetString getOctetAligned() { + return octetAligned; + } + + public void setOctetAligned(BerOctetString octetAligned) { + this.octetAligned = octetAligned; + } + + public BerBitString getArbitrary() { + return arbitrary; + } + + public void setArbitrary(BerBitString arbitrary) { + this.arbitrary = arbitrary; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (arbitrary != null) { + codeLength += arbitrary.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (octetAligned != null) { + codeLength += octetAligned.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (singleASN1Type != null) { + sublength = singleASN1Type.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + singleASN1Type = new BerAny(); + tlvByteCount += singleASN1Type.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + octetAligned = new BerOctetString(); + tlvByteCount += octetAligned.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + arbitrary = new BerBitString(); + tlvByteCount += arbitrary.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (singleASN1Type != null) { + sb.append("singleASN1Type: ").append(singleASN1Type); + return; + } + + if (octetAligned != null) { + sb.append("octetAligned: ").append(octetAligned); + return; + } + + if (arbitrary != null) { + sb.append("arbitrary: ").append(arbitrary); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/OidValues.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/OidValues.java new file mode 100644 index 0000000..e11127d --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/OidValues.java @@ -0,0 +1,14 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; + +public final class OidValues { + public static final BerObjectIdentifier aCSEId = + new BerObjectIdentifier(new int[] {2, 2, 3, 1, 1}); + public static final BerObjectIdentifier acseAsId = + new BerObjectIdentifier(new int[] {2, 2, 1, 0, 1}); +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/RLREApdu.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/RLREApdu.java new file mode 100644 index 0000000..b6501e7 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/RLREApdu.java @@ -0,0 +1,181 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class RLREApdu implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.APPLICATION_CLASS, BerTag.CONSTRUCTED, 3); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ReleaseResponseReason reason = null; + private AssociationInformation userInformation = null; + + public RLREApdu() {} + + public RLREApdu(byte[] code) { + this.code = code; + } + + public ReleaseResponseReason getReason() { + return reason; + } + + public void setReason(ReleaseResponseReason reason) { + this.reason = reason; + } + + public AssociationInformation getUserInformation() { + return userInformation; + } + + public void setUserInformation(AssociationInformation userInformation) { + this.userInformation = userInformation; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (userInformation != null) { + codeLength += userInformation.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 30 + reverseOS.write(0xBE); + codeLength += 1; + } + + if (reason != null) { + codeLength += reason.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + if (lengthVal == 0) { + return tlByteCount; + } + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + reason = new ReleaseResponseReason(); + vByteCount += reason.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 30)) { + userInformation = new AssociationInformation(); + vByteCount += userInformation.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (reason != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("reason: ").append(reason); + firstSelectedElement = false; + } + + if (userInformation != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userInformation: "); + userInformation.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/RLRQApdu.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/RLRQApdu.java new file mode 100644 index 0000000..7ed3068 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/RLRQApdu.java @@ -0,0 +1,181 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class RLRQApdu implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.APPLICATION_CLASS, BerTag.CONSTRUCTED, 2); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ReleaseRequestReason reason = null; + private AssociationInformation userInformation = null; + + public RLRQApdu() {} + + public RLRQApdu(byte[] code) { + this.code = code; + } + + public ReleaseRequestReason getReason() { + return reason; + } + + public void setReason(ReleaseRequestReason reason) { + this.reason = reason; + } + + public AssociationInformation getUserInformation() { + return userInformation; + } + + public void setUserInformation(AssociationInformation userInformation) { + this.userInformation = userInformation; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (userInformation != null) { + codeLength += userInformation.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 30 + reverseOS.write(0xBE); + codeLength += 1; + } + + if (reason != null) { + codeLength += reason.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + if (lengthVal == 0) { + return tlByteCount; + } + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + reason = new ReleaseRequestReason(); + vByteCount += reason.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 30)) { + userInformation = new AssociationInformation(); + vByteCount += userInformation.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (reason != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("reason: ").append(reason); + firstSelectedElement = false; + } + + if (userInformation != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userInformation: "); + userInformation.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/ReleaseRequestReason.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/ReleaseRequestReason.java new file mode 100644 index 0000000..35748fd --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/ReleaseRequestReason.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class ReleaseRequestReason extends BerInteger { + + private static final long serialVersionUID = 1L; + + public ReleaseRequestReason() {} + + public ReleaseRequestReason(byte[] code) { + super(code); + } + + public ReleaseRequestReason(BigInteger value) { + super(value); + } + + public ReleaseRequestReason(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/acse/asn1/ReleaseResponseReason.java b/src/main/java/com/beanit/josistack/internal/acse/asn1/ReleaseResponseReason.java new file mode 100644 index 0000000..0c6aa2a --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/acse/asn1/ReleaseResponseReason.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.acse.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class ReleaseResponseReason extends BerInteger { + + private static final long serialVersionUID = 1L; + + public ReleaseResponseReason() {} + + public ReleaseResponseReason(byte[] code) { + super(code); + } + + public ReleaseResponseReason(BigInteger value) { + super(value); + } + + public ReleaseResponseReason(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/AbstractSyntaxName.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/AbstractSyntaxName.java new file mode 100644 index 0000000..46728e0 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/AbstractSyntaxName.java @@ -0,0 +1,22 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; + +public class AbstractSyntaxName extends BerObjectIdentifier { + + private static final long serialVersionUID = 1L; + + public AbstractSyntaxName() {} + + public AbstractSyntaxName(byte[] code) { + super(code); + } + + public AbstractSyntaxName(int[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/CPAPPDU.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CPAPPDU.java new file mode 100644 index 0000000..8b5994c --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CPAPPDU.java @@ -0,0 +1,485 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class CPAPPDU implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 17); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ModeSelector modeSelector = null; + private NormalModeParameters normalModeParameters = null; + + public CPAPPDU() {} + + public CPAPPDU(byte[] code) { + this.code = code; + } + + public ModeSelector getModeSelector() { + return modeSelector; + } + + public void setModeSelector(ModeSelector modeSelector) { + this.modeSelector = modeSelector; + } + + public NormalModeParameters getNormalModeParameters() { + return normalModeParameters; + } + + public void setNormalModeParameters(NormalModeParameters normalModeParameters) { + this.normalModeParameters = normalModeParameters; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (normalModeParameters != null) { + codeLength += normalModeParameters.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + } + + codeLength += modeSelector.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + modeSelector = new ModeSelector(); + vByteCount += modeSelector.decode(is, false); + } else if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + normalModeParameters = new NormalModeParameters(); + vByteCount += normalModeParameters.decode(is, false); + } else if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } else { + throw new IOException("Tag does not match any set component: " + berTag); + } + } + if (vByteCount != lengthVal) { + throw new IOException( + "Length of set does not match length tag, length tag: " + + lengthVal + + ", actual set length: " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (modeSelector != null) { + sb.append("modeSelector: "); + modeSelector.appendAsString(sb, indentLevel + 1); + } else { + sb.append("modeSelector: "); + } + + if (normalModeParameters != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("normalModeParameters: "); + normalModeParameters.appendAsString(sb, indentLevel + 1); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class NormalModeParameters implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ProtocolVersion protocolVersion = null; + private RespondingPresentationSelector respondingPresentationSelector = null; + private PresentationContextDefinitionResultList presentationContextDefinitionResultList = null; + private PresentationRequirements presentationRequirements = null; + private UserSessionRequirements userSessionRequirements = null; + private UserData userData = null; + + public NormalModeParameters() {} + + public NormalModeParameters(byte[] code) { + this.code = code; + } + + public ProtocolVersion getProtocolVersion() { + return protocolVersion; + } + + public void setProtocolVersion(ProtocolVersion protocolVersion) { + this.protocolVersion = protocolVersion; + } + + public RespondingPresentationSelector getRespondingPresentationSelector() { + return respondingPresentationSelector; + } + + public void setRespondingPresentationSelector( + RespondingPresentationSelector respondingPresentationSelector) { + this.respondingPresentationSelector = respondingPresentationSelector; + } + + public PresentationContextDefinitionResultList getPresentationContextDefinitionResultList() { + return presentationContextDefinitionResultList; + } + + public void setPresentationContextDefinitionResultList( + PresentationContextDefinitionResultList presentationContextDefinitionResultList) { + this.presentationContextDefinitionResultList = presentationContextDefinitionResultList; + } + + public PresentationRequirements getPresentationRequirements() { + return presentationRequirements; + } + + public void setPresentationRequirements(PresentationRequirements presentationRequirements) { + this.presentationRequirements = presentationRequirements; + } + + public UserSessionRequirements getUserSessionRequirements() { + return userSessionRequirements; + } + + public void setUserSessionRequirements(UserSessionRequirements userSessionRequirements) { + this.userSessionRequirements = userSessionRequirements; + } + + public UserData getUserData() { + return userData; + } + + public void setUserData(UserData userData) { + this.userData = userData; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (userData != null) { + codeLength += userData.encode(reverseOS); + } + + if (userSessionRequirements != null) { + codeLength += userSessionRequirements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 9 + reverseOS.write(0x89); + codeLength += 1; + } + + if (presentationRequirements != null) { + codeLength += presentationRequirements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 8 + reverseOS.write(0x88); + codeLength += 1; + } + + if (presentationContextDefinitionResultList != null) { + codeLength += presentationContextDefinitionResultList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 5 + reverseOS.write(0xA5); + codeLength += 1; + } + + if (respondingPresentationSelector != null) { + codeLength += respondingPresentationSelector.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 3 + reverseOS.write(0x83); + codeLength += 1; + } + + if (protocolVersion != null) { + codeLength += protocolVersion.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + if (lengthVal == 0) { + return tlByteCount; + } + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + protocolVersion = new ProtocolVersion(); + vByteCount += protocolVersion.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 3)) { + respondingPresentationSelector = new RespondingPresentationSelector(); + vByteCount += respondingPresentationSelector.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 5)) { + presentationContextDefinitionResultList = new PresentationContextDefinitionResultList(); + vByteCount += presentationContextDefinitionResultList.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 8)) { + presentationRequirements = new PresentationRequirements(); + vByteCount += presentationRequirements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 9)) { + userSessionRequirements = new UserSessionRequirements(); + vByteCount += userSessionRequirements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + userData = new UserData(); + numDecodedBytes = userData.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + userData = null; + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (protocolVersion != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("protocolVersion: ").append(protocolVersion); + firstSelectedElement = false; + } + + if (respondingPresentationSelector != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("respondingPresentationSelector: ").append(respondingPresentationSelector); + firstSelectedElement = false; + } + + if (presentationContextDefinitionResultList != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("presentationContextDefinitionResultList: "); + presentationContextDefinitionResultList.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + if (presentationRequirements != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("presentationRequirements: ").append(presentationRequirements); + firstSelectedElement = false; + } + + if (userSessionRequirements != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userSessionRequirements: ").append(userSessionRequirements); + firstSelectedElement = false; + } + + if (userData != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userData: "); + userData.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/CPType.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CPType.java new file mode 100644 index 0000000..a6c0bba --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CPType.java @@ -0,0 +1,559 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class CPType implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 17); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ModeSelector modeSelector = null; + private NormalModeParameters normalModeParameters = null; + + public CPType() {} + + public CPType(byte[] code) { + this.code = code; + } + + public ModeSelector getModeSelector() { + return modeSelector; + } + + public void setModeSelector(ModeSelector modeSelector) { + this.modeSelector = modeSelector; + } + + public NormalModeParameters getNormalModeParameters() { + return normalModeParameters; + } + + public void setNormalModeParameters(NormalModeParameters normalModeParameters) { + this.normalModeParameters = normalModeParameters; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (normalModeParameters != null) { + codeLength += normalModeParameters.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 2 + reverseOS.write(0xA2); + codeLength += 1; + } + + codeLength += modeSelector.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + modeSelector = new ModeSelector(); + vByteCount += modeSelector.decode(is, false); + } else if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 2)) { + normalModeParameters = new NormalModeParameters(); + vByteCount += normalModeParameters.decode(is, false); + } else if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } else { + throw new IOException("Tag does not match any set component: " + berTag); + } + } + if (vByteCount != lengthVal) { + throw new IOException( + "Length of set does not match length tag, length tag: " + + lengthVal + + ", actual set length: " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (modeSelector != null) { + sb.append("modeSelector: "); + modeSelector.appendAsString(sb, indentLevel + 1); + } else { + sb.append("modeSelector: "); + } + + if (normalModeParameters != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("normalModeParameters: "); + normalModeParameters.appendAsString(sb, indentLevel + 1); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class NormalModeParameters implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private ProtocolVersion protocolVersion = null; + private CallingPresentationSelector callingPresentationSelector = null; + private CalledPresentationSelector calledPresentationSelector = null; + private PresentationContextDefinitionList presentationContextDefinitionList = null; + private DefaultContextName defaultContextName = null; + private PresentationRequirements presentationRequirements = null; + private UserSessionRequirements userSessionRequirements = null; + private UserData userData = null; + + public NormalModeParameters() {} + + public NormalModeParameters(byte[] code) { + this.code = code; + } + + public ProtocolVersion getProtocolVersion() { + return protocolVersion; + } + + public void setProtocolVersion(ProtocolVersion protocolVersion) { + this.protocolVersion = protocolVersion; + } + + public CallingPresentationSelector getCallingPresentationSelector() { + return callingPresentationSelector; + } + + public void setCallingPresentationSelector( + CallingPresentationSelector callingPresentationSelector) { + this.callingPresentationSelector = callingPresentationSelector; + } + + public CalledPresentationSelector getCalledPresentationSelector() { + return calledPresentationSelector; + } + + public void setCalledPresentationSelector( + CalledPresentationSelector calledPresentationSelector) { + this.calledPresentationSelector = calledPresentationSelector; + } + + public PresentationContextDefinitionList getPresentationContextDefinitionList() { + return presentationContextDefinitionList; + } + + public void setPresentationContextDefinitionList( + PresentationContextDefinitionList presentationContextDefinitionList) { + this.presentationContextDefinitionList = presentationContextDefinitionList; + } + + public DefaultContextName getDefaultContextName() { + return defaultContextName; + } + + public void setDefaultContextName(DefaultContextName defaultContextName) { + this.defaultContextName = defaultContextName; + } + + public PresentationRequirements getPresentationRequirements() { + return presentationRequirements; + } + + public void setPresentationRequirements(PresentationRequirements presentationRequirements) { + this.presentationRequirements = presentationRequirements; + } + + public UserSessionRequirements getUserSessionRequirements() { + return userSessionRequirements; + } + + public void setUserSessionRequirements(UserSessionRequirements userSessionRequirements) { + this.userSessionRequirements = userSessionRequirements; + } + + public UserData getUserData() { + return userData; + } + + public void setUserData(UserData userData) { + this.userData = userData; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (userData != null) { + codeLength += userData.encode(reverseOS); + } + + if (userSessionRequirements != null) { + codeLength += userSessionRequirements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 9 + reverseOS.write(0x89); + codeLength += 1; + } + + if (presentationRequirements != null) { + codeLength += presentationRequirements.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 8 + reverseOS.write(0x88); + codeLength += 1; + } + + if (defaultContextName != null) { + codeLength += defaultContextName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 6 + reverseOS.write(0xA6); + codeLength += 1; + } + + if (presentationContextDefinitionList != null) { + codeLength += presentationContextDefinitionList.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 4 + reverseOS.write(0xA4); + codeLength += 1; + } + + if (calledPresentationSelector != null) { + codeLength += calledPresentationSelector.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + } + + if (callingPresentationSelector != null) { + codeLength += callingPresentationSelector.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + if (protocolVersion != null) { + codeLength += protocolVersion.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + if (lengthVal == 0) { + return tlByteCount; + } + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + protocolVersion = new ProtocolVersion(); + vByteCount += protocolVersion.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + callingPresentationSelector = new CallingPresentationSelector(); + vByteCount += callingPresentationSelector.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + calledPresentationSelector = new CalledPresentationSelector(); + vByteCount += calledPresentationSelector.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 4)) { + presentationContextDefinitionList = new PresentationContextDefinitionList(); + vByteCount += presentationContextDefinitionList.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 6)) { + defaultContextName = new DefaultContextName(); + vByteCount += defaultContextName.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 8)) { + presentationRequirements = new PresentationRequirements(); + vByteCount += presentationRequirements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 9)) { + userSessionRequirements = new UserSessionRequirements(); + vByteCount += userSessionRequirements.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + userData = new UserData(); + numDecodedBytes = userData.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + userData = null; + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (protocolVersion != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("protocolVersion: ").append(protocolVersion); + firstSelectedElement = false; + } + + if (callingPresentationSelector != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("callingPresentationSelector: ").append(callingPresentationSelector); + firstSelectedElement = false; + } + + if (calledPresentationSelector != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("calledPresentationSelector: ").append(calledPresentationSelector); + firstSelectedElement = false; + } + + if (presentationContextDefinitionList != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("presentationContextDefinitionList: "); + presentationContextDefinitionList.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + if (defaultContextName != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("defaultContextName: "); + defaultContextName.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + if (presentationRequirements != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("presentationRequirements: ").append(presentationRequirements); + firstSelectedElement = false; + } + + if (userSessionRequirements != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userSessionRequirements: ").append(userSessionRequirements); + firstSelectedElement = false; + } + + if (userData != null) { + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("userData: "); + userData.appendAsString(sb, indentLevel + 1); + firstSelectedElement = false; + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/CalledPresentationSelector.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CalledPresentationSelector.java new file mode 100644 index 0000000..212d3c9 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CalledPresentationSelector.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +public class CalledPresentationSelector extends PresentationSelector { + + private static final long serialVersionUID = 1L; + + public CalledPresentationSelector() {} + + public CalledPresentationSelector(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/CallingPresentationSelector.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CallingPresentationSelector.java new file mode 100644 index 0000000..e4b134d --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/CallingPresentationSelector.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +public class CallingPresentationSelector extends PresentationSelector { + + private static final long serialVersionUID = 1L; + + public CallingPresentationSelector() {} + + public CallingPresentationSelector(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/ContextList.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ContextList.java new file mode 100644 index 0000000..8f732c1 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ContextList.java @@ -0,0 +1,477 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ContextList implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ContextList() { + seqOf = new ArrayList(); + } + + public ContextList(byte[] code) { + this.code = code; + } + + public List getSEQUENCE() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(SEQUENCE.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + SEQUENCE element = new SEQUENCE(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class SEQUENCE implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private PresentationContextIdentifier presentationContextIdentifier = null; + private AbstractSyntaxName abstractSyntaxName = null; + private TransferSyntaxNameList transferSyntaxNameList = null; + + public SEQUENCE() {} + + public SEQUENCE(byte[] code) { + this.code = code; + } + + public PresentationContextIdentifier getPresentationContextIdentifier() { + return presentationContextIdentifier; + } + + public void setPresentationContextIdentifier( + PresentationContextIdentifier presentationContextIdentifier) { + this.presentationContextIdentifier = presentationContextIdentifier; + } + + public AbstractSyntaxName getAbstractSyntaxName() { + return abstractSyntaxName; + } + + public void setAbstractSyntaxName(AbstractSyntaxName abstractSyntaxName) { + this.abstractSyntaxName = abstractSyntaxName; + } + + public TransferSyntaxNameList getTransferSyntaxNameList() { + return transferSyntaxNameList; + } + + public void setTransferSyntaxNameList(TransferSyntaxNameList transferSyntaxNameList) { + this.transferSyntaxNameList = transferSyntaxNameList; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += transferSyntaxNameList.encode(reverseOS, true); + + codeLength += abstractSyntaxName.encode(reverseOS, true); + + codeLength += presentationContextIdentifier.encode(reverseOS, true); + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(PresentationContextIdentifier.tag)) { + presentationContextIdentifier = new PresentationContextIdentifier(); + vByteCount += presentationContextIdentifier.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(AbstractSyntaxName.tag)) { + abstractSyntaxName = new AbstractSyntaxName(); + vByteCount += abstractSyntaxName.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(TransferSyntaxNameList.tag)) { + transferSyntaxNameList = new TransferSyntaxNameList(); + vByteCount += transferSyntaxNameList.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (presentationContextIdentifier != null) { + sb.append("presentationContextIdentifier: ").append(presentationContextIdentifier); + } else { + sb.append("presentationContextIdentifier: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (abstractSyntaxName != null) { + sb.append("abstractSyntaxName: ").append(abstractSyntaxName); + } else { + sb.append("abstractSyntaxName: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (transferSyntaxNameList != null) { + sb.append("transferSyntaxNameList: "); + transferSyntaxNameList.appendAsString(sb, indentLevel + 1); + } else { + sb.append("transferSyntaxNameList: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class TransferSyntaxNameList implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public TransferSyntaxNameList() { + seqOf = new ArrayList(); + } + + public TransferSyntaxNameList(byte[] code) { + this.code = code; + } + + public List getTransferSyntaxName() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(TransferSyntaxName.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + TransferSyntaxName element = new TransferSyntaxName(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = + new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + sb.append(it.next()); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append(it.next()); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/DefaultContextName.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/DefaultContextName.java new file mode 100644 index 0000000..470e5af --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/DefaultContextName.java @@ -0,0 +1,173 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class DefaultContextName implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private AbstractSyntaxName abstractSyntaxName = null; + private TransferSyntaxName transferSyntaxName = null; + + public DefaultContextName() {} + + public DefaultContextName(byte[] code) { + this.code = code; + } + + public AbstractSyntaxName getAbstractSyntaxName() { + return abstractSyntaxName; + } + + public void setAbstractSyntaxName(AbstractSyntaxName abstractSyntaxName) { + this.abstractSyntaxName = abstractSyntaxName; + } + + public TransferSyntaxName getTransferSyntaxName() { + return transferSyntaxName; + } + + public void setTransferSyntaxName(TransferSyntaxName transferSyntaxName) { + this.transferSyntaxName = transferSyntaxName; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += transferSyntaxName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + + codeLength += abstractSyntaxName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + abstractSyntaxName = new AbstractSyntaxName(); + vByteCount += abstractSyntaxName.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + transferSyntaxName = new TransferSyntaxName(); + vByteCount += transferSyntaxName.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (abstractSyntaxName != null) { + sb.append("abstractSyntaxName: ").append(abstractSyntaxName); + } else { + sb.append("abstractSyntaxName: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (transferSyntaxName != null) { + sb.append("transferSyntaxName: ").append(transferSyntaxName); + } else { + sb.append("transferSyntaxName: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/FullyEncodedData.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/FullyEncodedData.java new file mode 100644 index 0000000..667cbfc --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/FullyEncodedData.java @@ -0,0 +1,153 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class FullyEncodedData implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public FullyEncodedData() { + seqOf = new ArrayList(); + } + + public FullyEncodedData(byte[] code) { + this.code = code; + } + + public List getPDVList() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(PDVList.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + PDVList element = new PDVList(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/ModeSelector.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ModeSelector.java new file mode 100644 index 0000000..a22748d --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ModeSelector.java @@ -0,0 +1,140 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class ModeSelector implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 17); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private BerInteger modeValue = null; + + public ModeSelector() {} + + public ModeSelector(byte[] code) { + this.code = code; + } + + public BerInteger getModeValue() { + return modeValue; + } + + public void setModeValue(BerInteger modeValue) { + this.modeValue = modeValue; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += modeValue.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + modeValue = new BerInteger(); + vByteCount += modeValue.decode(is, false); + } else if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } else { + throw new IOException("Tag does not match any set component: " + berTag); + } + } + if (vByteCount != lengthVal) { + throw new IOException( + "Length of set does not match length tag, length tag: " + + lengthVal + + ", actual set length: " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (modeValue != null) { + sb.append("modeValue: ").append(modeValue); + } else { + sb.append("modeValue: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/PDVList.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PDVList.java new file mode 100644 index 0000000..e150238 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PDVList.java @@ -0,0 +1,360 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerAny; +import com.beanit.asn1bean.ber.types.BerBitString; +import com.beanit.asn1bean.ber.types.BerOctetString; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class PDVList implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private TransferSyntaxName transferSyntaxName = null; + private PresentationContextIdentifier presentationContextIdentifier = null; + private PresentationDataValues presentationDataValues = null; + + public PDVList() {} + + public PDVList(byte[] code) { + this.code = code; + } + + public TransferSyntaxName getTransferSyntaxName() { + return transferSyntaxName; + } + + public void setTransferSyntaxName(TransferSyntaxName transferSyntaxName) { + this.transferSyntaxName = transferSyntaxName; + } + + public PresentationContextIdentifier getPresentationContextIdentifier() { + return presentationContextIdentifier; + } + + public void setPresentationContextIdentifier( + PresentationContextIdentifier presentationContextIdentifier) { + this.presentationContextIdentifier = presentationContextIdentifier; + } + + public PresentationDataValues getPresentationDataValues() { + return presentationDataValues; + } + + public void setPresentationDataValues(PresentationDataValues presentationDataValues) { + this.presentationDataValues = presentationDataValues; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += presentationDataValues.encode(reverseOS); + + codeLength += presentationContextIdentifier.encode(reverseOS, true); + + if (transferSyntaxName != null) { + codeLength += transferSyntaxName.encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + int numDecodedBytes; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(TransferSyntaxName.tag)) { + transferSyntaxName = new TransferSyntaxName(); + vByteCount += transferSyntaxName.decode(is, false); + vByteCount += berTag.decode(is); + } + + if (berTag.equals(PresentationContextIdentifier.tag)) { + presentationContextIdentifier = new PresentationContextIdentifier(); + vByteCount += presentationContextIdentifier.decode(is, false); + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + presentationDataValues = new PresentationDataValues(); + numDecodedBytes = presentationDataValues.decode(is, berTag); + if (numDecodedBytes != 0) { + vByteCount += numDecodedBytes; + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + lengthVal + ", bytes decoded: " + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + boolean firstSelectedElement = true; + if (transferSyntaxName != null) { + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("transferSyntaxName: ").append(transferSyntaxName); + firstSelectedElement = false; + } + + if (!firstSelectedElement) { + sb.append(",\n"); + } + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (presentationContextIdentifier != null) { + sb.append("presentationContextIdentifier: ").append(presentationContextIdentifier); + } else { + sb.append("presentationContextIdentifier: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (presentationDataValues != null) { + sb.append("presentationDataValues: "); + presentationDataValues.appendAsString(sb, indentLevel + 1); + } else { + sb.append("presentationDataValues: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class PresentationDataValues implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private BerAny singleASN1Type = null; + private BerOctetString octetAligned = null; + private BerBitString arbitrary = null; + + public PresentationDataValues() {} + + public PresentationDataValues(byte[] code) { + this.code = code; + } + + public BerAny getSingleASN1Type() { + return singleASN1Type; + } + + public void setSingleASN1Type(BerAny singleASN1Type) { + this.singleASN1Type = singleASN1Type; + } + + public BerOctetString getOctetAligned() { + return octetAligned; + } + + public void setOctetAligned(BerOctetString octetAligned) { + this.octetAligned = octetAligned; + } + + public BerBitString getArbitrary() { + return arbitrary; + } + + public void setArbitrary(BerBitString arbitrary) { + this.arbitrary = arbitrary; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + int sublength; + + if (arbitrary != null) { + codeLength += arbitrary.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + return codeLength; + } + + if (octetAligned != null) { + codeLength += octetAligned.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + return codeLength; + } + + if (singleASN1Type != null) { + sublength = singleASN1Type.encode(reverseOS); + codeLength += sublength; + codeLength += BerLength.encodeLength(reverseOS, sublength); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + reverseOS.write(0xA0); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + BerLength length = new BerLength(); + tlvByteCount += length.decode(is); + singleASN1Type = new BerAny(); + tlvByteCount += singleASN1Type.decode(is, null); + tlvByteCount += length.readEocIfIndefinite(is); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + octetAligned = new BerOctetString(); + tlvByteCount += octetAligned.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + arbitrary = new BerBitString(); + tlvByteCount += arbitrary.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (singleASN1Type != null) { + sb.append("singleASN1Type: ").append(singleASN1Type); + return; + } + + if (octetAligned != null) { + sb.append("octetAligned: ").append(octetAligned); + return; + } + + if (arbitrary != null) { + sb.append("arbitrary: ").append(arbitrary); + return; + } + + sb.append(""); + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextDefinitionList.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextDefinitionList.java new file mode 100644 index 0000000..70ae9f7 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextDefinitionList.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +public class PresentationContextDefinitionList extends ContextList { + + private static final long serialVersionUID = 1L; + + public PresentationContextDefinitionList() {} + + public PresentationContextDefinitionList(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextDefinitionResultList.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextDefinitionResultList.java new file mode 100644 index 0000000..900210a --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextDefinitionResultList.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +public class PresentationContextDefinitionResultList extends ResultList { + + private static final long serialVersionUID = 1L; + + public PresentationContextDefinitionResultList() {} + + public PresentationContextDefinitionResultList(byte[] code) { + super(code); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextIdentifier.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextIdentifier.java new file mode 100644 index 0000000..1dae88c --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationContextIdentifier.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class PresentationContextIdentifier extends BerInteger { + + private static final long serialVersionUID = 1L; + + public PresentationContextIdentifier() {} + + public PresentationContextIdentifier(byte[] code) { + super(code); + } + + public PresentationContextIdentifier(BigInteger value) { + super(value); + } + + public PresentationContextIdentifier(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationRequirements.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationRequirements.java new file mode 100644 index 0000000..d00aa87 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationRequirements.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerBitString; + +public class PresentationRequirements extends BerBitString { + + private static final long serialVersionUID = 1L; + + public PresentationRequirements() {} + + public PresentationRequirements(byte[] code) { + super(code); + } + + public PresentationRequirements(byte[] value, int numBits) { + super(value, numBits); + } + + public PresentationRequirements(boolean[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationSelector.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationSelector.java new file mode 100644 index 0000000..ced60e0 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/PresentationSelector.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerOctetString; + +public class PresentationSelector extends BerOctetString { + + private static final long serialVersionUID = 1L; + + public PresentationSelector() {} + + public PresentationSelector(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/ProtocolVersion.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ProtocolVersion.java new file mode 100644 index 0000000..10bb4f5 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ProtocolVersion.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerBitString; + +public class ProtocolVersion extends BerBitString { + + private static final long serialVersionUID = 1L; + + public ProtocolVersion() {} + + public ProtocolVersion(byte[] code) { + super(code); + } + + public ProtocolVersion(byte[] value, int numBits) { + super(value, numBits); + } + + public ProtocolVersion(boolean[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/RespondingPresentationSelector.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/RespondingPresentationSelector.java new file mode 100644 index 0000000..3b1911d --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/RespondingPresentationSelector.java @@ -0,0 +1,16 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +public class RespondingPresentationSelector extends PresentationSelector { + + private static final long serialVersionUID = 1L; + + public RespondingPresentationSelector() {} + + public RespondingPresentationSelector(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/Result.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/Result.java new file mode 100644 index 0000000..573c517 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/Result.java @@ -0,0 +1,27 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerInteger; +import java.math.BigInteger; + +public class Result extends BerInteger { + + private static final long serialVersionUID = 1L; + + public Result() {} + + public Result(byte[] code) { + super(code); + } + + public Result(BigInteger value) { + super(value); + } + + public Result(long value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/ResultList.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ResultList.java new file mode 100644 index 0000000..cbfe954 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/ResultList.java @@ -0,0 +1,350 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerLength; +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerInteger; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ResultList implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private List seqOf = null; + + public ResultList() { + seqOf = new ArrayList(); + } + + public ResultList(byte[] code) { + this.code = code; + } + + public List getSEQUENCE() { + if (seqOf == null) { + seqOf = new ArrayList(); + } + return seqOf; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + for (int i = (seqOf.size() - 1); i >= 0; i--) { + codeLength += seqOf.get(i).encode(reverseOS, true); + } + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + + while (vByteCount < lengthVal || lengthVal < 0) { + vByteCount += berTag.decode(is); + + if (lengthVal < 0 && berTag.equals(0, 0, 0)) { + vByteCount += BerLength.readEocByte(is); + break; + } + + if (!berTag.equals(SEQUENCE.tag)) { + throw new IOException("Tag does not match mandatory sequence of/set of component."); + } + SEQUENCE element = new SEQUENCE(); + vByteCount += element.decode(is, false); + seqOf.add(element); + } + if (lengthVal >= 0 && vByteCount != lengthVal) { + throw new IOException( + "Decoded SequenceOf or SetOf has wrong length. Expected " + + lengthVal + + " but has " + + vByteCount); + } + return tlByteCount + vByteCount; + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (seqOf == null) { + sb.append("null"); + } else { + Iterator it = seqOf.iterator(); + if (it.hasNext()) { + it.next().appendAsString(sb, indentLevel + 1); + while (it.hasNext()) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + it.next().appendAsString(sb, indentLevel + 1); + } + } + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + + public static class SEQUENCE implements BerType, Serializable { + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + private static final long serialVersionUID = 1L; + private byte[] code = null; + private Result result = null; + private TransferSyntaxName transferSyntaxName = null; + private BerInteger providerReason = null; + + public SEQUENCE() {} + + public SEQUENCE(byte[] code) { + this.code = code; + } + + public Result getResult() { + return result; + } + + public void setResult(Result result) { + this.result = result; + } + + public TransferSyntaxName getTransferSyntaxName() { + return transferSyntaxName; + } + + public void setTransferSyntaxName(TransferSyntaxName transferSyntaxName) { + this.transferSyntaxName = transferSyntaxName; + } + + public BerInteger getProviderReason() { + return providerReason; + } + + public void setProviderReason(BerInteger providerReason) { + this.providerReason = providerReason; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + return encode(reverseOS, true); + } + + public int encode(OutputStream reverseOS, boolean withTag) throws IOException { + + if (code != null) { + reverseOS.write(code); + if (withTag) { + return tag.encode(reverseOS) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (providerReason != null) { + codeLength += providerReason.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 2 + reverseOS.write(0x82); + codeLength += 1; + } + + if (transferSyntaxName != null) { + codeLength += transferSyntaxName.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + reverseOS.write(0x81); + codeLength += 1; + } + + codeLength += result.encode(reverseOS, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + reverseOS.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(reverseOS, codeLength); + + if (withTag) { + codeLength += tag.encode(reverseOS); + } + + return codeLength; + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int tlByteCount = 0; + int vByteCount = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + tlByteCount += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + tlByteCount += length.decode(is); + int lengthVal = length.val; + vByteCount += berTag.decode(is); + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + result = new Result(); + vByteCount += result.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } else { + throw new IOException("Tag does not match mandatory sequence component."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + transferSyntaxName = new TransferSyntaxName(); + vByteCount += transferSyntaxName.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 2)) { + providerReason = new BerInteger(); + vByteCount += providerReason.decode(is, false); + if (lengthVal >= 0 && vByteCount == lengthVal) { + return tlByteCount + vByteCount; + } + vByteCount += berTag.decode(is); + } + + if (lengthVal < 0) { + if (!berTag.equals(0, 0, 0)) { + throw new IOException("Decoded sequence has wrong end of contents octets"); + } + vByteCount += BerLength.readEocByte(is); + return tlByteCount + vByteCount; + } + + throw new IOException( + "Unexpected end of sequence, length tag: " + + lengthVal + + ", bytes decoded: " + + vByteCount); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS, false); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (result != null) { + sb.append("result: ").append(result); + } else { + sb.append("result: "); + } + + if (transferSyntaxName != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("transferSyntaxName: ").append(transferSyntaxName); + } + + if (providerReason != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("providerReason: ").append(providerReason); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/SimplyEncodedData.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/SimplyEncodedData.java new file mode 100644 index 0000000..40b311c --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/SimplyEncodedData.java @@ -0,0 +1,18 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerOctetString; + +public class SimplyEncodedData extends BerOctetString { + + private static final long serialVersionUID = 1L; + + public SimplyEncodedData() {} + + public SimplyEncodedData(byte[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/TransferSyntaxName.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/TransferSyntaxName.java new file mode 100644 index 0000000..596a843 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/TransferSyntaxName.java @@ -0,0 +1,22 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; + +public class TransferSyntaxName extends BerObjectIdentifier { + + private static final long serialVersionUID = 1L; + + public TransferSyntaxName() {} + + public TransferSyntaxName(byte[] code) { + super(code); + } + + public TransferSyntaxName(int[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/UserData.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/UserData.java new file mode 100644 index 0000000..1855c3f --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/UserData.java @@ -0,0 +1,135 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.BerTag; +import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream; +import com.beanit.asn1bean.ber.types.BerType; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +public class UserData implements BerType, Serializable { + + private static final long serialVersionUID = 1L; + + private byte[] code = null; + private SimplyEncodedData simplyEncodedData = null; + private FullyEncodedData fullyEncodedData = null; + + public UserData() {} + + public UserData(byte[] code) { + this.code = code; + } + + public SimplyEncodedData getSimplyEncodedData() { + return simplyEncodedData; + } + + public void setSimplyEncodedData(SimplyEncodedData simplyEncodedData) { + this.simplyEncodedData = simplyEncodedData; + } + + public FullyEncodedData getFullyEncodedData() { + return fullyEncodedData; + } + + public void setFullyEncodedData(FullyEncodedData fullyEncodedData) { + this.fullyEncodedData = fullyEncodedData; + } + + @Override + public int encode(OutputStream reverseOS) throws IOException { + + if (code != null) { + reverseOS.write(code); + return code.length; + } + + int codeLength = 0; + if (fullyEncodedData != null) { + codeLength += fullyEncodedData.encode(reverseOS, false); + // write tag: APPLICATION_CLASS, CONSTRUCTED, 1 + reverseOS.write(0x61); + codeLength += 1; + return codeLength; + } + + if (simplyEncodedData != null) { + codeLength += simplyEncodedData.encode(reverseOS, false); + // write tag: APPLICATION_CLASS, PRIMITIVE, 0 + reverseOS.write(0x40); + codeLength += 1; + return codeLength; + } + + throw new IOException("Error encoding CHOICE: No element of CHOICE was selected."); + } + + @Override + public int decode(InputStream is) throws IOException { + return decode(is, null); + } + + public int decode(InputStream is, BerTag berTag) throws IOException { + + int tlvByteCount = 0; + boolean tagWasPassed = (berTag != null); + + if (berTag == null) { + berTag = new BerTag(); + tlvByteCount += berTag.decode(is); + } + + if (berTag.equals(BerTag.APPLICATION_CLASS, BerTag.PRIMITIVE, 0)) { + simplyEncodedData = new SimplyEncodedData(); + tlvByteCount += simplyEncodedData.decode(is, false); + return tlvByteCount; + } + + if (berTag.equals(BerTag.APPLICATION_CLASS, BerTag.CONSTRUCTED, 1)) { + fullyEncodedData = new FullyEncodedData(); + tlvByteCount += fullyEncodedData.decode(is, false); + return tlvByteCount; + } + + if (tagWasPassed) { + return 0; + } + + throw new IOException("Error decoding CHOICE: Tag " + berTag + " matched to no item."); + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream reverseOS = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(reverseOS); + code = reverseOS.getArray(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + if (simplyEncodedData != null) { + sb.append("simplyEncodedData: ").append(simplyEncodedData); + return; + } + + if (fullyEncodedData != null) { + sb.append("fullyEncodedData: "); + fullyEncodedData.appendAsString(sb, indentLevel + 1); + return; + } + + sb.append(""); + } +} diff --git a/src/main/java/com/beanit/josistack/internal/presentation/asn1/UserSessionRequirements.java b/src/main/java/com/beanit/josistack/internal/presentation/asn1/UserSessionRequirements.java new file mode 100644 index 0000000..b238f54 --- /dev/null +++ b/src/main/java/com/beanit/josistack/internal/presentation/asn1/UserSessionRequirements.java @@ -0,0 +1,26 @@ +/* + * This class file was automatically generated by ASN1bean (http://www.beanit.com) + */ + +package com.beanit.josistack.internal.presentation.asn1; + +import com.beanit.asn1bean.ber.types.BerBitString; + +public class UserSessionRequirements extends BerBitString { + + private static final long serialVersionUID = 1L; + + public UserSessionRequirements() {} + + public UserSessionRequirements(byte[] code) { + super(code); + } + + public UserSessionRequirements(byte[] value, int numBits) { + super(value, numBits); + } + + public UserSessionRequirements(boolean[] value) { + super(value); + } +} diff --git a/src/main/java/com/beanit/jositransport/ClientTSap.java b/src/main/java/com/beanit/jositransport/ClientTSap.java new file mode 100644 index 0000000..a318541 --- /dev/null +++ b/src/main/java/com/beanit/jositransport/ClientTSap.java @@ -0,0 +1,157 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.jositransport; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import javax.net.SocketFactory; + +/** + * This class implements a client Transport Service Access Point (TSAP) over TCP/IP as defined in + * RFC 1006, ISO 8072, and ISO 8073. It can be used to create TConnections that connect to remote + * ServerTSAPs. + */ +public final class ClientTSap { + + public byte[] tSelRemote = null; + public byte[] tSelLocal = null; + private int maxTPDUSizeParam = 16; + private SocketFactory socketFactory = null; + private int messageTimeout = 0; + private int messageFragmentTimeout = 60000; + + /** Use this constructor to create a client TSAP that will start connections to remote TSAPs. */ + public ClientTSap() { + socketFactory = SocketFactory.getDefault(); + } + + /** + * Use this constructor to create a client TSAP that will start connections to remote TSAPs. You + * could pass an SSLSocketFactory to enable SSL. + * + * @param socketFactory the socket factory to create the underlying socket + */ + public ClientTSap(SocketFactory socketFactory) { + this.socketFactory = socketFactory; + } + + /** + * Calculates and returns the maximum TPDUSize. This is equal to 2^(maxTPDUSizeParam) + * + * @param maxTPDUSizeParam the size parameter + * @return the maximum TPDU size + */ + public static int getMaxTPDUSize(int maxTPDUSizeParam) { + if (maxTPDUSizeParam < 7 || maxTPDUSizeParam > 16) { + throw new IllegalArgumentException("maxTPDUSizeParam is out of bound"); + } + if (maxTPDUSizeParam == 16) { + return 65531; + } else { + return (int) Math.pow(2, maxTPDUSizeParam); + } + } + + /** + * Set the TConnection timeout for waiting for the first byte of a new message. Default is 0 + * (unlimited) + * + * @param messageTimeout in milliseconds + */ + public void setMessageTimeout(int messageTimeout) { + this.messageTimeout = messageTimeout; + } + + /** + * Set the TConnection timeout for receiving data once the beginning of a message has been + * received. Default is 60000 (60seconds) + * + * @param messageFragmentTimeout in milliseconds + */ + public void setMessageFragmentTimeout(int messageFragmentTimeout) { + this.messageFragmentTimeout = messageFragmentTimeout; + } + + /** + * Get the maximum TPDU size parameter to be used by this TSAP + * + * @return the maximum TPDU size parameter + */ + public int getMaxTPDUSizeParam() { + return maxTPDUSizeParam; + } + + /** + * Set the maxTPDUSize. The default maxTPduSize is 65531 (see RFC 1006). + * + * @param maxTPDUSizeParam The maximum length is equal to 2^(maxTPDUSizeParam) octets. Note that + * the actual TSDU size that can be transfered is equal to TPduSize-3. Default is 65531 octets + * (see RFC 1006), 7 <= maxTPDUSizeParam <= 16, needs to be set before listening or + * connecting + */ + public void setMaxTPDUSizeParam(int maxTPDUSizeParam) { + if (maxTPDUSizeParam < 7 || maxTPDUSizeParam > 16) { + throw new IllegalArgumentException("maxTPDUSizeParam is out of bound"); + } + this.maxTPDUSizeParam = maxTPDUSizeParam; + } + + /** + * Connect to a remote TSAP that is listening at the destination address. + * + * @param address remote IP + * @param port remote port + * @return the Connection Object + * @throws IOException is thrown if connection was unsuccessful. + */ + public TConnection connectTo(InetAddress address, int port) throws IOException { + return connectTo(address, port, null, -1); + } + + /** + * Connect to a remote TSAP that is listening at the destination address. + * + * @param address remote IP + * @param port remote port + * @param localAddr local IP + * @param localPort local port + * @return the Connection Object + * @throws IOException is thrown if connection was unsuccessful. + */ + public TConnection connectTo(InetAddress address, int port, InetAddress localAddr, int localPort) + throws IOException { + Socket socket; + + if (localAddr == null) { + socket = socketFactory.createSocket(); + + socket.connect(new InetSocketAddress(address, port), messageTimeout); + } else { + socket = socketFactory.createSocket(address, port, localAddr, localPort); + } + TConnection tConnection = + new TConnection(socket, maxTPDUSizeParam, messageTimeout, messageFragmentTimeout, null); + tConnection.tSelRemote = tSelRemote; + tConnection.tSelLocal = tSelLocal; + tConnection.startConnection(); + + return tConnection; + } + + public void setSocketFactory(SocketFactory socketFactory) { + this.socketFactory = socketFactory; + } +} diff --git a/src/main/java/com/beanit/jositransport/ServerTSap.java b/src/main/java/com/beanit/jositransport/ServerTSap.java new file mode 100644 index 0000000..50859ea --- /dev/null +++ b/src/main/java/com/beanit/jositransport/ServerTSap.java @@ -0,0 +1,207 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.jositransport; + +import java.io.IOException; +import java.net.InetAddress; +import javax.net.ServerSocketFactory; + +/** + * This class implements the server Transport Service Access Point (TSAP) over TCP/IP as defined in + * RFC 1006, ISO 8072, and ISO 8073. It can be used to listen for incoming TConnections. + */ +public class ServerTSap { + + private final int port; + private final InetAddress bindAddr; + private final int backlog; + private final TConnectionListener connectionListener; + private final ServerSocketFactory serverSocketFactory; + private ServerThread serverThread; + private boolean started = false; + private int maxTPDUSizeParam = 16; + private int maxConnections = 100; + private int messageTimeout = 0; + private int messageFragmentTimeout = 60000; + + /** + * Use this constructor to create a server TSAP that can listen on a port. + * + * @param port the TCP port that the ServerSocket will connect to. Should be between 1 and 65535. + * @param conListener the ConnectionListener that will be notified when remote TSAPs are + * connecting or the server stopped listening. + */ + public ServerTSap(int port, TConnectionListener conListener) { + this(port, 0, null, conListener, ServerSocketFactory.getDefault()); + } + + /** + * Use this constructor to create a server TSAP that can listen on a port. + * + * @param port the TCP port that the ServerSocket will connect to. Should be between 1 and 65535. + * @param conListener the ConnectionListener that will be notified when remote TSAPs are + * connecting or the server stopped listening. + * @param backlog is passed to the java.net.ServerSocket + * @param bindAddr the IP address to bind to. It is passed to java.net.ServerSocket + */ + public ServerTSap(int port, int backlog, InetAddress bindAddr, TConnectionListener conListener) { + this(port, backlog, bindAddr, conListener, ServerSocketFactory.getDefault()); + } + + /** + * Use this constructor to create a server TSAP that can listen on a port, with a specified + * ServerSocketFactory. + * + * @param port the TCP port that the ServerSocket will connect to. Should be between 1 and 65535. + * @param connectionListener the ConnectionListener that will be notified when remote TSAPs are + * connecting or the server stopped listening. + * @param backlog is passed to the java.net.ServerSocket + * @param bindAddr the IP address to bind to. It is passed to java.net.ServerSocket + * @param serverSocketFactory The ServerSocketFactory to be used to create the ServerSocket + */ + public ServerTSap( + int port, + int backlog, + InetAddress bindAddr, + TConnectionListener connectionListener, + ServerSocketFactory serverSocketFactory) { + if (port < 1 || port > 65535) { + throw new IllegalArgumentException("port number is out of bound"); + } + + this.port = port; + this.backlog = backlog; + this.bindAddr = bindAddr; + this.connectionListener = connectionListener; + this.serverSocketFactory = serverSocketFactory; + } + + /** + * Calculates and returns the maximum TPDUSize. This is equal to 2^(maxTPDUSizeParam) + * + * @param maxTPDUSizeParam the size parameter + * @return the maximum TPDU size + */ + public static int getMaxTPDUSize(int maxTPDUSizeParam) { + if (maxTPDUSizeParam < 7 || maxTPDUSizeParam > 16) { + throw new IllegalArgumentException("maxTPDUSizeParam is out of bound"); + } + if (maxTPDUSizeParam == 16) { + return 65531; + } else { + return (int) Math.pow(2, maxTPDUSizeParam); + } + } + + /** + * Starts a new thread that listens on the configured port. This method is non-blocking. + * + * @throws IOException if a starting to listen fails + */ + public void startListening() throws IOException { + started = true; + serverThread = + new ServerThread( + serverSocketFactory.createServerSocket(port, backlog, bindAddr), + maxTPDUSizeParam, + maxConnections, + messageTimeout, + messageFragmentTimeout, + connectionListener); + serverThread.start(); + } + + /** Stop listing on the port. Stops the server thread. */ + public void stopListening() { + if (serverThread != null) { + serverThread.stopServer(); + } + serverThread = null; + started = false; + } + + /** + * Set the maximum number of connections that are allowed in parallel by the Server SAP. + * + * @param maxConnections the number of connections allowed (default is 100) + */ + public void setMaxConnections(int maxConnections) { + if (started == true) { + throw new RuntimeException("Trying to set parameter although server has started."); + } + if (maxConnections < 0) { + throw new IllegalArgumentException("maxConnections is out of bound"); + } + this.maxConnections = maxConnections; + } + + /** + * Set the TConnection timeout for waiting for the first byte of a new message. Default is 0 + * (unlimited) + * + * @param messageTimeout in milliseconds + */ + public void setMessageTimeout(int messageTimeout) { + if (started == true) { + throw new RuntimeException( + "Message timeout may not be set while the server SAP ist listening."); + } + this.messageTimeout = messageTimeout; + } + + /** + * Set the TConnection timeout for receiving data once the beginning of a message has been + * received. Default is 60000 (60 seconds) + * + * @param messageFragmentTimeout in milliseconds + */ + public void setMessageFragmentTimeout(int messageFragmentTimeout) { + if (started == true) { + throw new RuntimeException( + "Message fragment timeout may not be set while the server SAP ist listening."); + } + this.messageFragmentTimeout = messageFragmentTimeout; + } + + /** + * Get the maximum TPDU size parameter to be used by this TSAP + * + * @return the maximum TPDU size parameter + */ + public int getMaxTPDUSizeParam() { + return maxTPDUSizeParam; + } + + /** + * Set the maxTPDUSize. The default maxTPduSize is 65531 (see RFC 1006). + * + * @param maxTPDUSizeParam The maximum length is equal to 2^(maxTPDUSizeParam) octets. Note that + * the actual TSDU size that can be transfered is equal to TPduSize-3. Default is 65531 octets + * (see RFC 1006), 7 <= maxTPDUSizeParam <= 16, needs to be set before listening or + * connecting + */ + public void setMaxTPDUSizeParam(int maxTPDUSizeParam) { + if (started == true) { + throw new RuntimeException("Trying to set parameter although server has started."); + } + if (maxTPDUSizeParam < 7 || maxTPDUSizeParam > 16) { + throw new IllegalArgumentException("maxTPDUSizeParam is out of bound"); + } + this.maxTPDUSizeParam = maxTPDUSizeParam; + } + + TConnectionListener getConnectionListener() { + return connectionListener; + } +} diff --git a/src/main/java/com/beanit/jositransport/ServerThread.java b/src/main/java/com/beanit/jositransport/ServerThread.java new file mode 100644 index 0000000..02567e6 --- /dev/null +++ b/src/main/java/com/beanit/jositransport/ServerThread.java @@ -0,0 +1,147 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.jositransport; + +import com.beanit.iec61850bean.internal.NamedThreadFactory; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * This class extends Thread. It is started by ServerTSAP and listens on a socket for connections + * and hands them to the ConnectionHandler class. It notifies ConnectionListener if the socket is + * closed. + * + * @author Stefan Feuerhahn + */ +final class ServerThread extends Thread { + + private final ServerSocket serverSocket; + private final int maxTPduSizeParam; + private final int messageTimeout; + private final int messageFragmentTimeout; + private final int maxConnections; + private final TConnectionListener connectionListener; + + private boolean stopServer = false; + private int numConnections = 0; + + ServerThread( + ServerSocket socket, + int maxTPduSizeParam, + int maxConnections, + int messageTimeout, + int messageFragmentTimeout, + TConnectionListener connectionListener) { + serverSocket = socket; + this.maxTPduSizeParam = maxTPduSizeParam; + this.maxConnections = maxConnections; + this.messageTimeout = messageTimeout; + this.messageFragmentTimeout = messageFragmentTimeout; + this.connectionListener = connectionListener; + } + + @Override + public void run() { + + ExecutorService executor = + Executors.newCachedThreadPool(new NamedThreadFactory("iec61850bean-server")); + try { + + Socket clientSocket = null; + + while (true) { + try { + clientSocket = serverSocket.accept(); + } catch (IOException e) { + if (stopServer == false) { + connectionListener.serverStoppedListeningIndication(e); + } + return; + } + + boolean startConnection = false; + + synchronized (this) { + if (numConnections < maxConnections) { + numConnections++; + startConnection = true; + } + } + + if (startConnection) { + executor.execute(new ConnectionHandler(clientSocket, this)); + } else { + // Maximum number of connections reached. Ignoring connection request. + } + } + } finally { + executor.shutdown(); + } + } + + void connectionClosedSignal() { + synchronized (this) { + numConnections--; + } + } + + /** Stops listening for new connections. Existing connections are not touched. */ + void stopServer() { + stopServer = true; + if (serverSocket.isBound()) { + try { + serverSocket.close(); + } catch (IOException e) { + // there is nothing meaningful to be done when closing fails + } + } + } + + public final class ConnectionHandler extends Thread { + + private final Socket socket; + private final ServerThread serverThread; + + ConnectionHandler(Socket socket, ServerThread serverThread) { + this.socket = socket; + this.serverThread = serverThread; + } + + @Override + public void run() { + + TConnection tConnection; + try { + tConnection = + new TConnection( + socket, maxTPduSizeParam, messageTimeout, messageFragmentTimeout, serverThread); + } catch (IOException e) { + synchronized (ServerThread.this) { + numConnections--; + } + return; + } + try { + tConnection.listenForCR(); + } catch (IOException e) { + tConnection.close(); + return; + } + connectionListener.connectionIndication(tConnection); + } + } +} diff --git a/src/main/java/com/beanit/jositransport/TConnection.java b/src/main/java/com/beanit/jositransport/TConnection.java new file mode 100644 index 0000000..8cd6e71 --- /dev/null +++ b/src/main/java/com/beanit/jositransport/TConnection.java @@ -0,0 +1,657 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.jositransport; + +import com.beanit.iec61850bean.internal.util.SequenceNumber; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeoutException; + +public final class TConnection { + + // some servers do not like srcRef 0 + private static final SequenceNumber connectionCounter = new SequenceNumber(1, 1, 65519); + private final Socket socket; + private final DataOutputStream os; + private final DataInputStream is; + private final ServerThread serverThread; + public byte[] tSelRemote = null; + public byte[] tSelLocal = null; + private int srcRef; + private int dstRef; + private int maxTPduSizeParam; + private int maxTPduSize; + private int messageTimeout; + private int messageFragmentTimeout; + private boolean closed = false; + + TConnection( + Socket socket, + int maxTPduSizeParam, + int messageTimeout, + int messageFragmentTimeout, + ServerThread serverThread) + throws IOException { + if (maxTPduSizeParam < 7 || maxTPduSizeParam > 16) { + throw new RuntimeException("maxTPduSizeParam is incorrect"); + } + this.socket = socket; + os = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); + is = new DataInputStream(new BufferedInputStream(socket.getInputStream())); + + synchronized (connectionCounter) { + srcRef = connectionCounter.getAndIncrement(); + } + + this.messageTimeout = messageTimeout; + this.messageFragmentTimeout = messageFragmentTimeout; + this.maxTPduSizeParam = maxTPduSizeParam; + maxTPduSize = ClientTSap.getMaxTPDUSize(maxTPduSizeParam); + + this.serverThread = serverThread; + } + + /** + * This function is called once a client has connected to the server. It listens for a Connection + * Request (CR). If this is successful it replies afterwards with a Connection Confirm (CC). + * According to the norm a syntax error in the CR should be followed by an ER. This implementation + * does not send an ER because it seems unnecessary. + * + * @throws IOException if an error occurs + */ + void listenForCR() throws IOException { + + socket.setSoTimeout(messageFragmentTimeout); + + byte myByte; + int lengthIndicator; + int parameterLength; + + // start reading rfc 1006 header + if (is.read() != 0x03) { + throw new IOException(); + } + if (is.read() != 0) { + throw new IOException(); + } + // read Packet length, but is not needed + is.readShort(); + // reading rfc 1006 header finished + + lengthIndicator = is.read() & 0xff; + // 0xe0 is the CR-Code + if ((is.read() & 0xff) != 0xe0) { + throw new IOException(); + } + // DST-REF needs to be 0 in a CR packet + if (is.readShort() != 0) { + throw new IOException(); + } + // read the srcRef which is the dstRef for this end-point + dstRef = is.readShort() & 0xffff; + // read class + if ((is.read() & 0xff) != 0) { + throw new IOException(); + } + int variableBytesRead = 0; + while (lengthIndicator > (6 + variableBytesRead)) { + // read parameter code + myByte = is.readByte(); + switch (myByte & 0xff) { + case 0xc2: + parameterLength = is.readByte() & 0xff; + + if (tSelLocal == null) { + tSelLocal = new byte[parameterLength]; + is.readFully(tSelLocal); + } else { + if (parameterLength != tSelLocal.length) { + throw new IOException("local T-SElECTOR is wrong."); + } + for (int i = 0; i < parameterLength; i++) { + if ((tSelLocal[i] & 0xff) != is.read()) { + throw new IOException("local T-SElECTOR is wrong."); + } + } + } + variableBytesRead += 2 + parameterLength; + break; + case 0xc1: + parameterLength = is.readByte() & 0xff; + + if (tSelRemote == null) { + tSelRemote = new byte[parameterLength]; + is.readFully(tSelRemote); + } else { + if (parameterLength != tSelRemote.length) { + throw new IOException("remote T-SElECTOR is wrong."); + } + for (int i = 0; i < parameterLength; i++) { + if ((tSelRemote[i] & 0xff) != is.read()) { + throw new IOException("remote T-SElECTOR is wrong."); + } + } + } + variableBytesRead += 2 + parameterLength; + break; + + case 0xc0: + if ((is.readByte() & 0xff) != 1) { + throw new IOException(); + } + myByte = is.readByte(); + int newMaxTPDUSizeParam = (myByte & 0xff); + if (newMaxTPDUSizeParam < 7 || newMaxTPDUSizeParam > 16) { + throw new IOException("maxTPDUSizeParam is out of bound"); + } else { + if (newMaxTPDUSizeParam < maxTPduSizeParam) { + maxTPduSizeParam = newMaxTPDUSizeParam; + maxTPduSize = ClientTSap.getMaxTPDUSize(maxTPduSizeParam); + } + } + variableBytesRead += 3; + break; + default: + throw new IOException(); + } + } + + // write RFC 1006 Header + os.write(0x03); + os.write(0x00); + // write complete packet length + + int variableLength = 3; + + if (tSelLocal != null) { + variableLength += 2 + tSelLocal.length; + } + if (tSelRemote != null) { + variableLength += 2 + tSelRemote.length; + } + os.writeShort(4 + 7 + variableLength); + + // write connection request (CR) TPDU (§13.3) + + // write length indicator + os.write(6 + variableLength); + + // write fixed part + // write CC CDT + os.write(0xd0); + // write DST-REF + os.writeShort(dstRef); + // write SRC-REF + os.writeShort(srcRef); + // write class + os.write(0); + + // write variable part + if (tSelLocal != null) { + os.write(0xc2); + os.write(tSelLocal.length); + os.write(tSelLocal); + } + + if (tSelRemote != null) { + os.write(0xc1); + os.write(tSelRemote.length); + os.write(tSelRemote); + } + // write proposed maximum TPDU Size + os.write(0xc0); + os.write(1); + os.write(maxTPduSizeParam); + + os.flush(); + } + + /** + * Starts a connection, sends a CR, waits for a CC and throws an IOException if not successful + * + * @throws IOException if an error occurs + */ + void startConnection() throws IOException { + + // write RFC 1006 Header + os.write(0x03); + os.write(0x00); + + // write complete packet length + int variableLength = 3; + + if (tSelLocal != null) { + variableLength += 2 + tSelLocal.length; + } + if (tSelRemote != null) { + variableLength += 2 + tSelRemote.length; + } + os.writeShort(4 + 7 + variableLength); + // writing RFC 1006 Header finished + + // write connection request (CR) TPDU (§13.3) + + // write length indicator + os.write(6 + variableLength); + + // write fixed part + // write CR CDT + os.write(0xe0); + // write DST-REF + os.write(0); + os.write(0); + // write SRC-REF + os.writeShort(srcRef); + // write class + os.write(0); + + // write variable part + // write proposed maximum TPDU Size + os.write(0xc0); + os.write(1); + os.write(maxTPduSizeParam); + + if (tSelRemote != null) { + os.write(0xc2); + os.write(tSelRemote.length); + os.write(tSelRemote); + } + if (tSelLocal != null) { + os.write(0xc1); + os.write(tSelLocal.length); + os.write(tSelLocal); + } + + os.flush(); + + socket.setSoTimeout(messageTimeout); + + byte myByte; + int lengthIndicator; + int parameterLength; + if (is.readByte() != 0x03) { + throw new IOException(); + } + if (is.readByte() != 0) { + throw new IOException(); + } + // read packet length, but is not needed + is.readShort(); + lengthIndicator = is.readByte() & 0xff; + if ((is.readByte() & 0xff) != 0xd0) { + throw new IOException(); + } + // read the dstRef which is the srcRef for this end-point + is.readShort(); + // read the srcRef which is the dstRef for this end-point + dstRef = is.readShort() & 0xffff; + // read class + if (is.readByte() != 0) { + throw new IOException(); + } + + int variableBytesRead = 0; + while (lengthIndicator > (6 + variableBytesRead)) { + // read parameter code + myByte = is.readByte(); + switch (myByte & 0xff) { + case 0xc1: + parameterLength = is.readByte() & 0xff; + + if (tSelLocal == null) { + tSelLocal = new byte[parameterLength]; + is.readFully(tSelLocal); + } else { + for (int i = 0; i < parameterLength; i++) { + is.read(); + } + } + variableBytesRead += 2 + parameterLength; + break; + case 0xc2: + parameterLength = is.readByte() & 0xff; + + if (tSelRemote == null) { + tSelRemote = new byte[parameterLength]; + is.readFully(tSelRemote); + } else { + for (int i = 0; i < parameterLength; i++) { + is.read(); + } + } + variableBytesRead += 2 + parameterLength; + break; + + case 0xc0: + if (is.readByte() != 1) { + throw new IOException("maxTPduSizeParam size is not equal to 1"); + } + myByte = is.readByte(); + if ((myByte & 0xff) < 7 || (myByte & 0xff) > maxTPduSizeParam) { + throw new IOException("maxTPduSizeParam out of bound"); + } else { + if ((myByte & 0xff) < maxTPduSizeParam) { + maxTPduSizeParam = (myByte & 0xff); + } + } + variableBytesRead += 4; + break; + default: + throw new IOException(); + } + } + } + + public void send(List tsdus, List offsets, List lengths) + throws IOException { + + int bytesLeft = 0; + // for (byte[] tsdu : tsdus) { + // bytesLeft += tsdu.length; + // } + for (int length : lengths) { + bytesLeft += length; + } + int tsduOffset = 0; + int byteArrayListIndex = 0; + int numBytesToWrite; + boolean lastPacket = false; + int maxTSDUSize = maxTPduSize - 3; + while (bytesLeft > 0) { + + if (bytesLeft > maxTSDUSize) { + numBytesToWrite = maxTSDUSize; + } else { + numBytesToWrite = bytesLeft; + lastPacket = true; + } + + // --write RFC 1006 Header-- + // write Version + os.write(0x03); + // write reserved bits + os.write(0); + // write packet Length + os.writeShort(numBytesToWrite + 7); + + // --write 8073 Header-- + // write Length Indicator of header + os.write(0x02); + // write TPDU Code for DT Data + os.write(0xf0); + // write TPDU-NR and EOT, TPDU-NR is always 0 for class 0 + if (lastPacket) { + os.write(0x80); + } else { + os.write(0x00); + } + + bytesLeft -= numBytesToWrite; + while (numBytesToWrite > 0) { + byte[] tsdu = tsdus.get(byteArrayListIndex); + int length = lengths.get(byteArrayListIndex); + int offset = offsets.get(byteArrayListIndex); + + int tsduWriteLength = length - tsduOffset; + + if (numBytesToWrite > tsduWriteLength) { + os.write(tsdu, offset + tsduOffset, tsduWriteLength); + numBytesToWrite -= tsduWriteLength; + tsduOffset = 0; + byteArrayListIndex++; + } else { + os.write(tsdu, offset + tsduOffset, numBytesToWrite); + if (numBytesToWrite == tsduWriteLength) { + tsduOffset = 0; + byteArrayListIndex++; + } else { + tsduOffset += numBytesToWrite; + } + numBytesToWrite = 0; + } + } + + os.flush(); + } + } + + public void send(byte[] tsdu, int offset, int length) throws IOException { + List tsdus = new ArrayList<>(); + tsdus.add(tsdu); + List offsets = new ArrayList<>(); + offsets.add(offset); + List lengths = new ArrayList<>(); + lengths.add(length); + send(tsdus, offsets, lengths); + } + + public int getMessageTimeout() { + return messageTimeout; + } + + /** + * Set the TConnection timeout for waiting for the first byte of a new message. Default is 0 + * (unlimited) + * + * @param messageTimeout in milliseconds + */ + public void setMessageTimeout(int messageTimeout) { + this.messageTimeout = messageTimeout; + } + + public int getMessageFragmentTimeout() { + return messageFragmentTimeout; + } + + /** + * Set the TConnection timeout for receiving data once the beginning of a message has been + * received. Default is 60000 (60 seconds) + * + * @param messageFragmentTimeout in milliseconds + */ + public void setMessageFragmentTimeout(int messageFragmentTimeout) { + this.messageFragmentTimeout = messageFragmentTimeout; + } + + /** + * Listens for a new TPDU and writes the extracted TSDU into the passed buffer. + * + * @param tSduBuffer the buffer that is filled with the received TSDU data. + * @throws EOFException if a Disconnect Request (DR) was received or the socket was simply closed + * @throws SocketTimeoutException if a messageFragmentTimeout is thrown by the socket while + * receiving the remainder of a message + * @throws IOException if an ErrorPDU (ER) was received, any syntax error in the received message + * header was detected or the tSduBuffer is too small to hold the complete PDU. + * @throws TimeoutException this exception is thrown if the first byte of new message is not + * received within the message timeout. + */ + public void receive(ByteBuffer tSduBuffer) + throws EOFException, SocketTimeoutException, IOException, TimeoutException { + + tSduBuffer.mark(); + + int packetLength; + int eot = 0; + int li = 0; + int tPduCode; + + socket.setSoTimeout(messageTimeout); + byte version; + try { + version = is.readByte(); + } catch (SocketTimeoutException e) { + throw (new TimeoutException()); + } + socket.setSoTimeout(messageFragmentTimeout); + + do { + // read version + if (version != 3) { + throw new IOException( + "Syntax error at beginning of RFC1006 header: version not equal to 3"); + } + + // read reserved + if (is.readByte() != 0) { + throw new IOException( + "Syntax errorat beginning of RFC1006 header: reserved not equal to 0"); + } + + // read packet length + packetLength = is.readShort() & 0xffff; + if (packetLength <= 7) { + throw new IOException("Syntax error: packet length parameter < 7"); + } + + // read length indicator + li = is.readByte() & 0xff; + + // read TPDU code + tPduCode = is.readByte() & 0xff; + + if (tPduCode == 0xf0) { + // Data Transfer (DT) Code + + if (li != 2) { + throw new IOException("Syntax error: LI field does not equal 2"); + } + + // read EOT + eot = is.readByte() & 0xff; + if (eot != 0 && eot != 0x80) { + throw new IOException("Syntax error: eot wrong"); + } + + if (packetLength - 7 > tSduBuffer.limit() - tSduBuffer.position()) { + throw new IOException("tSduBuffer size is too small to hold the complete TSDU"); + } + is.readFully( + tSduBuffer.array(), tSduBuffer.arrayOffset() + tSduBuffer.position(), packetLength - 7); + tSduBuffer.position(tSduBuffer.position() + packetLength - 7); + } else if (tPduCode == 0x80) { + // Disconnect Request (DR) + + if (li != 6) { + throw new IOException("Syntax error: LI field does not equal 6"); + } + + // check if the DST-REF field is set to the reference of the + // receiving entity -> srcRef + if (is.readShort() != srcRef) { + throw new IOException("Syntax error: srcRef wrong"); + } + + // check if the SRC-REF field is that of the entity sending + // the DR + if (is.readShort() != dstRef) { + throw new IOException("Syntax error: dstRef wrong"); + } + + // check the reason field, for class 0 only between 1 and 4 + int reason = is.readByte() & 0xff; + if (reason > 4) { + throw new IOException("Syntax error: reason out of bound"); + } + + // Disconnect is valid, throw exception + throw new EOFException("Disconnect request. Reason:" + reason); + + } else if (tPduCode == 0x70) { + throw new IOException("Got TPDU error (ER) message"); + } else { + throw new IOException("Syntax error: unknown TPDU code"); + } + + if (eot != 0x80) { + version = is.readByte(); + } + + } while (eot != 0x80); + + tSduBuffer.limit(tSduBuffer.position()); + tSduBuffer.reset(); + } + + /** This function sends a Disconnect Request but does not wait for a Disconnect Confirm. */ + public void disconnect() { + + try { + // write header for rfc + // write version + os.write(0x03); + // write reserved + os.write(0x00); + + // write packet length + os.writeShort(4 + 7); // this does not include the variable part + // which + // contains additional user information for + // disconnect + + // beginning of ISO 8073 header + // write LI + os.write(0x06); + + // write DR + os.write(0x80); + + // write DST-REF + os.writeShort(dstRef); + + // write SRC-REF + os.writeShort(srcRef); + + // write reason - 0x00 corresponds to reason not specified. Can + // write + // the reasons as case structure, but need input from client + os.write(0x00); + + os.flush(); + } catch (IOException ignored) { + // io exceptions while disconnecting can be ignored + } finally { + close(); + } + } + + /** Will close the TCP connection if its still open and free any resources of this connection. */ + public void close() { + if (!closed) { + closed = true; + try { + // will also close socket + os.close(); + } catch (Exception e) { + // there is nothing meaningful to be done if closing fails + } + try { + is.close(); + } catch (Exception e) { + // there is nothing meaningful to be done if closing fails + } + if (serverThread != null) { + serverThread.connectionClosedSignal(); + } + } + } +} diff --git a/src/main/java/com/beanit/jositransport/TConnectionListener.java b/src/main/java/com/beanit/jositransport/TConnectionListener.java new file mode 100644 index 0000000..8c578f6 --- /dev/null +++ b/src/main/java/com/beanit/jositransport/TConnectionListener.java @@ -0,0 +1,29 @@ +/* + * Copyright 2011 The IEC61850bean Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.beanit.jositransport; + +import java.io.IOException; + +public interface TConnectionListener { + + void connectionIndication(TConnection tConnection); + + /** + * This function is only called when an IOException in ServerSocket.accept() occurred which was + * not forced using ServerTSAP.stopListening() + * + * @param e The IOException caught form ServerSocket.accept() + */ + void serverStoppedListeningIndication(IOException e); +}