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

at.yawk.dbus.protocol.DbusAddress Maven / Gradle / Ivy

The newest version!
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package at.yawk.dbus.protocol;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.*;
import lombok.Value;

/**
 * @author yawkat
 */
@Value
public class DbusAddress {
    private static final byte[] UNESCAPED_CHARS;

    static {
        UNESCAPED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/.\\"
                .getBytes(StandardCharsets.US_ASCII);
        Arrays.sort(UNESCAPED_CHARS);
    }

    private final String protocol;
    private final Map properties;

    private static boolean mustEscape(byte b) {
        return Arrays.binarySearch(UNESCAPED_CHARS, b) < 0;
    }

    public static Builder builder(String protocol) {
        return new Builder(protocol);
    }

    public static DbusAddress fromUnixSocket(Path location) {
        return builder("unix")
                .property("path", location.toString())
                .build();
    }

    public static DbusAddress fromTcpAddress(InetSocketAddress address) {
        return builder("tcp")
                .property("host", address.getHostString())
                .property("port", Integer.toString(address.getPort()))
                .build();
    }

    public static DbusAddress parse(String repr) {
        int protocolPart = repr.indexOf(':');

        String protocol = repr.substring(0, protocolPart);
        Map properties = new LinkedHashMap<>();

        int i = protocolPart + 1;
        while (true) {
            int valueSep = repr.indexOf('=', i);
            String key = repr.substring(i, valueSep);
            i = valueSep + 1;
            int entrySep = repr.indexOf(',', i);
            String value = repr.substring(i, entrySep == -1 ? repr.length() : entrySep);
            properties.put(unescape(key), unescape(value));

            if (entrySep == -1) { break; }
            i = entrySep + 1;
        }

        return new DbusAddress(protocol, properties);
    }

    public boolean hasProperty(String key) {
        return properties.containsKey(key);
    }

    public String getProperty(String key) {
        String value = properties.get(key);
        if (value == null) { throw new NoSuchElementException(key); }
        return value;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder()
                .append(protocol).append(':');
        properties.forEach((k, v) -> builder.append(escape(k)).append('=').append(escape(v)).append(','));
        if (!properties.isEmpty()) {
            // remove trailing ,
            builder.setLength(builder.length() - 1);
        }
        return builder.toString();
    }

    static String unescape(String s) {
        byte[] bytes = s.getBytes(StandardCharsets.US_ASCII);
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            byte b = bytes[i];
            if (b == '%') {
                String code = "" + (char) bytes[++i] + (char) bytes[++i];
                builder.append((char) Integer.parseInt(code, 16));
            } else {
                builder.append((char) b);
            }
        }
        return builder.toString();
    }

    static String escape(String s) {
        byte[] bytes = s.getBytes(StandardCharsets.US_ASCII);
        StringBuilder builder = new StringBuilder();
        for (byte b : bytes) {
            if (mustEscape(b)) {
                builder.append('%');
                if ((b & 0xff) < 0x10) { builder.append('0'); }
                builder.append(Integer.toHexString(b & 0xff));
            } else {
                builder.append((char) b);
            }
        }
        return builder.toString();
    }

    public static class Builder {
        private final String protocol;
        private final Map properties = new HashMap<>();

        Builder(String protocol) {
            this.protocol = protocol;
        }

        public Builder property(String key, String value) {
            properties.put(key, value);
            return this;
        }

        public DbusAddress build() {
            return new DbusAddress(protocol, properties);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy