ROS source code learning VIII. Response

2021SC@SDUSC

catalogue

1, Write in front

2, StatusCode

3, Response

4, ResultFactory

1, Write in front

        In the previous article, we mainly analyzed various logic of the server. Before analyzing the code of the client, this chapter and the next two to three chapters will serve as a connecting part, focusing on various bridges and protocols for communication between the analysis server and client users. After a clear understanding of these parts, We will have a clearer understanding of the communication mechanism and strategy when facing the client code in the future

2, StatusCode

        The purpose of building a communication system for ROS is to provide a bridge between process call and information exchange for each node. Whether the process call is successful or not and whether the information request is effective need a flag. The StatusCode introduced next is generated for this purpose

public enum StatusCode {
  ERROR(-1), FAILURE(0), SUCCESS(1);

  private final int intValue;

  private StatusCode(int value) {
    this.intValue = value;
  }

  public int toInt() {
    return intValue;
  }

  public static StatusCode fromInt(int intValue) {
    switch (intValue) {
    case -1:
      return ERROR;
    case 1:
      return SUCCESS;
    case 0:
    default:
      return FAILURE;
    }
  }
  
  @Override
  public String toString() {
    switch (this) {
      case ERROR:
        return "Error";
      case SUCCESS:
        return "Success";
      case FAILURE:
      default:
        return "Failure";
    }
  }
}

        StatusCode is an enumeration class with three values: ERROR, FAILURE and SUCCESS. The static method fromInt in StatusCode receives an integer value, and then returns an enumeration value according to the corresponding relationship between the enumeration value and the integer value. The toString method returns a corresponding integer value according to the enumeration value

3, Response

        Response is a class used to encapsulate and transfer information between ROS nodes. It contains three data members: statusCode, statusMessage and result, representing status value, status information and result information respectively

        

  public static <T> Response<T> newError(String message, T value) {
    return new Response<T>(StatusCode.ERROR, message, value);
  }

  public static <T> Response<T> newFailure(String message, T value) {
    return new Response<T>(StatusCode.FAILURE, message, value);
  }

  public static <T> Response<T> newSuccess(String message, T value) {
    return new Response<T>(StatusCode.SUCCESS, message, value);
  }

        The Response class provides three static methods to quickly generate a Response object. According to the types of Response status values, they are newError,newFailure and newSuccess. The parameters received by these three methods are String representing status information and generic value representing result value, After receiving the parameter, use the new keyword to create a Response object with a status value consistent with the called method and return it

        

  public Response(int statusCode, String statusMessage, T value) {
    this(StatusCode.fromInt(statusCode), statusMessage, value);
  }

  public Response(StatusCode statusCode, String statusMessage, T value) {
    this.statusCode = statusCode;
    this.statusMessage = statusMessage;
    this.result = value;
  }

        The constructor of Response can accept either a statusCode value of an enumeration class or an integer value and convert it to an enumeration value

                

public List<Object> toList() {
    return Lists.newArrayList(statusCode.toInt(), statusMessage, result == null ? "null" : result);
  } 

public static <T> Response<T> fromListCheckedFailure(List<Object> response,
      ResultFactory<T> resultFactory) throws RemoteException {
    StatusCode statusCode;
    String message;
    try {
      statusCode = StatusCode.fromInt((Integer) response.get(0));
      message = (String) response.get(1);
      if (statusCode == StatusCode.FAILURE) {
        throw new RemoteException(statusCode, message);
      }

    } catch (ClassCastException e) {
      throw new RosRuntimeException(
          "Remote side did not return correct type (status code/message).", e);
    }
    try {
      return new Response<T>(statusCode, message, resultFactory.newFromValue(response.get(2)));
    } catch (ClassCastException e) {
      throw new RosRuntimeException("Remote side did not return correct value type.", e);
    }
  }


public static <T> Response<T> fromListChecked(List<Object> response,
      ResultFactory<T> resultFactory) throws RemoteException {
    StatusCode statusCode;
    String message;
    try {
      statusCode = StatusCode.fromInt((Integer) response.get(0));
      message = (String) response.get(1);
      if (statusCode != StatusCode.SUCCESS) {
        throw new RemoteException(statusCode, message);
      }
    } catch (ClassCastException e) {
      throw new RosRuntimeException(
          "Remote side did not return correct type (status code/message).", e);
    }
    try {
      return new Response<T>(statusCode, message, resultFactory.newFromValue(response.get(2)));
    } catch (ClassCastException e) {
      throw new RosRuntimeException("Remote side did not return correct value type.", e);
    }
  }

  public Response(int statusCode, String statusMessage, T value) {
    this(StatusCode.fromInt(statusCode), statusMessage, value);
  }

  public Response(StatusCode statusCode, String statusMessage, T value) {
    this.statusCode = statusCode;
    this.statusMessage = statusMessage;
    this.result = value;
  }

        The next set of methods is the. toList method used to convert the Response instance object and the ArrayList object into each other. The contents of the Response are converted into ArrayList format. The index values from 0 to 2 correspond to the integer representation, status information and result information of the status value statusCode (if the result is empty, use the string "null" instead)

        The fromListCheckedFailure method receives a Response object in list form and a resultfactory instance object as parameters. The method first obtains the integer status value at index 0 and converts it into an enumeration value, obtains the status information at index 1 and stores it in the local variable message, and then determines whether the status value is FAILURE (i.e. FAILURE), If true, a remote execution exception will be thrown with FAILURE information. If not, it will be converted into a Response class object according to the corresponding information between the list and Response. The conversion of the result value is obtained through the newFromValue method of the incoming resultfactory object. If a type conversion exception occurs during the whole conversion process, a RosRuntimeException will be thrown

        fromListChecked also receives a Response object in the form of a list and a ResultFactory instance object as parameters. Different from the previous method, fromListCheckedFailure only checks whether it fails. If it fails, an exception will be thrown. This method will throw an exception for both failure and error

4, ResultFactory

        In the process of converting the returned information in the list form into the Response instance Object, because the type of the result member of the Response itself is determined, and the result member of the returned value in the list form is an Object class Object, the type of the result needs to be converted in the conversion process, and the ResultFactory is officially generated for this purpose

        ResultFactory is an interface. To implement this interface, you need to implement its newFromValue method, which is used to convert Object class objects into other objects. The ResultFactory interface and its implementation classes are as follows

        

public interface ResultFactory<T> {

  public T newFromValue(Object value);
}

public class BooleanResultFactory implements ResultFactory<Boolean> {
  
  @Override
  public Boolean newFromValue(Object value) {
    return (Boolean) value;
  }
}

public class IntegerResultFactory implements ResultFactory<Integer> {
  
  @Override
  public Integer newFromValue(Object value) {
    return (Integer) value;
  }
}

public class ObjectResultFactory implements ResultFactory<Object> {

  @Override
  public Object newFromValue(Object value) {
    return value;
  }
}

public class StringResultFactory implements ResultFactory<String> {
  
  @Override
  public String newFromValue(Object value) {
    return (String) value;
  }
}

public class VoidResultFactory implements ResultFactory<Void> {
  
  @Override
  public Void newFromValue(Object value) {
    return null;
  }
}

public class UriResultFactory implements ResultFactory<URI> {

  @Override
  public URI newFromValue(Object value) {
    try {
      return new URI((String) value);
    } catch (URISyntaxException e) {
      throw new RosRuntimeException(e);
    }
  }
}

        The above codes are interfaces and partial implementation classes. These implementation classes simply perform forced type conversion to obtain the target data

public class StringListResultFactory implements ResultFactory<List<String>> {

  @Override
  public List<String> newFromValue(Object value) {
    List<String> strings = Lists.newArrayList();
    List<Object> objects = Arrays.asList((Object[]) value);
    for (Object topic : objects) {
      strings.add((String) topic);
    }
    return strings;
  }
}



public class UriListResultFactory implements ResultFactory<List<URI>> {

	@Override
	public List<URI> newFromValue(Object value) {
		List<Object> values = Arrays.asList((Object[]) value);
		List<URI> uris = Lists.newArrayList();
		for (Object uri : values) {
			try {
				uris.add(new URI((String) uri));
			} catch (URISyntaxException e) {
				throw new RosRuntimeException(e);
			}
		}
		return uris;
	}
}

public class TopicTypeListResultFactory implements
		ResultFactory<List<TopicType>> {

	@Override
	public List<TopicType> newFromValue(Object value) {
		List<TopicType> topics = Lists.newArrayList();

		for (Object pair : (Object[]) value) {
			topics.add(new TopicType((String) ((Object[]) pair)[0],
					(String) ((Object[]) pair)[1]));
		}

		return topics;
	}

}

public class TopicListResultFactory implements ResultFactory<List<TopicDeclaration>> {

  @Override
  public List<TopicDeclaration> newFromValue(Object value) {
    List<TopicDeclaration> descriptions = Lists.newArrayList();
    List<Object> topics = Arrays.asList((Object[]) value);
    for (Object topic : topics) {
      String name = (String) ((Object[]) topic)[0];
      String type = (String) ((Object[]) topic)[1];
      descriptions.add(TopicDeclaration.newFromTopicName(GraphName.of(name), new TopicDescription(type, null,
          null), null));
    }
    return descriptions;
  }
}

        The above code is the method of converting Object class to complex class Object

        The corresponding method in the StringListResultFactory class first converts the Object to Object [], then traverses the Object array, converts each Object object into a String, puts it into the array, and returns

        The corresponding method in the TopicListResultFactory class first converts the Object into Object [], then traverses the Object array, and converts each Object object into Object [], and then takes the first item into String as the topic name, and the second item into String as the topic message format, then encapsulates it into TopicDeclaration format and stores it in the list, and returns the list after traversal

        UriListResultFactory and TopicTypeListFactory are similar to the above implementation class logic. They both perform type conversion by parsing Object objects into nested lists

        

public class SystemStateResultFactory implements ResultFactory<SystemState> {

	@Override
	public SystemState newFromValue(Object value) {
		Object[] vals = (Object[]) value;

		Map<String, Set<String>> publisherMap = getPublishers(vals[0]);
		Map<String, Set<String>> subscriberMap = getSubscribers(vals[1]);

		Map<String, TopicSystemState> topics = Maps.newHashMap();

		for (Entry<String, Set<String>> publisherData : publisherMap.entrySet()) {
			String topicName = publisherData.getKey();

			Set<String> subscriberNodes = subscriberMap.remove(topicName);

			
			if (subscriberNodes == null) {
				subscriberNodes = Sets.newHashSet();
			}

			topics.put(topicName,
					new TopicSystemState(topicName, publisherData.getValue(),
							subscriberNodes));
		}

		for (Entry<String, Set<String>> subscriberData : subscriberMap
				.entrySet()) {
			// At this point there are no publishers with the same topic name
			HashSet<String> noPublishers = Sets.newHashSet();
			String topicName = subscriberData.getKey();
			topics.put(topicName, new TopicSystemState(topicName,
					noPublishers, subscriberData.getValue()));
		}

		
		return new SystemState(topics.values());
	}

                      This class resolves the Object object into a SystemState Object. The so-called SystemState refers to various Service and topic information existing in the current system, but this method only needs to return topic information

                        First, transform the Object class into Object [], then pass the first Object object in the list into getPublisher method to obtain a hash table with key as topic name and value as publisher name collection, and pass the second Object object in the list into getSubscriber method to obtain a hash table with key as topic name and value as subscriber name collection, The specific logic of the method to obtain both is similar to the above method

                        After obtaining two hash tables, traverse the two hash tables and restore the key values of the hash table to a group of TopicSystemState objects. The specific method is to use the topic name when traversing the publisher map, and instantiate the TopicSystemState object with the publisher set and the empty subscriber set, Then, when traversing the subscriber map, use the subscriber set to fill the empty subscriber set under the corresponding topic. After creation, use the SystemState object to encapsulate the TopicSystemState object list and return it

Keywords: Java Machine Learning Autonomous vehicles

Added by jwstockwell on Sun, 21 Nov 2021 11:10:10 +0200