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

gurux.dlms.GXDLMSConverter Maven / Gradle / Ivy

There is a newer version: 4.0.72
Show newest version
package gurux.dlms;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import gurux.dlms.asn.enums.KeyUsage;
import gurux.dlms.enums.DataType;
import gurux.dlms.enums.ObjectType;
import gurux.dlms.enums.Standard;
import gurux.dlms.internal.GXCommon;
import gurux.dlms.manufacturersettings.GXObisCode;
import gurux.dlms.objects.GXDLMSObject;
import gurux.dlms.objects.GXDLMSObjectCollection;
import gurux.dlms.objects.enums.CertificateType;

/**
 * DLMS converter is used to get descriptions for the OBIS codes.
 */
public class GXDLMSConverter {
    /**
     * Collection of standard OBIS codes.
     */
    private GXStandardObisCodeCollection codes = new GXStandardObisCodeCollection();

    private Standard standard;

    /**
     * Constructor.
     */
    public GXDLMSConverter() {

    }

    /**
     * Constructor.
     * 
     * @param value
     *            Used standard.
     */
    public GXDLMSConverter(Standard value) {
        standard = value;
    }

    /**
     * Get OBIS code description.
     * 
     * @param logicalName
     *            Logical name (OBIS code).
     * @return Array of descriptions that match given OBIS code.
     */
    public final String[] getDescription(final String logicalName) {
        return getDescription(logicalName, ObjectType.NONE);
    }

    /**
     * Get OBIS code description.
     * 
     * @param logicalName
     *            Logical name (OBIS code).
     * @param description
     *            Description filter.
     * @return Array of descriptions that match given OBIS code.
     */
    public final String[] getDescription(final String logicalName, final String description) {
        return getDescription(logicalName, ObjectType.NONE, description);
    }

    /**
     * Get OBIS code description.
     * 
     * @param logicalName
     *            Logical name (OBIS code).
     * @param type
     *            Object type.
     * @return Array of descriptions that match given OBIS code.
     */
    public final String[] getDescription(final String logicalName, final ObjectType type) {
        return getDescription(logicalName, type, null);
    }

    /**
     * Get OBIS code description.
     * 
     * @param logicalName
     *            Logical name (OBIS code).
     * @param type
     *            Object type.
     * @param description
     *            Description filter.
     * @return Array of descriptions that match given OBIS code.
     */
    public final String[] getDescription(final String logicalName, final ObjectType type,
            final String description) {
        if (codes.isEmpty()) {
            readStandardObisInfo(standard, codes);
        }
        List list = new ArrayList();
        boolean all = logicalName == null || logicalName.isEmpty();
        for (GXStandardObisCode it : codes.find(logicalName, type)) {
            if (description != null && !description.isEmpty()
                    && !it.getDescription().toLowerCase().contains(description.toLowerCase())) {
                continue;
            }
            if (all) {
                list.add("A=" + it.getOBIS()[0] + ", B=" + it.getOBIS()[1] + ", C="
                        + it.getOBIS()[2] + ", D=" + it.getOBIS()[3] + ", E=" + it.getOBIS()[4]
                        + ", F=" + it.getOBIS()[5] + "\r\n" + it.getDescription());
            } else {
                list.add(it.getDescription());
            }
        }
        return list.toArray(new String[list.size()]);
    }

    /**
     * Update OBIS code information.
     * 
     * @param codes
     *            COSEM objects.
     * @param it
     *            COSEM object.
     * @param it
     *            used DLMS standard.
     */
    private static void updateOBISCodeInfo(final GXStandardObisCodeCollection codes,
            final GXDLMSObject it, final Standard standard) {
        String ln = it.getLogicalName();
        GXStandardObisCode[] list = codes.find(ln, it.getObjectType());
        GXStandardObisCode code = list[0];
        if (code != null) {
            if (it.getDescription() == null || it.getDescription().equals("")) {
                it.setDescription(code.getDescription());
            }
            // Update data type from DLMS standard.
            if (standard != Standard.DLMS) {
                GXStandardObisCode d = list[list.length - 1];
                code.setDataType(d.getDataType());
            }
            if (code.getUIDataType() == null) {
                // If string is used
                if (code.getDataType().contains("10")) {
                    code.setUIDataType("10");
                } else if (code.getDataType().contains("25") || code.getDataType().contains("26")) {
                    // If date time is used.
                    code.setUIDataType("25");
                } else if (code.getDataType().contains("9")) {
                    // Time stamps of the billing periods objects (first
                    // scheme
                    // if there are two)
                    if ((GXStandardObisCodeCollection.equalsMask("0.0-64.96.7.10-14.255", ln)
                            // Time stamps of the billing periods objects
                            // (second scheme)
                            || GXStandardObisCodeCollection.equalsMask("0.0-64.0.1.5.0-99,255", ln)
                            // Time of power failure
                            || GXStandardObisCodeCollection.equalsMask("0.0-64.0.1.2.0-99,255", ln)
                            // Time stamps of the billing periods
                            // objects (first
                            // scheme if there are two)
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.1.2.0-99,255", ln)
                            // Time stamps of the billing periods
                            // objects
                            // (second scheme)
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.1.5.0-99,255", ln)
                            // Time expired since last end of
                            // billing
                            // period
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.0.255", ln)
                            // Time of last reset
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.6.255", ln)
                            // Date of last reset
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.7.255", ln)
                            // Time expired since last end of
                            // billing
                            // period
                            // (Second billing period scheme)
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.13.255", ln)
                            // Time of last reset (Second billing
                            // period
                            // scheme)
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.14.255", ln)
                            // Date of last reset (Second billing
                            // period
                            // scheme)
                            || GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.15.255", ln))) {
                        code.setUIDataType("25");
                    } else if (GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.1.255", ln)) {
                        // Local time
                        code.setUIDataType("27");
                    } else if (GXStandardObisCodeCollection.equalsMask("1.0-64.0.9.2.255", ln)) {
                        // Local date
                        code.setUIDataType("26");
                    }
                    // Active firmware identifier
                    else if (GXStandardObisCodeCollection.equalsMask("1.0.0.2.0.255", ln)) {
                        code.setUIDataType("10");
                    }
                }
                // Unix time
                else if (it.getObjectType() == ObjectType.DATA
                        && GXStandardObisCodeCollection.equalsMask("0.0.1.1.0.255", ln)) {
                    code.setUIDataType("25");
                }
            }
            if (!code.getDataType().equals("*") && !code.getDataType().equals("")
                    && !code.getDataType().contains(",")) {
                DataType type = DataType.forValue(Integer.parseInt(code.getDataType()));
                ObjectType objectType = it.getObjectType();
                if (objectType == ObjectType.DATA || objectType == ObjectType.REGISTER
                        || objectType == ObjectType.REGISTER_ACTIVATION
                        || objectType == ObjectType.EXTENDED_REGISTER) {
                    it.setDataType(2, type);
                }
            }
            if (code.getUIDataType() != null && !code.getUIDataType().isEmpty()) {
                DataType type = DataType.forValue(Integer.parseInt(code.getUIDataType()));
                ObjectType objectType = it.getObjectType();
                if (objectType == ObjectType.DATA || objectType == ObjectType.REGISTER
                        || objectType == ObjectType.REGISTER_ACTIVATION
                        || objectType == ObjectType.EXTENDED_REGISTER) {
                    it.setUIDataType(2, type);
                }
            }
        } else {
            Logger.getLogger(GXDLMSConverter.class.getName()).log(Level.INFO,
                    "Unknown OBIS Code: " + it.getLogicalName() + " Type: " + it.getObjectType());
        }
    }

    /**
     * Update standard OBIS codes description and type if defined.
     * 
     * @param object
     *            COSEM object.
     */
    public final void updateOBISCodeInformation(final GXDLMSObject object) {
        synchronized (codes) {
            if (codes.isEmpty()) {
                readStandardObisInfo(standard, codes);
            }
            updateOBISCodeInfo(codes, object, standard);
        }
    }

    /**
     * Update standard OBIS codes descriptions and type if defined.
     * 
     * @param objects
     *            Collection of COSEM objects to update.
     */
    public final void updateOBISCodeInformation(final GXDLMSObjectCollection objects) {
        synchronized (codes) {
            if (codes.isEmpty()) {
                readStandardObisInfo(standard, codes);
            }
            for (GXDLMSObject it : objects) {
                updateOBISCodeInfo(codes, it, standard);
            }
        }
    }

    /**
     * Get country spesific OBIS codes.
     * 
     * @param standard
     *            Used standard.
     * @return Collection for special OBIC codes.
     */
    @SuppressWarnings("squid:S00112")
    static GXObisCode[] getObjects(Standard standard) {
        List codes = new ArrayList();
        InputStream stream = null;
        if (standard == Standard.ITALY) {
            stream = GXDLMSClient.class.getResourceAsStream("/Italy.txt");
        } else if (standard == Standard.INDIA) {
            stream = GXDLMSClient.class.getResourceAsStream("/India.txt");
        } else if (standard == Standard.SAUDI_ARABIA) {
            stream = GXDLMSClient.class.getResourceAsStream("/SaudiArabia.txt");
        } else if (standard == Standard.SPAIN) {
            stream = GXDLMSClient.class.getResourceAsStream("/Spain.txt");
        }
        if (stream == null) {
            return new GXObisCode[0];
        }
        int nRead;
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] data = new byte[1000];
        try {
            while ((nRead = stream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
        String str = buffer.toString();
        str = str.replace("\r", "");
        List rows = GXCommon.split(str, '\n');
        for (String it : rows) {
            // Comments start with #.
            if (!it.startsWith("#")) {
                List items = GXCommon.split(it, ';');
                // Skip empty lines.
                if (items.size() > 1) {
                    ObjectType ot = ObjectType.forValue(Integer.parseInt(items.get(0)));
                    String ln = GXCommon.toLogicalName(GXCommon.logicalNameToBytes(items.get(1)));
                    int version = Integer.parseInt(items.get(2));
                    String desc = items.get(3);
                    GXObisCode code = new GXObisCode(ln, ot, desc);
                    if (items.size() > 4) {
                        code.setUIDataType(items.get(4));
                    }
                    code.setVersion(version);
                    codes.add(code);
                }
            }
        }
        return codes.toArray(new GXObisCode[0]);
    }

    /**
     * Read standard OBIS code information from the file.
     * 
     * @param codes
     *            Collection of standard OBIS codes.
     */
    @SuppressWarnings("squid:S00112")
    private static void readStandardObisInfo(final Standard standard,
            final GXStandardObisCodeCollection codes) {

        if (standard != Standard.DLMS) {
            for (GXObisCode it : getObjects(standard)) {
                GXStandardObisCode tmp = new GXStandardObisCode();
                tmp.setInterfaces(String.valueOf(it.getObjectType().getValue()));
                tmp.setOBIS(GXCommon.split(it.getLogicalName(), '.').toArray(new String[0]));
                tmp.setDescription(it.getDescription());
                tmp.setUIDataType(it.getUIDataType());
                codes.add(tmp);
            }
        }
        InputStream stream = GXDLMSClient.class.getResourceAsStream("/OBISCodes.txt");
        if (stream == null) {
            return;
        }

        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[1000];
        try {
            while ((nRead = stream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
        String str = buffer.toString();
        str = str.replace("\r", "");
        List rows = GXCommon.split(str, '\n');
        for (String it : rows) {
            if (!it.isEmpty()) {
                List items = GXCommon.split(it, ';');
                List obis = GXCommon.split(items.get(0), '.');
                GXStandardObisCode code = new GXStandardObisCode(
                        obis.toArray(new String[0]), items.get(3) + "; " + items.get(4) + "; "
                                + items.get(5) + "; " + items.get(6) + "; " + items.get(7),
                        items.get(1), items.get(2));
                codes.add(code);
            }
        }
    }

    @SuppressWarnings("rawtypes")
    public static Class getDataType(final DataType value) {
        if (value == DataType.NONE) {
            return null;
        }
        if (value == DataType.OCTET_STRING) {
            return byte[].class;
        }
        if (value == DataType.ENUM) {
            return GXEnum.class;
        }
        if (value == DataType.INT8) {
            return Byte.class;
        }
        if (value == DataType.INT16) {
            return Short.class;
        }
        if (value == DataType.INT32) {
            return Integer.class;
        }
        if (value == DataType.INT64) {
            return Long.class;
        }
        if (value == DataType.UINT8) {
            return GXUInt8.class;
        }
        if (value == DataType.UINT16) {
            return GXUInt16.class;
        }
        if (value == DataType.UINT32) {
            return GXUInt32.class;
        }
        if (value == DataType.UINT64) {
            return GXUInt64.class;
        }
        if (value == DataType.TIME) {
            return GXTime.class;
        }
        if (value == DataType.DATE) {
            return GXDate.class;
        }
        if (value == DataType.DATETIME) {
            return GXDateTime.class;
        }
        if (value == DataType.ARRAY) {
            return Object[].class;
        }
        if (value == DataType.STRING) {
            return String.class;
        }
        if (value == DataType.BOOLEAN) {
            return Boolean.class;
        }
        if (value == DataType.FLOAT32) {
            return Float.class;
        }
        if (value == DataType.FLOAT64) {
            return Double.class;
        }
        if (value == DataType.ENUM) {
            return GXEnum.class;
        }
        if (value == DataType.BITSTRING) {
            return GXBitString.class;
        }
        throw new IllegalArgumentException("Invalid value.");
    }

    public static DataType getDLMSDataType(final Object value) {
        if (value == null) {
            return DataType.NONE;
        }
        if (value instanceof byte[]) {
            return DataType.OCTET_STRING;
        }
        if (value instanceof Enum) {
            return DataType.ENUM;
        }
        if (value instanceof Byte) {
            return DataType.INT8;
        }
        if (value instanceof Short) {
            return DataType.INT16;
        }
        if (value instanceof Integer) {
            return DataType.INT32;
        }
        if (value instanceof Long) {
            return DataType.INT64;
        }
        if (value instanceof GXDateTimeOS) {
            return DataType.OCTET_STRING;
        }
        if (value instanceof GXTime) {
            return DataType.TIME;
        }
        if (value instanceof GXDate) {
            return DataType.DATE;
        }
        if (value instanceof java.util.Date || value instanceof GXDateTime) {
            return DataType.DATETIME;
        }
        if (value.getClass().isArray()) {
            return DataType.ARRAY;
        }
        if (value instanceof String) {
            return DataType.STRING;
        }
        if (value instanceof Boolean) {
            return DataType.BOOLEAN;
        }
        if (value instanceof Float) {
            return DataType.FLOAT32;
        }
        if (value instanceof Double) {
            return DataType.FLOAT64;
        }
        if (value instanceof BigInteger) {
            return DataType.UINT64;
        }
        if (value instanceof GXArray) {
            return DataType.ARRAY;
        }
        if (value instanceof GXStructure) {
            return DataType.STRUCTURE;
        }
        if (value instanceof GXBitString) {
            return DataType.BITSTRING;
        }
        if (value instanceof GXEnum) {
            return DataType.ENUM;
        }
        if (value instanceof GXByteBuffer) {
            return DataType.OCTET_STRING;
        }
        if (value instanceof GXUInt8) {
            return DataType.UINT8;
        }
        if (value instanceof GXUInt16) {
            return DataType.UINT16;
        }
        if (value instanceof GXUInt32) {
            return DataType.UINT32;
        }
        if (value instanceof GXUInt64) {
            return DataType.UINT64;
        }
        throw new IllegalArgumentException("Invalid value.");
    }

    /**
     * Change value type.
     * 
     * @param value
     *            Value to converted.
     * @param type
     *            Data type.
     * @return Converted value.
     */
    public static Object changeType(final Object value, final DataType type) {
        if (getDLMSDataType(value) == type) {
            return value;
        }
        switch (type) {
        case ARRAY:
            throw new IllegalArgumentException("Can't change array types.");
        case BCD:
            break;
        case BOOLEAN:
            if (value instanceof String) {
                return Boolean.parseBoolean((String) value);
            }
            return ((Number) value).longValue() != 0;
        case COMPACT_ARRAY:
            throw new IllegalArgumentException("Can't change compact array types.");
        case DATE:
            return new GXDate((String) value);
        case DATETIME:
            return new GXDateTime((String) value);
        case ENUM:
            if (value instanceof String) {
                return new GXEnum(Short.parseShort((String) value));
            }
            return new GXEnum((byte) value);
        case FLOAT32:
            if (value instanceof String) {
                try {
                    return Float.parseFloat((String) value);
                } catch (NumberFormatException e) {
                    return Float.parseFloat(((String) value).replace(",", "."));
                }
            }
            return ((Number) value).floatValue();
        case FLOAT64:
            if (value instanceof String) {
                try {
                    return Double.parseDouble((String) value);
                } catch (NumberFormatException e) {
                    return Double.parseDouble(((String) value).replace(",", "."));
                }
            }
            return ((Number) value).doubleValue();
        case INT16:
            if (value instanceof String) {
                return Short.parseShort((String) value);
            }
            return ((Number) value).shortValue();
        case INT32:
            if (value instanceof String) {
                return Integer.parseInt((String) value);
            }
            return ((Number) value).intValue();
        case INT64:
            if (value instanceof String) {
                return Long.parseLong((String) value);
            }
            return ((Number) value).longValue();
        case INT8:
            if (value instanceof String) {
                return Byte.parseByte((String) value);
            }
            return (char) ((Number) value).byteValue();
        case NONE:
            return null;
        case OCTET_STRING:
            if (value instanceof String) {
                return GXCommon.hexToBytes((String) value);
            }
            throw new IllegalArgumentException("Can't change octet string type.");
        case STRING:
            return String.valueOf(value);
        case BITSTRING:
            return new GXBitString((String) value);
        case STRING_UTF8:
            return String.valueOf(value);
        case STRUCTURE:
            throw new IllegalArgumentException("Can't change structure types.");
        case TIME:
            return new GXTime((String) value);
        case UINT8:
            if (value instanceof String) {
                return new GXUInt8(Short.parseShort((String) value));
            }
            return new GXUInt8(((Number) value).shortValue());
        case UINT16:
            if (value instanceof String) {
                return new GXUInt16(Integer.parseInt((String) value));
            }
            return new GXUInt16(((Number) value).intValue());
        case UINT32:
            if (value instanceof String) {
                return new GXUInt32(Long.parseLong((String) value));
            }
            return new GXUInt32(((Number) value).longValue());
        case UINT64:
            if (value instanceof String) {
                return BigInteger.valueOf(Long.parseLong((String) value));
            }
            return BigInteger.valueOf(((Number) value).longValue());
        default:
            break;
        }
        throw new IllegalArgumentException("Invalid data type: " + type.toString());
    }

    /**
     * Convert system title to string.
     * 
     * @param standard
     *            Used standard.
     * @param st
     *            System title.
     * @param addComments
     *            Are comments added.
     * @return System title in string format.
     */
    public static String systemTitleToString(final Standard standard, final byte[] st,
            final boolean addComments) {
        return GXCommon.systemTitleToString(standard, st, addComments);
    }

    /**
     * Convert key usage to certificate type.
     * 
     * @param value
     *            Key usage
     * @return Certificate type.
     */
    public static CertificateType keyUsageToCertificateType(final Set value) {
        if (value.contains(KeyUsage.DIGITAL_SIGNATURE) && value.contains(KeyUsage.KEY_AGREEMENT)) {
            return CertificateType.TLS;
        } else if (value.contains(KeyUsage.DIGITAL_SIGNATURE)) {
            return CertificateType.DIGITAL_SIGNATURE;
        } else if (value.contains(KeyUsage.KEY_AGREEMENT)) {
            return CertificateType.KEY_AGREEMENT;
        }
        throw new IllegalArgumentException("Unknown certificate type.");
    }

    /**
     * Convert key usage to certificate type.
     * 
     * @param value
     *            Key usage
     * @return Certificate type.
     */
    public static Set certificateTypeToKeyUsage(final CertificateType value) {
        Set ret = new HashSet();
        switch (value) {
        case DIGITAL_SIGNATURE:
            ret.add(KeyUsage.DIGITAL_SIGNATURE);
            break;
        case KEY_AGREEMENT:
            ret.add(KeyUsage.KEY_AGREEMENT);
            break;
        case TLS:
            ret.add(KeyUsage.DIGITAL_SIGNATURE);
            ret.add(KeyUsage.KEY_AGREEMENT);
            break;
        default:
            throw new IllegalArgumentException();
        }
        return ret;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy