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

com.paremus.dosgi.net.config.ProtocolScheme Maven / Gradle / Ivy

Go to download

An implementation of OSGi Remote Service Admin, enhanced to provide support for OSGi Promises and streaming using OSGi PushStreams.

The newest version!
/*-
 * #%L
 * com.paremus.dosgi.net
 * %%
 * Copyright (C) 2016 - 2019 Paremus Ltd
 * %%
 * Licensed under the Fair Source License, Version 0.9 (the "License");
 * 
 * See the NOTICE.txt file distributed with this work for additional 
 * information regarding copyright ownership. You may not use this file 
 * except in compliance with the License. For usage restrictions see the 
 * LICENSE.txt file distributed with this work
 * #L%
 */
package com.paremus.dosgi.net.config;

import static java.lang.String.format;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ProtocolScheme {
	
	private static final Logger LOG = LoggerFactory.getLogger(ProtocolScheme.class);
	
	private final Pattern COLON = Pattern.compile(":");
	
	private final Protocol protocol;
	
	private final int receiveBufferSize;
	
	private final int sendBufferSize;

	private final InetSocketAddress bindAddress;
	
	private final Map toAdvertise = new LinkedHashMap<>();
	
	private final Map specificSocketOptions = new HashMap();

	private final String configuration;
	
	public ProtocolScheme(String spec) {
		this.configuration = spec;
		
		String[] stanzas = spec.split(";");
		
		protocol = Protocol.valueOf(stanzas[0]);
		
		int portDef = 0;
		int rcvBuf = 1 << 18;
		int sendBuf = 1 << 18;
		InetSocketAddress bindAddress = null;
		
		for(int i = 1; i < stanzas.length; i++) {
			String[] stanza = stanzas[i].split("=",2);
			switch(stanza[0]) {
				case "port" :
					portDef = Integer.valueOf(stanza[1]);
					if(portDef < 0 || portDef > 65535)  {
						throw new IllegalArgumentException("" + portDef + " is not a valid port number");
					}
					continue;
				case "bind" :
					try {
						bindAddress = handleAddress(spec, stanza[1]);
						InetAddress address = bindAddress.getAddress();
						if(NetworkInterface.getByInetAddress(address) == null && 
								!address.isAnyLocalAddress()) {
							throw new IllegalArgumentException("The bind address " + 
									stanza[1] + " is not local to this machine.");
						}
					} catch (Exception e) {
						throw new IllegalArgumentException("Unable to bind to the address " + stanza[1], e);
					}
					continue;
				case "advertise" :
					InetSocketAddress isa = handleAddress(spec, stanza[1]);
					toAdvertise.put(isa.getHostString(), isa.getPort());
					continue;
				default:
					specificSocketOptions.put(stanza[0], stanza[1]);
			}
		}
		
		receiveBufferSize = rcvBuf;
		sendBufferSize = sendBuf;
		this.bindAddress = bindAddress;
	}

	private InetSocketAddress handleAddress(String spec, String value) {
		
		int portDelimiter = value.lastIndexOf(':');
		
		Matcher colonCounter = COLON.matcher(value);
		
		boolean hasMultipleColons = colonCounter.find() && colonCounter.find();
		
		boolean hasPort;
		if(value.startsWith("[") ) {
			// IPv6
			int endOfAddress = value.lastIndexOf(']');
			hasPort = portDelimiter > endOfAddress;
		} else if(hasMultipleColons) {
			LOG.warn("The protocol definition {} contains an address {} which uses IPV6 notation but is not surrounded by \"[]\". No port information can be detected using this syntax and it should be avoided.", spec, value);
			hasPort = false;
		} else {
			hasPort = portDelimiter > 0;
		}
		
		try {
			int port;
			String address;
			if(hasPort) {
				port = Integer.parseInt(value.substring(portDelimiter + 1));
				if(port < 0 || port > 65535)  {
					LOG.error("The protocol definition {} contains an address {} which declares an invalid port", spec, value);
					throw new IllegalArgumentException("The " + port + " is not a valid port number");
				}
				address = value.substring(0, portDelimiter);
			} else {
				port = 0;
				address = value;
			}
			
			// Check for valid syntax when creating
			return new InetSocketAddress(InetAddress.getByName(address), port);
		} catch (Exception e) {
			throw new RuntimeException("The protocol specification " + spec + " contains an invalid clause " + value);
		}
	}

	public Protocol getProtocol() {
		return protocol;
	}

	public int getSendBufferSize() {
		return sendBufferSize;
	}
	
	public InetSocketAddress getBindAddress() {
		return bindAddress;
	}

	public Map getAddressesToAdvertise() {
		return new LinkedHashMap<>(toAdvertise);
	}

	public int getReceiveBufferSize() {
		return receiveBufferSize;
	}

	@SuppressWarnings("unchecked")
	public  T getOption(String option, Class clazz) {
		
		String value = specificSocketOptions.get(option);
		if(value == null) {
			return null;
		} else if(clazz.isInstance(value)) {
			return clazz.cast(value);
		} else {
			try {
				Method m = clazz.getMethod("valueOf", String.class);
				if(Modifier.isStatic(m.getModifiers())) {
					return (T) m.invoke(null, value);
				}
			} catch (NoSuchMethodException nsme) {
				//Look for a constructor instead
			} catch (Exception e) {
				throw new RuntimeException(
						format("Unable to convert the property value {} for option {}", value, option), e);
			}
			try {
				Constructor c = clazz.getConstructor(String.class);
				return c.newInstance(value);
			} catch (Exception e) {
				throw new RuntimeException(
						format("Unable to convert the property value {} for option {}", value, option), e);
			}
		}
	}

	public String getConfigurationString() {
		return configuration;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy