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

org.eclipse.californium.cli.ClientConfig Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2020 Bosch.IO GmbH and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 * 
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *    http://www.eclipse.org/org/documents/edl-v10.html.
 * 
 * Contributors:
 *    Bosch.IO GmbH - initial creation
 ******************************************************************************/
package org.eclipse.californium.cli;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Random;

import javax.crypto.SecretKey;

import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.CoAP.Type;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.elements.util.StringUtil;

import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.INegatableOptionTransformer;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;

/**
 * Client command line configuration.
 * 
 * @since 2.3
 */
public class ClientConfig extends ClientBaseConfig {

	/**
	 * Content type.
	 */
	@ArgGroup(exclusive = true)
	public ContentType contentType;

	public static class ContentType {

		/**
		 * Use JSON.
		 */
		@Option(names = "--json", description = "use json payload.")
		public boolean json;

		/**
		 * Use CBOR.
		 */
		@Option(names = "--cbor", description = "use cbor payload.")
		public boolean cbor;

		/**
		 * Use XML.
		 */
		@Option(names = "--xml", description = "use xml payload.")
		public boolean xml;

		/**
		 * Use plain-text.
		 */
		@Option(names = "--text", description = "use plain-text payload.")
		public boolean text;

		/**
		 * Use octet-stream.
		 */
		@Option(names = "--octets", description = "use octet stream payload.")
		public boolean octets;

		/**
		 * Use type from {@link MediaTypeRegistry#parse(String)}.
		 */
		@Option(names = "--ctype", paramLabel = "TYPE", description = "use content type for payload.")
		public String type;

		/**
		 * Numerical value of content type.
		 * 
		 * @see MediaTypeRegistry
		 */
		public int contentType;

		public void defaults() {
			if (type != null) {
				contentType = MediaTypeRegistry.parse(type);
			} else if (text) {
				contentType = MediaTypeRegistry.TEXT_PLAIN;
			} else if (json) {
				contentType = MediaTypeRegistry.APPLICATION_JSON;
			} else if (cbor) {
				contentType = MediaTypeRegistry.APPLICATION_CBOR;
			} else if (xml) {
				contentType = MediaTypeRegistry.APPLICATION_XML;
			} else if (octets) {
				contentType = MediaTypeRegistry.APPLICATION_OCTET_STREAM;
			}
		}
	}

	/**
	 * Payload.
	 */
	@ArgGroup(exclusive = true)
	public Payload payload;

	public static class Payload {

		/**
		 * Payload as text (utf8).
		 */
		@Option(names = "--payload", description = "payload, utf8")
		public String text;

		/**
		 * Payload hexadecimal.
		 */
		@Option(names = "--payloadhex", description = "payload, hexadecimal")
		public String hex;

		/**
		 * Payload base64.
		 */
		@Option(names = "--payload64", description = "payload, base64")
		public String base64;

		/**
		 * Random payload size.
		 * 
		 * @since 3.0
		 */
		@Option(names = "--payload-random", description = "random payload size")
		public Integer size;

		/**
		 * Payload from file.
		 * 
		 * @since 2.4
		 */
		@Option(names = "--payload-file", description = "payload from file")
		public String filename;

		/**
		 * Payload in bytes.
		 * 
		 * (Moved from {@link ClientConfig}.)
		 * 
		 * @since 3.0
		 */
		public byte[] payloadBytes;

		/**
		 * Setup payload defaults.
		 * 
		 * (Moved from {@link ClientConfig}.)
		 * 
		 * @param max maximum supported payload size
		 * @since 3.0
		 */
		public void defaults(int max) {
			if (payloadBytes == null) {
				if (text != null) {
					payloadBytes = text.getBytes();
				} else if (hex != null) {
					payloadBytes = StringUtil.hex2ByteArray(hex);
				} else if (base64 != null) {
					payloadBytes = StringUtil.base64ToByteArray(base64);
				} else if (size != null) {
					if (size <= max) {
						Random rand = new Random();
						payloadBytes = new byte[(int) size];
						for (int index=0; index < size; ++index) {
							payloadBytes[index] = (byte)(' ' + rand.nextInt(127 - ' '));
						}
					} else {
						LOGGER.error("Random payload with {} bytes is too large! (Maximum {} bytes.)", size, max);
					}
				} else if (filename != null) {
					File file = new File(filename);
					if (file.canRead()) {
						long length = file.length();
						if (length <= max) {
							payloadBytes = new byte[(int)length];
							InputStream in = null;
							try {
								in = new FileInputStream(file);
								int len = in.read(payloadBytes);
								if (len != length) {
									LOGGER.error("file {} with {} bytes, read {} bytes!", file, length, len);
								}
							} catch (FileNotFoundException e) {
								LOGGER.error("Missing file {}", file, e);
							} catch (IOException e) {
								LOGGER.error("Error reading file {}", file, e);
							} finally {
								if (in != null) {
									try {
										in.close();
									} catch (IOException e) {
										LOGGER.error("Error closing file {}", file, e);
									}
								}
							}
						} else {
							LOGGER.error("file {} with {} bytes is too large! (Maximum {} bytes.)", file, length, max);
						}
					} else {
						LOGGER.error("Can not read file {} ({})", file, file.getAbsolutePath());
					}
				}
			}
		}
	}

	/**
	 * Apply {@link String#format(String, Object...)} to payload. The used
	 * parameter depends on the client implementation.
	 * 
	 * @since 2.4
	 */
	@Option(names = "--payload-format", description = "apply format to payload.")
	public boolean payloadFormat;

	/**
	 * Message type.
	 * 
	 * @since 2.5
	 */
	@ArgGroup(exclusive = true)
	public MessageType messageType;

	public static class MessageType {

		/**
		 * Request type. {@code true} for {@link Type#CON}.
		 */
		@Option(names = "--con", description = "send request confirmed.")
		public boolean con;
		/**
		 * Request type. {@code true} for {@link Type#NON}.
		 */
		@Option(names = "--non", description = "send request non-confirmed.")
		public boolean non;
	}

	/**
	 * Request method.
	 */
	@Option(names = { "-m", "--method" }, description = "use method. GET|PUT|POST|DELETE|FETCH|PATCH|IPATCH.")
	public CoAP.Code method;

	@Override
	public void register(CommandLine cmd) {
		super.register(cmd);
		cmd.setNegatableOptionTransformer(messageTypeTransformer);
	}

	@Override
	public void defaults() {
		super.defaults();
		if (contentType != null) {
			contentType.defaults();
		}
		if (payload != null) {
			int max = configuration.get(CoapConfig.MAX_RESOURCE_BODY_SIZE);
			payload.defaults(max);
		}
	}

	@Override
	public ClientConfig create() {
		return (ClientConfig) super.create();
	}

	@Override
	public ClientConfig create(String id, SecretKey secret) {
		return (ClientConfig) super.create(id, secret);
	}

	@Override
	public ClientConfig create(PrivateKey privateKey, PublicKey publicKey) {
		return (ClientConfig) super.create(privateKey, publicKey);
	}

	/**
	 * Negatable transformer. Transforms "--con" to "-non".
	 */
	public static INegatableOptionTransformer messageTypeTransformer = new INegatableOptionTransformer() {

		private INegatableOptionTransformer delegate = CommandLine.RegexTransformer.createDefault();

		@Override
		public String makeNegative(String optionName, CommandSpec cmd) {
			if ("--con".equals(optionName)) {
				return "--non";
			} else {
				return delegate.makeNegative(optionName, cmd);
			}
		}

		@Override
		public String makeSynopsis(String optionName, CommandSpec cmd) {
			if ("--con".equals(optionName)) {
				return "(--con|--non)";
			} else {
				return delegate.makeSynopsis(optionName, cmd);
			}
		}

	};
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy