All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gurux.dlms.objects.GXDLMSAssociationLogicalName Maven / Gradle / Ivy

There is a newer version: 4.0.72
Show newest version
//
// --------------------------------------------------------------------------
//  Gurux Ltd
// 
//
//
// Filename:        $HeadURL$
//
// Version:         $Revision$,
//                  $Date$
//                  $Author$
//
// Copyright (c) Gurux Ltd
//
//---------------------------------------------------------------------------
//
//  DESCRIPTION
//
// This file is a part of Gurux Device Framework.
//
// Gurux Device Framework is Open Source software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License 
// as published by the Free Software Foundation; version 2 of the License.
// Gurux Device Framework is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
// See the GNU General Public License for more details.
//
// More information of Gurux products: https://www.gurux.org
//
// This code is licensed under the GNU General Public License v2. 
// Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
//---------------------------------------------------------------------------

package gurux.dlms.objects;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.xml.stream.XMLStreamException;

import gurux.dlms.GXBitString;
import gurux.dlms.GXByteBuffer;
import gurux.dlms.GXCryptoKeyParameter;
import gurux.dlms.GXDLMSClient;
import gurux.dlms.GXDLMSServerBase;
import gurux.dlms.GXDLMSSettings;
import gurux.dlms.GXDLMSTranslator;
import gurux.dlms.GXSimpleEntry;
import gurux.dlms.IGXCryptoNotifier;
import gurux.dlms.ValueEventArgs;
import gurux.dlms.asn.GXAsn1Converter;
import gurux.dlms.asn.GXAsn1Integer;
import gurux.dlms.enums.AccessMode;
import gurux.dlms.enums.AccessMode3;
import gurux.dlms.enums.Authentication;
import gurux.dlms.enums.Conformance;
import gurux.dlms.enums.DataType;
import gurux.dlms.enums.ErrorCode;
import gurux.dlms.enums.MethodAccessMode;
import gurux.dlms.enums.MethodAccessMode3;
import gurux.dlms.enums.ObjectType;
import gurux.dlms.internal.GXCommon;
import gurux.dlms.manufacturersettings.GXDLMSAttributeSettings;
import gurux.dlms.objects.enums.ApplicationContextName;
import gurux.dlms.objects.enums.AssociationStatus;
import gurux.dlms.objects.enums.CertificateType;
import gurux.dlms.objects.enums.SecuritySuite;
import gurux.dlms.secure.GXSecure;

/**
 * Online help: 
* https://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAssociationLogicalName */ public class GXDLMSAssociationLogicalName extends GXDLMSObject implements IGXDLMSBase { /** * Is this association including other association views. */ private boolean multipleAssociationViews; private HashMap accessRights = new HashMap(); private HashMap methodAccessRights = new HashMap(); private static final Logger LOGGER = Logger.getLogger(GXDLMSAssociationLogicalName.class.getName()); private GXDLMSObjectCollection objectList; private int clientSAP; private short serverSAP = 1; private GXApplicationContextName applicationContextName; private GXxDLMSContextType xDLMSContextInfo; private GXAuthenticationMechanismName authenticationMechanismName; /** * Secret used in Low Level Authentication. */ private byte[] secret; private AssociationStatus associationStatus = AssociationStatus.NON_ASSOCIATED; private String securitySetupReference; /** * User list. */ private List> userList; /** * Current user. */ private Entry currentUser; /** * Constructor. */ public GXDLMSAssociationLogicalName() { this("0.0.40.0.0.255"); } /** * Constructor. * * @param ln * Logical Name of the object. */ public GXDLMSAssociationLogicalName(final String ln) { super(ObjectType.ASSOCIATION_LOGICAL_NAME, ln, 0); setLogicalName(ln); objectList = new GXDLMSObjectCollection(this); applicationContextName = new GXApplicationContextName(); xDLMSContextInfo = new GXxDLMSContextType(); authenticationMechanismName = new GXAuthenticationMechanismName(); setUserList(new ArrayList>()); setVersion(2); } /** * @return Object list. */ public final GXDLMSObjectCollection getObjectList() { return objectList; } /** * @param value * Object list. */ public final void setObjectList(final GXDLMSObjectCollection value) { objectList = value; } /** * @return Contains the identifiers of the COSEM client APs within the * physical devices hosting these APs, which belong to the AA * modeled by the Association LN object. */ public final int getClientSAP() { return clientSAP; } /** * @param value * Client address. */ public final void setClientSAP(final int value) { clientSAP = value; } /** * @return Contains the identifiers of the COSEM server (logical device) APs * within the physical devices hosting these APs, which belong to * the AA modeled by the Association LN object. */ public final short getServerSAP() { return serverSAP; } /** * @param value * Server address. */ public final void setServerSAP(final short value) { serverSAP = value; } /** * @return Application context name. */ public final GXApplicationContextName getApplicationContextName() { return applicationContextName; } public final GXxDLMSContextType getXDLMSContextInfo() { return xDLMSContextInfo; } /** * @return Authentication mechanism name. */ public final GXAuthenticationMechanismName getAuthenticationMechanismName() { return authenticationMechanismName; } /** * @return Secret used in Low Level Authentication. */ public final byte[] getSecret() { return secret; } /** * @param value * Secret used in Low Level Authentication. */ public final void setSecret(final byte[] value) { secret = value; } /** * @return Association status. */ public final AssociationStatus getAssociationStatus() { return associationStatus; } /** * @param value * Association status. */ public final void setAssociationStatus(final AssociationStatus value) { associationStatus = value; } public final String getSecuritySetupReference() { return securitySetupReference; } public final void setSecuritySetupReference(final String value) { securitySetupReference = value; } /** * Updates secret. * * @param client * DLMS client. * @return Action bytes. * @throws NoSuchPaddingException * No such padding exception. * @throws NoSuchAlgorithmException * No such algorithm exception. * @throws InvalidAlgorithmParameterException * Invalid algorithm parameter exception. * @throws InvalidKeyException * Invalid key exception. * @throws BadPaddingException * Bad padding exception. * @throws IllegalBlockSizeException * Illegal block size exception. * @throws SignatureException * Signature exception. */ public byte[][] updateSecret(final GXDLMSClient client) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, SignatureException { if (getAuthenticationMechanismName().getMechanismId() == Authentication.NONE) { throw new IllegalArgumentException("Invalid authentication level in MechanismId."); } if (getAuthenticationMechanismName().getMechanismId() == Authentication.HIGH_GMAC) { throw new IllegalArgumentException("HighGMAC secret is updated using Security setup."); } if (getAuthenticationMechanismName().getMechanismId() == Authentication.LOW) { return client.write(this, 7); } // Action is used to update High authentication password. return client.method(this, 2, secret, DataType.OCTET_STRING); } /** * Add user to user list. * * @param client * DLMS client. * @param id * User ID. * @param name * User name. * @return Action bytes. * @throws NoSuchPaddingException * No such padding exception. * @throws NoSuchAlgorithmException * No such algorithm exception. * @throws InvalidAlgorithmParameterException * Invalid algorithm parameter exception. * @throws InvalidKeyException * Invalid key exception. * @throws BadPaddingException * Bad padding exception. * @throws IllegalBlockSizeException * Illegal block size exception. * @throws SignatureException * Signature exception. */ public final byte[][] addUser(final GXDLMSClient client, final byte id, final String name) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, SignatureException { GXByteBuffer data = new GXByteBuffer(); data.setUInt8(DataType.STRUCTURE.getValue()); // Add structure size. data.setUInt8(2); GXCommon.setData(null, data, DataType.UINT8, id); GXCommon.setData(null, data, DataType.STRING, name); return client.method(this, 5, data.array(), DataType.STRUCTURE); } /** * Remove user from user list. * * @param client * DLMS client. * @param id * User ID. * @param name * User name. * @return Action bytes. * @throws NoSuchPaddingException * No such padding exception. * @throws NoSuchAlgorithmException * No such algorithm exception. * @throws InvalidAlgorithmParameterException * Invalid algorithm parameter exception. * @throws InvalidKeyException * Invalid key exception. * @throws BadPaddingException * Bad padding exception. * @throws IllegalBlockSizeException * Illegal block size exception. * @throws SignatureException * Signature exception. */ public final byte[][] removeUser(final GXDLMSClient client, final byte id, final String name) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, SignatureException { GXByteBuffer data = new GXByteBuffer(); data.setUInt8(DataType.STRUCTURE.getValue()); // Add structure size. data.setUInt8(2); GXCommon.setData(null, data, DataType.UINT8, id); GXCommon.setData(null, data, DataType.STRING, name); return client.method(this, 6, data.array(), DataType.STRUCTURE); } @Override public final Object[] getValues() { return new Object[] { getLogicalName(), getObjectList(), clientSAP + "/" + serverSAP, getApplicationContextName(), getXDLMSContextInfo(), getAuthenticationMechanismName(), getSecret(), getAssociationStatus(), getSecuritySetupReference(), userList, currentUser }; } static Object getKey(IGXCryptoNotifier cryptoNotifier, SecuritySuite securitySuite, CertificateType certificateType, byte[] systemTitle, boolean encrypt) { if (cryptoNotifier == null) { throw new RuntimeException("Failed to get the certificate."); } GXCryptoKeyParameter args = new GXCryptoKeyParameter(); args.setEncrypt(encrypt); args.setSecuritySuite(securitySuite); args.setCertificateType(certificateType); args.setSystemTitle(systemTitle); PrivateKey key = null; PublicKey pub = null; cryptoNotifier.onKey(cryptoNotifier, args); if (encrypt) { key = args.getPrivateKey(); } else { pub = args.getPublicKey(); } if (encrypt) { return key; } else { return pub; } } private byte[] replyToHlsAuthentication(final GXDLMSSettings settings, final ValueEventArgs e) throws InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, SignatureException { byte[] serverChallenge = null, clientChallenge = null; long ic = 0; byte[] readSecret; boolean accept; if (settings.getAuthentication() == Authentication.HIGH_ECDSA) { try { if (settings.getSourceSystemTitle() == null || settings.getSourceSystemTitle().length != 8) { throw new IllegalArgumentException("SourceSystemTitle is invalid."); } // Get signature key if not set. if (settings.getCipher().getSigningKeyPair() == null) { PrivateKey key = (PrivateKey) getKey(settings.getCryptoNotifier(), settings.getCipher().getSecuritySuite(), CertificateType.DIGITAL_SIGNATURE, settings.getCipher().getSystemTitle(), true); PublicKey pub = (PublicKey) getKey(settings.getCryptoNotifier(), settings.getCipher().getSecuritySuite(), CertificateType.DIGITAL_SIGNATURE, settings.getCipher().getSystemTitle(), false); settings.getCipher().setKeyAgreementKeyPair(new KeyPair(pub, key)); } GXByteBuffer signature = new GXByteBuffer((byte[]) e.getParameters()); byte[] tmp; Signature ver; if (settings.getCipher().getSecuritySuite() == SecuritySuite.SUITE_1) { ver = Signature.getInstance("SHA256withECDSA"); tmp = GXAsn1Converter.toByteArray(new Object[] { new GXAsn1Integer(signature.subArray(0, 32)), new GXAsn1Integer(signature.subArray(32, 32)) }); } else if (settings.getCipher().getSecuritySuite() == SecuritySuite.SUITE_2) { ver = Signature.getInstance("SHA384withECDSA"); tmp = GXAsn1Converter.toByteArray(new Object[] { new GXAsn1Integer(signature.subArray(0, 48)), new GXAsn1Integer(signature.subArray(48, 48)) }); } else { throw new IllegalArgumentException("Invalid security suite."); } signature.size(0); signature.set(tmp); ver.initVerify(settings.getCipher().getSigningKeyPair().getPublic()); GXByteBuffer bb = new GXByteBuffer(); bb.set(settings.getSourceSystemTitle()); bb.set(settings.getCipher().getSystemTitle()); bb.set(settings.getStoCChallenge()); bb.set(settings.getCtoSChallenge()); ver.update(bb.array()); LOGGER.log(Level.INFO, "StoC " + bb.toHex(true, 0)); accept = ver.verify(signature.array()); } catch (Exception ex) { throw new RuntimeException(ex.getMessage()); } } else { if (settings.getAuthentication() == Authentication.HIGH_GMAC) { readSecret = settings.getSourceSystemTitle(); GXByteBuffer bb = new GXByteBuffer((byte[]) e.getParameters()); bb.getUInt8(); ic = bb.getUInt32(); } else if (settings.getAuthentication() == Authentication.HIGH_SHA256) { GXByteBuffer tmp = new GXByteBuffer(); tmp.set(secret); tmp.set(settings.getSourceSystemTitle()); tmp.set(settings.getCipher().getSystemTitle()); tmp.set(settings.getStoCChallenge()); tmp.set(settings.getCtoSChallenge()); readSecret = tmp.array(); } else { readSecret = secret; } serverChallenge = GXSecure.secure(settings, settings.getCipher(), ic, settings.getStoCChallenge(), readSecret); clientChallenge = (byte[]) e.getParameters(); accept = GXCommon.compare(serverChallenge, clientChallenge); } if (accept) { if (settings.getAuthentication() == Authentication.HIGH_GMAC) { readSecret = settings.getCipher().getSystemTitle(); ic = settings.getCipher().getInvocationCounter(); } else { readSecret = secret; } if (settings.getAuthentication() == Authentication.HIGH_SHA256 || settings.getAuthentication() == Authentication.HIGH_ECDSA) { GXByteBuffer tmp = new GXByteBuffer(); tmp.set(secret); tmp.set(settings.getCipher().getSystemTitle()); tmp.set(settings.getSourceSystemTitle()); tmp.set(settings.getCtoSChallenge()); tmp.set(settings.getStoCChallenge()); readSecret = tmp.array(); } byte[] tmp = GXSecure.secure(settings, settings.getCipher(), ic, settings.getCtoSChallenge(), readSecret); associationStatus = AssociationStatus.ASSOCIATED; return tmp; } else { LOGGER.info("Invalid CtoS:" + GXCommon.toHex(serverChallenge, false) + "-" + GXCommon.toHex(clientChallenge, false)); associationStatus = AssociationStatus.NON_ASSOCIATED; e.setError(ErrorCode.READ_WRITE_DENIED); } return null; } private void changeHlsSecret(final GXDLMSSettings settings, final ValueEventArgs e) { byte[] tmp = (byte[]) e.getParameters(); if (tmp == null || tmp.length == 0) { e.setError(ErrorCode.READ_WRITE_DENIED); } else { secret = tmp; } } private void removeObject(final GXDLMSSettings settings, final ValueEventArgs e) { // Remove COSEM object. GXDLMSObject obj = getObject(settings, (List) e.getParameters(), false); // Current association can't be removed. if (obj == this || (obj instanceof GXDLMSAssociationLogicalName && obj.getLogicalName().compareTo("0.0.40.0.0.255") == 0)) { e.setError(ErrorCode.INCONSISTENT_CLASS); } // Unknown objects are not removed. else if (obj instanceof IGXDLMSBase) { GXDLMSObject t = objectList.findByLN(obj.getObjectType(), obj.getLogicalName()); if (t != null) { objectList.remove(t); } boolean exists = false; // Remove object if it's not in other association views. for (GXDLMSObject it : settings.getObjects().getObjects(ObjectType.ASSOCIATION_LOGICAL_NAME)) { if (it != obj) { GXDLMSAssociationLogicalName a = (GXDLMSAssociationLogicalName) it; if (a.objectList.indexOf(obj) != -1) { exists = true; break; } } } if (!exists) { settings.getObjects().remove(obj); } } } private void addObject(final GXDLMSSettings settings, final ValueEventArgs e) { // Add COSEM object. GXDLMSObject obj = getObject(settings, (List) e.getParameters(), true); // Unknown objects are not add. if (obj instanceof IGXDLMSBase) { if (objectList.findByLN(obj.getObjectType(), obj.getLogicalName()) == null) { objectList.add(obj); if (settings.isServer()) { // Set default values from this LN. if (obj instanceof GXDLMSAssociationLogicalName) { if (obj.getLogicalName().compareTo("0.0.40.0.0.255") == 0) { e.setError(ErrorCode.UNDEFINED_OBJECT); return; } // All LN objects are using the same version. obj.setVersion(version); GXDLMSAssociationLogicalName ln = (GXDLMSAssociationLogicalName) obj; ln.getXDLMSContextInfo().setConformance(xDLMSContextInfo.getConformance()); ln.getXDLMSContextInfo().setMaxReceivePduSize(xDLMSContextInfo.getMaxReceivePduSize()); ln.getXDLMSContextInfo().setMaxSendPduSize(xDLMSContextInfo.getMaxSendPduSize()); } else if (obj instanceof GXDLMSSecuritySetup) { GXDLMSSecuritySetup ss = (GXDLMSSecuritySetup) obj; // Update server system title and keys. ss.setServerSystemTitle(settings.getCipher().getSystemTitle()); ss.setGuek(settings.getCipher().getBlockCipherKey()); ss.setGbek(settings.getCipher().getBroadcastBlockCipherKey()); ss.setGak(settings.getCipher().getAuthenticationKey()); ss.setKek(settings.getKek()); } int count = obj.getAttributeCount(); int[] list = new int[count]; for (int pos = 0; pos != count; ++pos) { if (getVersion() < 3) { list[pos] = obj.getAccess(1 + pos).getValue(); } else { list[pos] = AccessMode3.toInteger(obj.getAccess3(1 + pos)); } } accessRights.put(obj, list); count = obj.getMethodCount(); list = new int[count]; for (int pos = 0; pos != count; ++pos) { if (getVersion() < 3) { list[pos] = obj.getMethodAccess(1 + pos).getValue(); } else { list[pos] = MethodAccessMode3.toInteger(obj.getMethodAccess3(1 + pos)); } } methodAccessRights.put(obj, list); } } } else { e.setError(ErrorCode.UNDEFINED_OBJECT); } } private void addUser(final GXDLMSSettings settings, final ValueEventArgs e) { List tmp = (List) e.getParameters(); if (tmp == null || tmp.size() != 2) { e.setError(ErrorCode.READ_WRITE_DENIED); } else { userList.add(new GXSimpleEntry(((Number) tmp.get(0)).byteValue(), (String) tmp.get(1))); } } private void removeUser(final GXDLMSSettings settings, final ValueEventArgs e) { List tmp = (List) e.getParameters(); if (tmp == null || tmp.size() != 2) { e.setError(ErrorCode.READ_WRITE_DENIED); } else { byte id = ((Number) tmp.get(0)).byteValue(); String name = (String) tmp.get(1); for (Entry it : userList) { if (it.getKey() == id && it.getValue().compareTo(name) == 0) { userList.remove(it); break; } } } } @Override public final byte[] invoke(final GXDLMSSettings settings, final ValueEventArgs e) throws InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, SignatureException { switch (e.getIndex()) { case 1: return replyToHlsAuthentication(settings, e); case 2: changeHlsSecret(settings, e); break; case 3: addObject(settings, e); break; case 4: removeObject(settings, e); break; case 5: addUser(settings, e); break; case 6: removeUser(settings, e); break; default: e.setError(ErrorCode.READ_WRITE_DENIED); break; } return null; } /* * Returns collection of attributes to read. If attribute is static and * already read or device is returned HW error it is not returned. */ @Override public final int[] getAttributeIndexToRead(final boolean all) { java.util.ArrayList attributes = new java.util.ArrayList(); // LN is static and read only once. if (all || getLogicalName() == null || getLogicalName().compareTo("") == 0) { attributes.add(1); } // ObjectList is static and read only once. if (all || !isRead(2)) { attributes.add(2); } // associated_partners_id is static and read only once. if (all || !isRead(3)) { attributes.add(3); } // Application Context Name is static and read only once. if (all || !isRead(4)) { attributes.add(4); } // xDLMS Context Info if (all || !isRead(5)) { attributes.add(5); } // Authentication Mechanism Name if (all || !isRead(6)) { attributes.add(6); } // Secret if (all || !isRead(7)) { attributes.add(7); } // Association Status if (all || !isRead(8)) { attributes.add(8); } // Security Setup Reference is from version 1. if (getVersion() > 0 && (all || !isRead(9))) { attributes.add(9); } // User list and current user are in version 2. if (getVersion() > 1) { if (all || !isRead(10)) { attributes.add(10); } if (all || !isRead(11)) { attributes.add(11); } } return GXDLMSObjectHelpers.toIntArray(attributes); } @Override public final int getAttributeCount() { if (getVersion() > 1) { return 11; } // Security Setup Reference is from version 1. if (getVersion() > 0) { return 9; } return 8; } /* * Returns amount of methods. */ @Override public final int getMethodCount() { if (getVersion() > 1) return 6; return 4; } /** * Returns Association View. */ private byte[] getObjects(final GXDLMSSettings settings, final ValueEventArgs e) { try { boolean found = false; GXByteBuffer data = new GXByteBuffer(); // Add count only for first time. if (settings.getIndex() == 0) { int count = objectList.size(); // Find current association and add it if's not found. if (associationStatus == AssociationStatus.ASSOCIATED) { for (GXDLMSObject it : objectList) { if (it != this && it.getObjectType() == ObjectType.ASSOCIATION_LOGICAL_NAME) { if (it.getLogicalName().equals("0.0.40.0.0.255")) { found = true; } else if (!multipleAssociationViews) { // Remove extra association view. --count; } } } if (!found) { ++count; } } else { found = true; } settings.setCount(count); data.setUInt8(DataType.ARRAY.getValue()); GXCommon.setObjectCount(count, data); // If default association view is not found. if (!found) { data.setUInt8(DataType.STRUCTURE.getValue()); // Count data.setUInt8(4); // ClassID GXCommon.setData(settings, data, DataType.UINT16, getObjectType().getValue()); // Version GXCommon.setData(settings, data, DataType.UINT8, getVersion()); // LN GXCommon.setData(settings, data, DataType.OCTET_STRING, GXCommon.logicalNameToBytes("0.0.40.0.0.255")); // Access rights. getAccessRights(settings, this, e.getServer(), data); } } int pos = 0; boolean gbt = settings.getNegotiatedConformance().contains(Conformance.GENERAL_BLOCK_TRANSFER); for (GXDLMSObject it : objectList) { ++pos; if (!(pos <= settings.getIndex())) { if (it.getObjectType() == ObjectType.ASSOCIATION_LOGICAL_NAME) { if (!multipleAssociationViews && !(it == this || it.getLogicalName().equals("0.0.40.0.0.255"))) { settings.setIndex(settings.getIndex() + 1); continue; } } data.setUInt8(DataType.STRUCTURE.getValue()); // Count data.setUInt8(4); // ClassID GXCommon.setData(settings, data, DataType.UINT16, it.getObjectType().getValue()); // Version GXCommon.setData(settings, data, DataType.UINT8, it.getVersion()); // LN GXCommon.setData(settings, data, DataType.OCTET_STRING, GXCommon.logicalNameToBytes(it.getLogicalName())); // Access rights. getAccessRights(settings, it, e.getServer(), data); settings.setIndex(settings.getIndex() + 1); if (settings.isServer()) { // If PDU is full. if (!gbt && !e.isSkipMaxPduSize() && data.size() >= settings.getMaxPduSize()) { break; } } } } // If all objects are read. if (pos == objectList.size()) { settings.setCount(0); settings.setIndex(0); } return data.array(); } catch (Exception ex) { e.setError(ErrorCode.HARDWARE_FAULT); return null; } } private void getAccessRights(final GXDLMSSettings settings, final GXDLMSObject item, final GXDLMSServerBase server, final GXByteBuffer data) throws Exception { data.setUInt8(DataType.STRUCTURE.getValue()); data.setUInt8(2); if (server == null) { data.setUInt8(DataType.ARRAY.getValue()); data.setUInt8(0); data.setUInt8(DataType.ARRAY.getValue()); data.setUInt8(0); } else { data.setUInt8(DataType.ARRAY.getValue()); int cnt = item.getAttributeCount(); data.setUInt8(cnt); ValueEventArgs e = new ValueEventArgs(server, item, 0, 0, null); int m; for (int pos = 0; pos != cnt; ++pos) { e.setIndex(pos + 1); m = server.notifyGetAttributeAccess(e); // attribute_access_item data.setUInt8(DataType.STRUCTURE.getValue()); data.setUInt8(3); GXCommon.setData(settings, data, DataType.INT8, pos + 1); GXCommon.setData(settings, data, DataType.ENUM, m); GXCommon.setData(settings, data, DataType.NONE, null); } data.setUInt8(DataType.ARRAY.getValue()); cnt = item.getMethodCount(); data.setUInt8(cnt); for (int pos = 0; pos != cnt; ++pos) { e.setIndex(pos + 1); // attribute_access_item data.setUInt8(DataType.STRUCTURE.getValue()); data.setUInt8(2); GXCommon.setData(settings, data, DataType.INT8, pos + 1); m = server.notifyGetMethodAccess(e); // If version is 0. if (getVersion() == 0) { GXCommon.setData(settings, data, DataType.BOOLEAN, m != 0); } else { GXCommon.setData(settings, data, DataType.ENUM, m); } } } } final void updateAccessRights(final GXDLMSObject obj, final List buff) { if (buff != null && !buff.isEmpty()) { int ver; if (obj instanceof GXDLMSAssociationLogicalName) { ver = obj.getVersion(); } else { ver = getVersion(); } for (Object access : (List) buff.get(0)) { List attributeAccess = (List) access; int id = ((Number) attributeAccess.get(0)).intValue(); int tmp = ((Number) attributeAccess.get(1)).intValue(); if (ver < 3) { obj.setAccess(id, AccessMode.forValue(tmp)); } else { obj.setAccess3(id, AccessMode3.forValue(tmp)); } } for (Object access : (List) buff.get(1)) { List methodAccess = (List) access; int id = ((Number) methodAccess.get(0)).intValue(); int tmp; // If version is 0. if (methodAccess.get(1) instanceof Boolean) { if (((Boolean) methodAccess.get(1)).booleanValue()) { tmp = 1; } else { tmp = 0; } } else { // If version is 1. tmp = ((Number) methodAccess.get(1)).intValue(); } if (ver < 3) { obj.setMethodAccess(id, MethodAccessMode.forValue(tmp)); } else { obj.setMethodAccess3(id, MethodAccessMode3.forValue(tmp)); } } } } /* * Returns User list. */ private GXByteBuffer getUserList(final GXDLMSSettings settings, final ValueEventArgs e) { GXByteBuffer data = new GXByteBuffer(); // Add count only for first time. if (settings.getIndex() == 0) { settings.setCount(userList.size()); data.setUInt8(DataType.ARRAY.getValue()); GXCommon.setObjectCount(userList.size(), data); } int pos = 0; for (Entry it : userList) { ++pos; if (!(pos <= settings.getIndex())) { settings.setIndex(settings.getIndex() + 1); data.setUInt8(DataType.STRUCTURE.getValue()); data.setUInt8(2); // Count GXCommon.setData(settings, data, DataType.UINT8, it.getKey()); // Id GXCommon.setData(settings, data, DataType.STRING, it.getValue()); // Name } } return data; } @Override public final DataType getDataType(final int index) { if (index == 1) { return DataType.OCTET_STRING; } if (index == 2) { return DataType.ARRAY; } if (index == 3) { return DataType.STRUCTURE; } if (index == 4) { return DataType.STRUCTURE; } if (index == 5) { return DataType.STRUCTURE; } if (index == 6) { return DataType.STRUCTURE; } if (index == 7) { return DataType.OCTET_STRING; } if (index == 8) { return DataType.ENUM; } if (getVersion() > 0 && index == 9) { return DataType.OCTET_STRING; } if (getVersion() > 1) { if (index == 10) { return DataType.ARRAY; } if (index == 11) { return DataType.STRUCTURE; } } throw new IllegalArgumentException("getDataType failed. Invalid attribute index."); } /* * Returns value of given attribute. */ @Override public final Object getValue(final GXDLMSSettings settings, final ValueEventArgs e) { if (e.getIndex() == 1) { return GXCommon.logicalNameToBytes(getLogicalName()); } if (e.getIndex() == 2) { return getObjects(settings, e); } if (e.getIndex() == 3) { GXByteBuffer data = new GXByteBuffer(); data.setUInt8(DataType.STRUCTURE.getValue()); // Add count data.setUInt8(2); data.setUInt8(DataType.INT8.getValue()); data.setUInt8(clientSAP); data.setUInt8(DataType.UINT16.getValue()); data.setUInt16(serverSAP); return data.array(); } if (e.getIndex() == 4) { GXByteBuffer data = new GXByteBuffer(); data.setUInt8(DataType.STRUCTURE.getValue()); // Add count data.setUInt8(0x7); GXCommon.setData(settings, data, DataType.UINT8, applicationContextName.getJointIsoCtt()); GXCommon.setData(settings, data, DataType.UINT8, applicationContextName.getCountry()); GXCommon.setData(settings, data, DataType.UINT16, applicationContextName.getCountryName()); GXCommon.setData(settings, data, DataType.UINT8, applicationContextName.getIdentifiedOrganization()); GXCommon.setData(settings, data, DataType.UINT8, applicationContextName.getDlmsUA()); GXCommon.setData(settings, data, DataType.UINT8, applicationContextName.getApplicationContext()); GXCommon.setData(settings, data, DataType.UINT8, applicationContextName.getContextId().getValue()); return data.array(); } if (e.getIndex() == 5) { GXByteBuffer data = new GXByteBuffer(); data.setUInt8(DataType.STRUCTURE.getValue()); data.setUInt8(6); GXCommon.setData(settings, data, DataType.BITSTRING, GXBitString.toBitString(Conformance.toInteger(xDLMSContextInfo.getConformance()), 24)); GXCommon.setData(settings, data, DataType.UINT16, xDLMSContextInfo.getMaxReceivePduSize()); GXCommon.setData(settings, data, DataType.UINT16, xDLMSContextInfo.getMaxSendPduSize()); GXCommon.setData(settings, data, DataType.UINT8, xDLMSContextInfo.getDlmsVersionNumber()); GXCommon.setData(settings, data, DataType.INT8, xDLMSContextInfo.getQualityOfService()); GXCommon.setData(settings, data, DataType.OCTET_STRING, xDLMSContextInfo.getCypheringInfo()); return data.array(); } if (e.getIndex() == 6) { GXByteBuffer data = new GXByteBuffer(); data.setUInt8(DataType.STRUCTURE.getValue()); // Add count data.setUInt8(0x7); GXCommon.setData(settings, data, DataType.UINT8, authenticationMechanismName.getJointIsoCtt()); GXCommon.setData(settings, data, DataType.UINT8, authenticationMechanismName.getCountry()); GXCommon.setData(settings, data, DataType.UINT16, authenticationMechanismName.getCountryName()); GXCommon.setData(settings, data, DataType.UINT8, authenticationMechanismName.getIdentifiedOrganization()); GXCommon.setData(settings, data, DataType.UINT8, authenticationMechanismName.getDlmsUA()); GXCommon.setData(settings, data, DataType.UINT8, authenticationMechanismName.getAuthenticationMechanismName()); GXCommon.setData(settings, data, DataType.UINT8, authenticationMechanismName.getMechanismId().getValue()); return data.array(); } if (e.getIndex() == 7) { return secret; } if (e.getIndex() == 8) { return getAssociationStatus().ordinal(); } if (e.getIndex() == 9) { return GXCommon.logicalNameToBytes(getSecuritySetupReference()); } if (e.getIndex() == 10) { return getUserList(settings, e).array(); } if (e.getIndex() == 11) { GXByteBuffer data = new GXByteBuffer(); data.setUInt8(DataType.STRUCTURE.getValue()); // Add structure size. data.setUInt8(2); if (currentUser == null) { GXCommon.setData(settings, data, DataType.UINT8, 0); GXCommon.setData(settings, data, DataType.STRING, null); } else { GXCommon.setData(settings, data, DataType.UINT8, currentUser.getKey()); GXCommon.setData(settings, data, DataType.STRING, currentUser.getValue()); } return data.array(); } e.setError(ErrorCode.READ_WRITE_DENIED); return null; } /** * Get object. * * @param settings * DLMS settings. * @param item * received data. * @param add * Is data added to settings object list. * @return Created object. */ private GXDLMSObject getObject(final GXDLMSSettings settings, final List item, boolean add) { ObjectType type = ObjectType.forValue(((Number) item.get(0)).intValue()); int version = ((Number) item.get(1)).intValue(); String ln = GXCommon.toLogicalName((byte[]) item.get(2)); GXDLMSObject obj = settings.getObjects().findByLN(type, ln); if (obj == null) { obj = gurux.dlms.GXDLMSClient.createObject(type); obj.setLogicalName(ln); obj.setVersion(version); if (settings.isServer() && add) { settings.getObjects().add(obj); } } if (add && obj instanceof IGXDLMSBase && item.get(3) != null) { List arr = (List) item.get(3); updateAccessRights(obj, arr); } return obj; } private void updateObjectList(final GXDLMSSettings settings, final GXDLMSObjectCollection target, final Object value) { target.clear(); if (value != null) { for (Object tmp : (List) value) { List item = (List) tmp; GXDLMSObject obj = getObject(settings, item, true); // Add only known objects. if (obj instanceof IGXDLMSBase) { target.add(obj); } } } } private void updateApplicationContextName(final Object value) { // Value of the object identifier encoded in BER if (value instanceof byte[]) { GXByteBuffer buff = new GXByteBuffer((byte[]) value); if (buff.getUInt8(0) == 0x60) { applicationContextName.setJointIsoCtt(0); applicationContextName.setCountry(0); applicationContextName.setCountryName(0); buff.position(buff.position() + 3); applicationContextName.setIdentifiedOrganization(buff.getUInt8()); applicationContextName.setDlmsUA(buff.getUInt8()); applicationContextName.setApplicationContext(buff.getUInt8()); applicationContextName.setContextId(ApplicationContextName.forValue(buff.getUInt8())); } else { // Get Tag and length. if (buff.getUInt8() != 2 && buff.getUInt8() != 7) { throw new IllegalArgumentException(); } // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } applicationContextName.setJointIsoCtt(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } applicationContextName.setCountry(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x12) { throw new IllegalArgumentException(); } applicationContextName.setCountryName(buff.getUInt16()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } applicationContextName.setIdentifiedOrganization(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } applicationContextName.setDlmsUA(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } applicationContextName.setApplicationContext(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } applicationContextName.setContextId(ApplicationContextName.forValue(buff.getUInt8())); } } else { if (value != null) { List arr = (List) value; applicationContextName.setJointIsoCtt(((Number) arr.get(0)).intValue()); applicationContextName.setCountry(((Number) arr.get(1)).intValue()); applicationContextName.setCountryName(((Number) arr.get(2)).intValue()); applicationContextName.setIdentifiedOrganization(((Number) arr.get(3)).intValue()); applicationContextName.setDlmsUA(((Number) arr.get(4)).intValue()); applicationContextName.setApplicationContext(((Number) arr.get(5)).intValue()); applicationContextName.setContextId(ApplicationContextName.forValue(((Number) arr.get(6)).intValue())); } } } private void updateAuthenticationMechanismName(final Object value) { if (value != null) { // Value of the object identifier encoded in BER if (value instanceof byte[]) { GXByteBuffer buff = new GXByteBuffer((byte[]) value); if (buff.getUInt8(0) == 0x60) { authenticationMechanismName.setJointIsoCtt(0); authenticationMechanismName.setCountry(0); authenticationMechanismName.setCountryName(0); buff.position(buff.position() + 3); authenticationMechanismName.setIdentifiedOrganization(buff.getUInt8()); authenticationMechanismName.setDlmsUA(buff.getUInt8()); authenticationMechanismName.setAuthenticationMechanismName(buff.getUInt8()); authenticationMechanismName.setMechanismId(Authentication.forValue(buff.getUInt8())); } else { // Get Tag and length. if (buff.getUInt8() != 2 && buff.getUInt8() != 7) { throw new IllegalArgumentException(); } // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } authenticationMechanismName.setJointIsoCtt(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } authenticationMechanismName.setCountry(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x12) { throw new IllegalArgumentException(); } authenticationMechanismName.setCountryName(buff.getUInt16()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } authenticationMechanismName.setIdentifiedOrganization(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } authenticationMechanismName.setDlmsUA(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } authenticationMechanismName.setAuthenticationMechanismName(buff.getUInt8()); // Get tag if (buff.getUInt8() != 0x11) { throw new IllegalArgumentException(); } authenticationMechanismName.setMechanismId(Authentication.forValue(buff.getUInt8())); } } else { List arr = (List) value; authenticationMechanismName.setJointIsoCtt(((Number) arr.get(0)).intValue()); authenticationMechanismName.setCountry(((Number) arr.get(1)).intValue()); authenticationMechanismName.setCountryName(((Number) arr.get(2)).intValue()); authenticationMechanismName.setIdentifiedOrganization(((Number) arr.get(3)).intValue()); authenticationMechanismName.setDlmsUA(((Number) arr.get(4)).intValue()); authenticationMechanismName.setAuthenticationMechanismName(((Number) arr.get(5)).intValue()); authenticationMechanismName.setMechanismId(Authentication.forValue(((Number) arr.get(6)).intValue())); } } } /* * Set value of given attribute. */ @Override public final void setValue(final GXDLMSSettings settings, final ValueEventArgs e) { switch (e.getIndex()) { case 1: setLogicalName(GXCommon.toLogicalName(e.getValue())); break; case 2: updateObjectList(settings, objectList, e.getValue()); break; case 3: if (e.getValue() != null) { List tmp = (List) e.getValue(); clientSAP = ((Number) tmp.get(0)).shortValue(); serverSAP = ((Number) tmp.get(1)).shortValue(); } break; case 4: updateApplicationContextName(e.getValue()); break; case 5: if (e.getValue() != null) { List arr = (List) e.getValue(); xDLMSContextInfo.setConformance(Conformance.forValue(((GXBitString) arr.get(0)).toInteger())); xDLMSContextInfo.setMaxReceivePduSize(((Number) arr.get(1)).intValue()); xDLMSContextInfo.setMaxSendPduSize(((Number) arr.get(2)).intValue()); xDLMSContextInfo.setDlmsVersionNumber(((Number) arr.get(3)).byteValue()); xDLMSContextInfo.setQualityOfService(((Number) arr.get(4)).intValue()); xDLMSContextInfo.setCypheringInfo((byte[]) arr.get(5)); } break; case 6: updateAuthenticationMechanismName(e.getValue()); break; case 7: secret = (byte[]) e.getValue(); break; case 8: if (e.getValue() == null) { setAssociationStatus(AssociationStatus.NON_ASSOCIATED); } else { setAssociationStatus(AssociationStatus.values()[((Number) e.getValue()).intValue()]); } break; case 9: setSecuritySetupReference(GXCommon.toLogicalName((byte[]) e.getValue())); break; case 10: userList.clear(); if (e.getValue() != null) { for (Object tmp : (List) e.getValue()) { List item = (List) tmp; userList.add(new GXSimpleEntry((Byte) item.get(0), (String) item.get(1))); } } break; case 11: if (e.getValue() != null) { List tmp = (List) e.getValue(); currentUser = new GXSimpleEntry(((Number) tmp.get(0)).byteValue(), (String) tmp.get(1)); } else { currentUser = null; } break; default: e.setError(ErrorCode.READ_WRITE_DENIED); } } @Override public final void load(final GXXmlReader reader) throws XMLStreamException { // Load objects. String str; objectList.clear(); if (reader.isStartElement("ObjectList", true)) { String target; int[] buff; while (!reader.isEOF()) { if (reader.isStartElement()) { target = reader.getName(); if (target.startsWith("GXDLMS")) { str = target.substring(6); reader.read(); ObjectType type = ObjectType.getEnum(target.substring(6)); if (type == null) { throw new RuntimeException("Invalid object type: " + target + "."); } String ln = reader.readElementContentAsString("LN"); GXDLMSObject obj = reader.getObjects().findByLN(type, ln); if (obj == null) { obj = GXDLMSClient.createObject(type); obj.setVersion(0); obj.setLogicalName(ln); reader.getObjects().add(obj); } objectList.add(obj); // methodAccessRights String access = reader.readElementContentAsString("Access"); if (access != null && access != "") { byte[] tmp = access.getBytes(); buff = new int[tmp.length]; for (int pos = 0; pos != tmp.length; ++pos) { buff[pos] = tmp[pos] - 0x30; } accessRights.put(obj, buff); } access = reader.readElementContentAsString("Access3"); if (access != null && access != "") { buff = new int[access.length() / 4]; for (int pos = 0; pos != buff.length; ++pos) { buff[pos] = Integer.parseInt(access.substring(4 * pos, 4 * pos + 4), 16) & ~0x8000; } accessRights.put(obj, buff); } access = reader.readElementContentAsString("MethodAccess"); if (access != null && access != "") { byte[] tmp = access.getBytes(); buff = new int[tmp.length]; for (int pos = 0; pos != tmp.length; ++pos) { buff[pos] = tmp[pos] - 0x30; } methodAccessRights.put(obj, buff); } access = reader.readElementContentAsString("MethodAccess3"); if (access != null && access != "") { buff = new int[access.length() / 4]; for (int pos = 0; pos != buff.length; ++pos) { buff[pos] = Integer.parseInt(access.substring(4 * pos, 4 * pos + 4), 16) & ~0x8000; } methodAccessRights.put(obj, buff); } reader.readEndElement(target); } else { break; } } else { if (reader.getName().compareTo("ObjectList") == 0) { break; } reader.read(); } } reader.readEndElement("ObjectList"); // Add logical name association object to the object list. objectList.add(this); } clientSAP = (byte) reader.readElementContentAsInt("ClientSAP"); serverSAP = (byte) reader.readElementContentAsInt("ServerSAP"); if (reader.isStartElement("ApplicationContextName", true)) { applicationContextName.setJointIsoCtt(reader.readElementContentAsInt("JointIsoCtt")); applicationContextName.setCountry(reader.readElementContentAsInt("Country")); applicationContextName.setCountryName(reader.readElementContentAsInt("CountryName")); applicationContextName.setIdentifiedOrganization(reader.readElementContentAsInt("IdentifiedOrganization")); applicationContextName.setDlmsUA(reader.readElementContentAsInt("DlmsUA")); applicationContextName.setApplicationContext(reader.readElementContentAsInt("ApplicationContext")); applicationContextName .setContextId(ApplicationContextName.forValue(reader.readElementContentAsInt("ContextId"))); reader.readEndElement("ApplicationContextName"); } if (reader.isStartElement("XDLMSContextInfo", true)) { xDLMSContextInfo.setConformance(Conformance.forValue(reader.readElementContentAsInt("Conformance"))); xDLMSContextInfo.setMaxReceivePduSize(reader.readElementContentAsInt("MaxReceivePduSize")); xDLMSContextInfo.setMaxSendPduSize(reader.readElementContentAsInt("MaxSendPduSize")); xDLMSContextInfo.setDlmsVersionNumber((byte) reader.readElementContentAsInt("DlmsVersionNumber")); xDLMSContextInfo.setQualityOfService(reader.readElementContentAsInt("QualityOfService")); xDLMSContextInfo .setCypheringInfo(GXDLMSTranslator.hexToBytes(reader.readElementContentAsString("CypheringInfo"))); reader.readEndElement("XDLMSContextInfo"); } if (reader.isStartElement("AuthenticationMechanismName", true) || reader.isStartElement("XDLMSContextInfo", true)) { authenticationMechanismName.setJointIsoCtt(reader.readElementContentAsInt("JointIsoCtt")); authenticationMechanismName.setCountry(reader.readElementContentAsInt("Country")); authenticationMechanismName.setCountryName(reader.readElementContentAsInt("CountryName")); authenticationMechanismName .setIdentifiedOrganization(reader.readElementContentAsInt("IdentifiedOrganization")); authenticationMechanismName.setDlmsUA(reader.readElementContentAsInt("DlmsUA")); authenticationMechanismName .setAuthenticationMechanismName(reader.readElementContentAsInt("AuthenticationMechanismName")); authenticationMechanismName .setMechanismId(Authentication.forValue(reader.readElementContentAsInt("MechanismId"))); reader.readEndElement("AuthenticationMechanismName"); reader.readEndElement("XDLMSContextInfo"); } str = reader.readElementContentAsString("Secret"); if (str == null) { secret = null; } else { secret = GXDLMSTranslator.hexToBytes(str); } associationStatus = AssociationStatus.values()[reader.readElementContentAsInt("AssociationStatus")]; securitySetupReference = reader.readElementContentAsString("SecuritySetupReference"); // Load users. userList.clear(); if (reader.isStartElement("Users", true)) { while (reader.isStartElement("Item", true)) { byte id = (byte) reader.readElementContentAsInt("Id"); String name = reader.readElementContentAsString("Name"); userList.add(new GXSimpleEntry(id, name)); } reader.readEndElement("Users"); } multipleAssociationViews = reader.readElementContentAsInt("MultipleAssociationViews") != 0; } private String getObjectName(final ObjectType ot) { String name = String.valueOf(ot).toLowerCase(); String tmp[] = name.split("_"); for (int pos = 0; pos != tmp.length; ++pos) { char[] array = tmp[pos].toCharArray(); array[0] = Character.toUpperCase(array[0]); tmp[pos] = new String(array); } name = String.join("", tmp); return name; } @Override public final void save(final GXXmlWriter writer) throws XMLStreamException { // Add objects. if (objectList != null) { writer.writeStartElement("ObjectList"); StringBuilder sb = new StringBuilder(); for (GXDLMSObject it : objectList) { // Default association view is not saved. if (!(it.getObjectType() == ObjectType.ASSOCIATION_LOGICAL_NAME && (it == this || it.getLogicalName().equals("0.0.40.0.0.255")))) { if (multipleAssociationViews || it.getObjectType() != ObjectType.ASSOCIATION_LOGICAL_NAME) { writer.writeStartElement("GXDLMS" + getObjectName(it.getObjectType())); // Add LN writer.writeElementString("LN", it.getLogicalName()); if (!accessRights.containsKey(it)) { if (getVersion() < 3) { for (int pos = 1; pos != ((IGXDLMSBase) it).getAttributeCount() + 1; ++pos) { setAccess(it, pos, it.getAccess(pos)); } } else { for (int pos = 1; pos != ((IGXDLMSBase) it).getAttributeCount() + 1; ++pos) { setAccess3(it, pos, it.getAccess3(pos)); } } } // Add access rights if set. if (accessRights.containsKey(it)) { int[] buff = accessRights.get(it); sb.setLength(0); for (int pos = 0; pos != buff.length; ++pos) { if (getVersion() < 3) { sb.append(String.valueOf(buff[pos])); } else { // Set highest bit so value is write with // two byte. sb.append(Integer.toHexString(0x8000 | buff[pos])); } } if (getVersion() < 3) { writer.writeElementString("Access", sb.toString()); } else { writer.writeElementString("Access3", sb.toString()); } } if (!methodAccessRights.containsKey(it)) { if (getVersion() < 3) { for (int pos = 1; pos != ((IGXDLMSBase) it).getMethodCount() + 1; ++pos) { setMethodAccess(it, pos, it.getMethodAccess(pos)); } } else { for (int pos = 1; pos != ((IGXDLMSBase) it).getMethodCount() + 1; ++pos) { setMethodAccess3(it, pos, it.getMethodAccess3(pos)); } } } if (methodAccessRights.containsKey(it)) { int[] buff = methodAccessRights.get(it); sb.setLength(0); for (int pos = 0; pos != buff.length; ++pos) { if (getVersion() < 3) { sb.append(String.valueOf(buff[pos])); } else { // Set highest bit so value is write with // two byte. sb.append(Integer.toHexString(0x8000 | buff[pos])); } } if (getVersion() < 3) { writer.writeElementString("MethodAccess", sb.toString()); } else { writer.writeElementString("MethodAccess3", sb.toString()); } } writer.writeEndElement(); } } } writer.writeEndElement(); } writer.writeElementString("ClientSAP", clientSAP); writer.writeElementString("ServerSAP", serverSAP); if (applicationContextName != null) { writer.writeStartElement("ApplicationContextName"); writer.writeElementString("JointIsoCtt", applicationContextName.getJointIsoCtt()); writer.writeElementString("Country", applicationContextName.getCountry()); writer.writeElementString("CountryName", applicationContextName.getCountryName()); writer.writeElementString("IdentifiedOrganization", applicationContextName.getIdentifiedOrganization()); writer.writeElementString("DlmsUA", applicationContextName.getDlmsUA()); writer.writeElementString("ApplicationContext", applicationContextName.getApplicationContext()); writer.writeElementString("ContextId", applicationContextName.getContextId().getValue()); writer.writeEndElement(); } if (xDLMSContextInfo != null) { writer.writeStartElement("XDLMSContextInfo"); writer.writeElementString("Conformance", Conformance.toInteger(xDLMSContextInfo.getConformance())); writer.writeElementString("MaxReceivePduSize", xDLMSContextInfo.getMaxReceivePduSize()); writer.writeElementString("MaxSendPduSize", xDLMSContextInfo.getMaxSendPduSize()); writer.writeElementString("DlmsVersionNumber", xDLMSContextInfo.getDlmsVersionNumber()); writer.writeElementString("QualityOfService", xDLMSContextInfo.getQualityOfService()); writer.writeElementString("CypheringInfo", GXDLMSTranslator.toHex(xDLMSContextInfo.getCypheringInfo())); writer.writeEndElement(); } if (authenticationMechanismName != null) { writer.writeStartElement("AuthenticationMechanismName"); writer.writeElementString("JointIsoCtt", authenticationMechanismName.getJointIsoCtt()); writer.writeElementString("Country", authenticationMechanismName.getCountry()); writer.writeElementString("CountryName", authenticationMechanismName.getCountryName()); writer.writeElementString("IdentifiedOrganization", authenticationMechanismName.getIdentifiedOrganization()); writer.writeElementString("DlmsUA", authenticationMechanismName.getDlmsUA()); writer.writeElementString("AuthenticationMechanismName", authenticationMechanismName.getAuthenticationMechanismName()); writer.writeElementString("MechanismId", authenticationMechanismName.getMechanismId().getValue()); writer.writeEndElement(); } writer.writeElementString("Secret", GXDLMSTranslator.toHex(secret)); writer.writeElementString("AssociationStatus", associationStatus.ordinal()); writer.writeElementString("SecuritySetupReference", securitySetupReference); // Add users. if (userList != null) { writer.writeStartElement("Users"); for (Entry it : userList) { writer.writeStartElement("User"); writer.writeElementString("Id", it.getKey()); writer.writeElementString("Name", it.getValue()); writer.writeEndElement(); } writer.writeEndElement(); } writer.writeElementString("MultipleAssociationViews", multipleAssociationViews); } @Override public final void postLoad(final GXXmlReader reader) { } /** * @return User list. */ public List> getUserList() { return userList; } /** * @param userList * User list. */ public void setUserList(List> userList) { this.userList = userList; } /** * @return Current user. */ public Entry getCurrentUser() { return currentUser; } /** * @param currentUser * Current user. */ public void setCurrentUser(Entry currentUser) { this.currentUser = currentUser; } /** * @return Is this association including other association views. */ public boolean isMultipleAssociationViews() { return multipleAssociationViews; } /** * @param value * Is this association including other association views. */ public void setMultipleAssociationViews(final boolean value) { multipleAssociationViews = value; } /** * Returns default attribute access mode for the selected object. * * @param target * target object. * @param attributeIndex * Attribute index. * @return Returns Default access mode. */ private static int getAttributeAccess(final GXDLMSObject target, final int attributeIndex) { if (attributeIndex == 1) { return AccessMode.READ.getValue(); } GXDLMSAttributeSettings att = target.getAttributes().find(attributeIndex); if (att != null) { return att.getAccess().getValue(); } switch (target.getObjectType()) { case ACCOUNT: break; case ACTION_SCHEDULE: break; case ACTIVITY_CALENDAR: break; case ARBITRATOR: break; case ASSOCIATION_LOGICAL_NAME: // Association Status if (attributeIndex == 8) { return AccessMode.READ.getValue(); } case ASSOCIATION_SHORT_NAME: break; case AUTO_ANSWER: break; case AUTO_CONNECT: break; case CHARGE: break; case CLOCK: break; case COMPACT_DATA: break; case CREDIT: break; case DATA: break; case DATA_PROTECTION: break; case DEMAND_REGISTER: break; case DISCONNECT_CONTROL: break; case EXTENDED_REGISTER: break; case G3_PLC6_LO_WPAN: break; case G3_PLC_MAC_LAYER_COUNTERS: break; case G3_PLC_MAC_SETUP: break; case GPRS_SETUP: break; case GSM_DIAGNOSTIC: break; case IEC_61334_4_32_LLC_SETUP: break; case IEC_8802_LLC_TYPE1_SETUP: break; case IEC_8802_LLC_TYPE2_SETUP: break; case IEC_8802_LLC_TYPE3_SETUP: break; case IEC_HDLC_SETUP: break; case IEC_LOCAL_PORT_SETUP: break; case IEC_TWISTED_PAIR_SETUP: break; case IMAGE_TRANSFER: break; case IP4_SETUP: break; case IP6_SETUP: break; case LIMITER: break; case LLC_SSCS_SETUP: break; case MAC_ADDRESS_SETUP: break; case MBUS_CLIENT: break; case MBUS_MASTER_PORT_SETUP: break; case MBUS_SLAVE_PORT_SETUP: break; case MODEM_CONFIGURATION: break; case NONE: break; case PARAMETER_MONITOR: break; case PPP_SETUP: break; case PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: break; case PRIME_NB_OFDM_PLC_MAC_COUNTERS: break; case PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: break; case PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: break; case PRIME_NB_OFDM_PLC_MAC_SETUP: break; case PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: break; case PROFILE_GENERIC: break; case PUSH_SETUP: break; case REGISTER: break; case REGISTER_ACTIVATION: break; case REGISTER_MONITOR: break; case REGISTER_TABLE: break; case SAP_ASSIGNMENT: break; case SCHEDULE: break; case SCRIPT_TABLE: break; case SECURITY_SETUP: break; case SFSK_ACTIVE_INITIATOR: break; case SFSK_MAC_COUNTERS: break; case SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: break; case SFSK_PHY_MAC_SETUP: break; case SFSK_REPORTING_SYSTEM_LIST: break; case SMTP_SETUP: break; case SPECIAL_DAYS_TABLE: break; case STATUS_MAPPING: break; case TARIFF_PLAN: break; case TCP_UDP_SETUP: break; case TOKEN_GATEWAY: break; case UTILITY_TABLES: break; case WIRELESS_MODE_Q_CHANNEL: break; case ZIG_BEE_NETWORK_CONTROL: break; case ZIG_BEE_SAS_APS_FRAGMENTATION: break; case ZIG_BEE_SAS_JOIN: break; case ZIG_BEE_SAS_STARTUP: break; default: break; } return AccessMode.READ_WRITE.getValue(); } /** * Returns access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @return Access mode. */ public AccessMode getAccess(final GXDLMSObject target, final int index) { if (target == this || (target instanceof GXDLMSAssociationLogicalName && target.getLogicalName().compareTo("0.0.40.0.0.255") == 0)) { return this.getAccess(index); } int[] tmp = accessRights.get(target); if (tmp == null) { return AccessMode.forValue(getAttributeAccess(target, index)); } return AccessMode.forValue(tmp[index - 1]); } /** * Sets access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @param access * Access mode. */ public void setAccess(final GXDLMSObject target, final int index, final AccessMode access) { if (accessRights.containsKey(target)) { accessRights.get(target)[index - 1] = access.getValue(); } else { int[] list = new int[target.getAttributeCount()]; Arrays.fill(list, 3); list[index - 1] = access.getValue(); accessRights.put(target, list); } } /** * Sets access mode for given object. * * @param target * COSEM object. * @param access * Access modes. */ public void setAccess(final GXDLMSObject target, final AccessMode[] access) { int count = target.getAttributeCount(); if (count < access.length) { throw new RuntimeException("Invalid access buffer."); } int[] buff = new int[count]; Arrays.fill(buff, 3); for (int pos = 0; pos != access.length; ++pos) { buff[pos] = access[pos].getValue(); } accessRights.put(target, buff); } /** * Returns method access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @return Method access mode. */ public MethodAccessMode getMethodAccess(final GXDLMSObject target, final int index) { if (target == this || (target instanceof GXDLMSAssociationLogicalName && target.getLogicalName().compareTo("0.0.40.0.0.255") == 0) || methodAccessRights.get(target) == null) { return this.getMethodAccess(index); } return MethodAccessMode.forValue(methodAccessRights.get(target)[index - 1]); } /** * Sets method access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @param access * Method access mode. */ public void setMethodAccess(final GXDLMSObject target, final int index, final MethodAccessMode access) { if (methodAccessRights.containsKey(target)) { methodAccessRights.get(target)[index - 1] = access.getValue(); } else { int[] list = new int[target.getMethodCount()]; Arrays.fill(list, 1); list[index - 1] = access.getValue(); methodAccessRights.put(target, list); } } /** * Sets method access mode for given object. * * @param target * COSEM object. * @param access * Method access modes. */ public void setMethodAccess(final GXDLMSObject target, final MethodAccessMode[] access) { int count = target.getMethodCount(); if (count < access.length) { throw new RuntimeException("Invalid access buffer."); } int[] buff = new int[count]; Arrays.fill(buff, 1); for (int pos = 0; pos != access.length; ++pos) { buff[pos] = access[pos].getValue(); } methodAccessRights.put(target, buff); } /** * Returns access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @return Access mode. */ public Set getAccess3(final GXDLMSObject target, final int index) { if (target == this || (target instanceof GXDLMSAssociationLogicalName && target.getLogicalName().compareTo("0.0.40.0.0.255") == 0)) { return this.getAccess3(index); } int[] tmp = accessRights.get(target); if (tmp == null) { return AccessMode3.forValue(getAttributeAccess(target, index)); } return AccessMode3.forValue(tmp[index - 1]); } /** * Sets access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @param access * Access mode. */ public void setAccess3(final GXDLMSObject target, final int index, final Set access) { if (accessRights.containsKey(target)) { accessRights.get(target)[index - 1] = AccessMode3.toInteger(access); } else { int[] list = new int[target.getAttributeCount()]; Arrays.fill(list, 3); list[index - 1] = AccessMode3.toInteger(access); accessRights.put(target, list); } } /** * Sets access mode for given object. * * @param target * COSEM object. * @param access * Access modes. */ public void setAccess3(final GXDLMSObject target, final Set[] access) { int count = target.getAttributeCount(); if (count < access.length) { throw new RuntimeException("Invalid access buffer."); } int[] buff = new int[count]; Arrays.fill(buff, 3); for (int pos = 0; pos != access.length; ++pos) { buff[pos] = AccessMode3.toInteger(access[pos]); } accessRights.put(target, buff); } /** * Returns method access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @return Method access mode. */ public Set getMethodAccess3(final GXDLMSObject target, final int index) { if (target == this || (target instanceof GXDLMSAssociationLogicalName && target.getLogicalName().compareTo("0.0.40.0.0.255") == 0) || accessRights.get(target) == null) { return this.getMethodAccess3(index); } return MethodAccessMode3.forValue(methodAccessRights.get(target)[index - 1]); } /** * Sets method access mode for given object. * * @param target * COSEM object. * @param index * Attribute index. * @param access * Method access mode. */ public void setMethodAccess3(final GXDLMSObject target, final int index, final Set access) { if (methodAccessRights.containsKey(target)) { methodAccessRights.get(target)[index - 1] = MethodAccessMode3.toInteger(access); } else { int[] list = new int[target.getMethodCount()]; Arrays.fill(list, 1); list[index - 1] = MethodAccessMode3.toInteger(access); methodAccessRights.put(target, list); } } /** * Sets method access mode for given object. * * @param target * COSEM object. * @param access * Method access modes. */ public void setMethodAccess3(final GXDLMSObject target, final Set[] access) { int count = target.getMethodCount(); if (count < access.length) { throw new RuntimeException("Invalid access buffer."); } int[] buff = new int[count]; Arrays.fill(buff, 1); for (int pos = 0; pos != access.length; ++pos) { buff[pos] = MethodAccessMode3.toInteger(access[pos]); } methodAccessRights.put(target, buff); } @Override public String[] getNames() { if (version == 0) { return new String[] { "Logical Name", "Object List", "Associated partners Id", "Application Context Name", "xDLMS Context Info", "Authentication Mechanism Name", "Secret", "Association Status" }; } if (version == 1) { return new String[] { "Logical Name", "Object List", "Associated partners Id", "Application Context Name", "xDLMS Context Info", "Authentication Mechanism Name", "Secret", "Association Status", "Security Setup Reference" }; } return new String[] { "Logical Name", "Object List", "Associated partners Id", "Application Context Name", "xDLMS Context Info", "Authentication Mechanism Name", "Secret", "Association Status", "Security Setup Reference", "UserList", "CurrentUser" }; } @Override public String[] getMethodNames() { if (version > 1) return new String[] { "Reply to HLS authentication", "Change HLS secret", "Add object", "Remove object", "Add user", "Remove user" }; return new String[] { "Reply to HLS authentication", "Change HLS secret", "Add object", "Remove object" }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy