/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.ros.internal.message; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import org.apache.commons.lang.StringEscapeUtils; import org.ros.exception.RosRuntimeException; import org.ros.internal.message.context.MessageContext; import org.ros.internal.message.context.MessageContextProvider; import org.ros.internal.message.field.Field; import org.ros.internal.message.field.FieldType; import org.ros.internal.message.field.MessageFields; import org.ros.internal.message.field.PrimitiveFieldType; import org.ros.message.MessageDeclaration; import org.ros.message.MessageFactory; import java.util.Set; /** * @author damonkohler@google.com (Damon Kohler) */ public class MessageInterfaceBuilder { private MessageDeclaration messageDeclaration; private String packageName; private String interfaceName; private boolean addConstantsAndMethods; private String nestedContent; // TODO(damonkohler): Upgrade Apache Commons Lang. See // https://issues.apache.org/jira/browse/LANG-437 private static String escapeJava(String str) { return StringEscapeUtils.escapeJava(str).replace("\\/", "/").replace("'", "\\'"); } public MessageDeclaration getMessageDeclaration() { return messageDeclaration; } public MessageInterfaceBuilder setMessageDeclaration(MessageDeclaration messageDeclaration) { Preconditions.checkNotNull(messageDeclaration); this.messageDeclaration = messageDeclaration; return this; } public String getPackageName() { return packageName; } /** * @param packageName * the package name of the interface or {@code null} if no package * name should be specified * @return this {@link MessageInterfaceBuilder} */ public MessageInterfaceBuilder setPackageName(String packageName) { this.packageName = packageName; return this; } public String getInterfaceName() { return interfaceName; } public MessageInterfaceBuilder setInterfaceName(String interfaceName) { Preconditions.checkNotNull(interfaceName); this.interfaceName = interfaceName; return this; } public boolean getAddConstantsAndMethods() { return addConstantsAndMethods; } public void setAddConstantsAndMethods(boolean enabled) { addConstantsAndMethods = enabled; } public String getNestedContent() { return nestedContent; } public void setNestedContent(String nestedContent) { this.nestedContent = nestedContent; } public String build(MessageFactory messageFactory) { Preconditions.checkNotNull(messageDeclaration); Preconditions.checkNotNull(interfaceName); StringBuilder builder = new StringBuilder(); if (packageName != null) { builder.append(String.format("package %s;\n\n", packageName)); } builder.append(String.format( "public interface %s extends org.ros.internal.message.Message {\n", interfaceName)); builder.append(String.format(" static final java.lang.String _TYPE = \"%s\";\n", messageDeclaration.getType())); builder.append(String.format(" static final java.lang.String _DEFINITION = \"%s\";\n", escapeJava(messageDeclaration.getDefinition()))); if (addConstantsAndMethods) { MessageContextProvider messageContextProvider = new MessageContextProvider(messageFactory); MessageContext messageContext = messageContextProvider.get(messageDeclaration); appendConstants(messageContext, builder); appendSettersAndGetters(messageContext, builder); } if (nestedContent != null) { builder.append("\n"); builder.append(nestedContent); } builder.append("}\n"); return builder.toString(); } @SuppressWarnings("deprecation") private String getJavaValue(PrimitiveFieldType primitiveFieldType, String value) { switch (primitiveFieldType) { case BOOL: return Boolean.valueOf(!value.equals("0") && !value.equals("false")).toString(); case FLOAT32: return value + "f"; case STRING: return "\"" + escapeJava(value) + "\""; case BYTE: case CHAR: case INT8: case UINT8: case INT16: case UINT16: case INT32: case UINT32: case INT64: case UINT64: case FLOAT64: return value; default: throw new RosRuntimeException("Unsupported PrimitiveFieldType: " + primitiveFieldType); } } private void appendConstants(MessageContext messageContext, StringBuilder builder) { MessageFields messageFields = new MessageFields(messageContext); for (Field field : messageFields.getFields()) { if (field.isConstant()) { Preconditions.checkState(field.getType() instanceof PrimitiveFieldType); // We use FieldType and cast back to PrimitiveFieldType below to avoid a // bug in the Sun JDK: http://gs.sun.com/view_bug.do?bug_id=6522780 FieldType fieldType = (FieldType) field.getType(); String value = getJavaValue((PrimitiveFieldType) fieldType, field.getValue().toString()); builder.append(String.format(" static final %s %s = %s;\n", fieldType.getJavaTypeName(), field.getName(), value)); } } } private void appendSettersAndGetters(MessageContext messageContext, StringBuilder builder) { MessageFields messageFields = new MessageFields(messageContext); Set<String> getters = Sets.newHashSet(); for (Field field : messageFields.getFields()) { if (field.isConstant()) { continue; } String type = field.getJavaTypeName(); String getter = messageContext.getFieldGetterName(field.getName()); String setter = messageContext.getFieldSetterName(field.getName()); if (getters.contains(getter)) { // In the case that two or more message fields have the same name except // for capitalization, we only generate a getter and setter pair for the // first one. The following fields will only be accessible via the // RawMessage interface. continue; } getters.add(getter); builder.append(String.format(" %s %s();\n", type, getter)); builder.append(String.format(" void %s(%s value);\n", setter, type)); } } }