From 1dd629bd10885940a2ffe9c978361d5b296d05e9 Mon Sep 17 00:00:00 2001 From: Daniel Stonier <d.stonier@gmail.com> Date: Sun, 8 Sep 2013 15:58:18 +0900 Subject: [PATCH] bringing in message_generator and updating gradle_plugins. --- build.gradle | 1 - gradle_plugins/build.gradle | 24 + .../ros/gradle_plugins/CatkinPlugin.groovy | 117 +++ .../META-INF/gradle-plugins/catkin.properties | 1 + message_generator/build.gradle | 38 + .../exception/RosMessageRuntimeException.java | 36 + .../java/org/ros/exception/package-info.java | 20 + .../message/DefaultMessageDeserializer.java | 50 ++ .../message/DefaultMessageFactory.java | 51 ++ .../DefaultMessageInterfaceClassProvider.java | 55 ++ .../DefaultMessageSerializationFactory.java | 80 ++ .../message/DefaultMessageSerializer.java | 36 + .../internal/message/GenerateInterfaces.java | 172 +++++ .../org/ros/internal/message/GetInstance.java | 25 + .../ros/internal/message/Md5Generator.java | 96 +++ .../org/ros/internal/message/Message.java | 28 + .../internal/message/MessageBufferPool.java | 91 +++ .../ros/internal/message/MessageBuffers.java | 44 ++ .../org/ros/internal/message/MessageImpl.java | 491 ++++++++++++ .../message/MessageInterfaceBuilder.java | 193 +++++ .../MessageInterfaceClassProvider.java | 32 + .../internal/message/MessageProxyFactory.java | 80 ++ .../MessageProxyInvocationHandler.java | 51 ++ .../org/ros/internal/message/RawMessage.java | 207 +++++ .../internal/message/StringFileProvider.java | 130 ++++ .../message/StringResourceProvider.java | 73 ++ .../message/context/MessageContext.java | 144 ++++ .../context/MessageContextBuilder.java | 85 +++ .../context/MessageContextProvider.java | 55 ++ .../MessageDefinitionFileProvider.java | 114 +++ .../definition/MessageDefinitionParser.java | 176 +++++ .../MessageDefinitionProviderChain.java | 86 +++ .../MessageDefinitionReflectionProvider.java | 88 +++ .../MessageDefinitionTupleParser.java | 68 ++ .../message/field/BooleanArrayField.java | 117 +++ .../message/field/ByteArrayField.java | 117 +++ .../message/field/ChannelBufferField.java | 118 +++ .../message/field/DoubleArrayField.java | 117 +++ .../org/ros/internal/message/field/Field.java | 113 +++ .../internal/message/field/FieldFactory.java | 25 + .../ros/internal/message/field/FieldType.java | 50 ++ .../message/field/FloatArrayField.java | 117 +++ .../message/field/IntegerArrayField.java | 117 +++ .../ros/internal/message/field/ListField.java | 115 +++ .../message/field/LongArrayField.java | 119 +++ .../message/field/MessageFieldType.java | 136 ++++ .../internal/message/field/MessageFields.java | 116 +++ .../message/field/PrimitiveFieldType.java | 714 ++++++++++++++++++ .../message/field/ShortArrayField.java | 117 +++ .../internal/message/field/ValueField.java | 110 +++ .../ros/internal/message/package-info.java | 22 + .../ServiceDefinitionFileProvider.java | 51 ++ .../ServiceDefinitionResourceProvider.java | 69 ++ .../message/service/ServiceDescription.java | 98 +++ .../service/ServiceDescriptionFactory.java | 44 ++ .../service/ServiceRequestMessageFactory.java | 50 ++ ...eRequestMessageInterfaceClassProvider.java | 37 + .../ServiceResponseMessageFactory.java | 50 ++ ...ResponseMessageInterfaceClassProvider.java | 37 + .../message/service/package-info.java | 22 + .../topic/TopicDefinitionFileProvider.java | 51 ++ .../TopicDefinitionResourceProvider.java | 68 ++ .../message/topic/TopicDescription.java | 69 ++ .../topic/TopicDescriptionFactory.java | 44 ++ .../message/topic/TopicMessageFactory.java | 30 + .../internal/message/topic/package-info.java | 22 + .../main/java/org/ros/message/Duration.java | 167 ++++ .../org/ros/message/MessageDeclaration.java | 108 +++ .../message/MessageDefinitionProvider.java | 50 ++ .../org/ros/message/MessageDeserializer.java | 31 + .../java/org/ros/message/MessageFactory.java | 30 + .../ros/message/MessageFactoryProvider.java | 24 + .../org/ros/message/MessageIdentifier.java | 121 +++ .../java/org/ros/message/MessageListener.java | 36 + .../message/MessageSerializationFactory.java | 75 ++ .../org/ros/message/MessageSerializer.java | 30 + .../src/main/java/org/ros/message/Time.java | 156 ++++ .../java/org/ros/message/package-info.java | 22 + package.xml | 16 + settings.gradle | 3 +- 80 files changed, 6987 insertions(+), 2 deletions(-) create mode 100644 gradle_plugins/build.gradle create mode 100644 gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy create mode 100644 gradle_plugins/src/main/resources/META-INF/gradle-plugins/catkin.properties create mode 100644 message_generator/build.gradle create mode 100644 message_generator/src/main/java/org/ros/exception/RosMessageRuntimeException.java create mode 100644 message_generator/src/main/java/org/ros/exception/package-info.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/DefaultMessageDeserializer.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/DefaultMessageFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/DefaultMessageInterfaceClassProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializationFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializer.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/GenerateInterfaces.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/GetInstance.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/Md5Generator.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/Message.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/MessageBufferPool.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/MessageBuffers.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/MessageImpl.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/MessageInterfaceBuilder.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/MessageInterfaceClassProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/MessageProxyFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/MessageProxyInvocationHandler.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/RawMessage.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/StringFileProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/StringResourceProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/context/MessageContext.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/context/MessageContextBuilder.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/context/MessageContextProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionFileProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionParser.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionProviderChain.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionReflectionProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionTupleParser.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/BooleanArrayField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/ByteArrayField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/ChannelBufferField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/DoubleArrayField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/Field.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/FieldFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/FieldType.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/FloatArrayField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/IntegerArrayField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/ListField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/LongArrayField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/MessageFieldType.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/MessageFields.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/PrimitiveFieldType.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/ShortArrayField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/field/ValueField.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/package-info.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionFileProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionResourceProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceDescription.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceDescriptionFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageInterfaceClassProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageInterfaceClassProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/service/package-info.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionFileProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionResourceProvider.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/topic/TopicDescription.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/topic/TopicDescriptionFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/topic/TopicMessageFactory.java create mode 100644 message_generator/src/main/java/org/ros/internal/message/topic/package-info.java create mode 100644 message_generator/src/main/java/org/ros/message/Duration.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageDeclaration.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageDefinitionProvider.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageDeserializer.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageFactory.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageFactoryProvider.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageIdentifier.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageListener.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageSerializationFactory.java create mode 100644 message_generator/src/main/java/org/ros/message/MessageSerializer.java create mode 100644 message_generator/src/main/java/org/ros/message/Time.java create mode 100644 message_generator/src/main/java/org/ros/message/package-info.java create mode 100644 package.xml diff --git a/build.gradle b/build.gradle index a994432..bd3fd6c 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,6 @@ task wrapper(type: Wrapper) { allprojects { group='org.ros.rosjava_bootstrap' - version='0.1.0-SNAPSHOT' } subprojects { diff --git a/gradle_plugins/build.gradle b/gradle_plugins/build.gradle new file mode 100644 index 0000000..3f1428a --- /dev/null +++ b/gradle_plugins/build.gradle @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 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. + */ + +apply plugin: 'groovy' + +version='0.1.0' + +dependencies { + compile gradleApi() + groovy localGroovy() +} diff --git a/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy new file mode 100644 index 0000000..2d2f2b5 --- /dev/null +++ b/gradle_plugins/src/main/groovy/org/ros/gradle_plugins/CatkinPlugin.groovy @@ -0,0 +1,117 @@ +package org.ros.gradle_plugins; + +import org.gradle.api.Project; +import org.gradle.api.Plugin; +import org.gradle.api.Task; +import org.gradle.api.*; + +/* + * Provides catkin information to the gradle build, defining properties: + * + * - project.catkin.rosPackagePath : list of Strings + * - project.catkin.packages : dictionary of CatkinPackage objects + * + * The latter can be iterated over for information: + * + * project.catkin.packages.each { pair -> + * pkg = pair.value + * println pkg.name + * println pkg.version + * pkg.dependencies.each { d -> + * println d + * } + * // filtered list of *_msg dependencies. + * pkg.messageDependencies().each { d -> + * println d + * } + * } + * + * Use this only once in the root of a multi-project gradle build - it will + * only generate the properties once and share them this way. + */ +class CatkinPlugin implements Plugin<Project> { + /* + * Possibly should check for existence of these properties and + * be lazy if they're already defined. + */ + def void apply(Project project) { + project.extensions.create("catkin", CatkinPluginExtension) + project.catkin.packages = [:] + project.catkin.rosPackagePath = [] + project.catkin.rosPackagePath = "$System.env.ROS_PACKAGE_PATH".split(":") + project.catkin.rosPackagePath.each { rosPackageRoot -> + def manifestTree = project.fileTree(dir: rosPackageRoot, include: '**/package.xml') + manifestTree.each { file -> + def pkg = new CatkinPackage(file) + project.catkin.packages.put(pkg.name, pkg) + } + } + println("CatkinPlugin is happy, you should be too.") + project.task('catkinPackageInfo') << { + println("CatkinPlugin is happy, you should be too.") + println("rosPackagePath........." + project.catkin.rosPackagePath) + println("Catkin Packages") + project.catkin.packages.each { pkg -> + print pkg.value.toString() + } + } + } +} + +class CatkinPluginExtension { + Map<String, CatkinPackage> packages + List<String> rosPackagePath +} + +/* + * Use this to establish methods that can be used by the project. + * Currently don't have any. + */ +class CatkinPluginConvention { + private Project project + public CatkinPluginConvention(Project project) { + this.project = project + } +} + +class CatkinPackage { + def name + def version + def dependencies + + def CatkinPackage(File packageXmlFilename) { + def packageXml = new XmlParser().parse(packageXmlFilename) + name = packageXml.name.text() + version = packageXml.version.text() + dependencies = [] + packageXml.build_depend.each { d -> + dependencies.add(d.text()) + } + } + def String toString() { + def out = new String() + out += name + "\n" + out += " version: " + version + "\n" + out += " dependencies:" + "\n" + dependencies.each { d -> + out += " " + d + "\n" + } + return out + } + /* + * Find and annotate a list of package package dependencies. + * Useful for message artifact generation). + * + * @return List<String> : dependencies (package name strings) + */ + def List<String> messageDependencies() { + List<String> msgDependencies = [] + dependencies.each { d -> + if ( d.contains("_msgs") || d.contains("_srvs") ) { + msgDependencies.add(d) + } + } + return msgDependencies + } +} + diff --git a/gradle_plugins/src/main/resources/META-INF/gradle-plugins/catkin.properties b/gradle_plugins/src/main/resources/META-INF/gradle-plugins/catkin.properties new file mode 100644 index 0000000..687eec7 --- /dev/null +++ b/gradle_plugins/src/main/resources/META-INF/gradle-plugins/catkin.properties @@ -0,0 +1 @@ +implementation-class=org.ros.gradle_plugins.CatkinPlugin \ No newline at end of file diff --git a/message_generator/build.gradle b/message_generator/build.gradle new file mode 100644 index 0000000..325acdb --- /dev/null +++ b/message_generator/build.gradle @@ -0,0 +1,38 @@ +/* + * 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. + */ + +version='0.1.0' + +dependencies { +/* + testCompile 'junit:junit:4.8.2' + */ + compile 'io.netty:netty:3.5.2.Final' + compile 'com.google.guava:guava:12.0' + compile 'org.apache.commons:com.springsource.org.apache.commons.codec:1.3.0' + compile 'org.apache.commons:com.springsource.org.apache.commons.io:1.4.0' + compile 'commons-pool:commons-pool:1.6' + compile 'org.apache.commons:com.springsource.org.apache.commons.lang:2.4.0' +} + +jar { + manifest { + version = '0.1.0' + symbolicName = 'org.ros.rosjava_messages.message_generator' + } +} + + diff --git a/message_generator/src/main/java/org/ros/exception/RosMessageRuntimeException.java b/message_generator/src/main/java/org/ros/exception/RosMessageRuntimeException.java new file mode 100644 index 0000000..b48b9b8 --- /dev/null +++ b/message_generator/src/main/java/org/ros/exception/RosMessageRuntimeException.java @@ -0,0 +1,36 @@ +/* + * 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.exception; + +/** + * @author damonkohler@google.com (Damon Kohler) + * @author d.stonier@gmail.com (Daniel Stonier) + */ +public class RosMessageRuntimeException extends RuntimeException { + + public RosMessageRuntimeException(final Throwable throwable) { + super(throwable); + } + + public RosMessageRuntimeException(final String message, final Throwable throwable) { + super(message, throwable); + } + + public RosMessageRuntimeException(final String message) { + super(message); + } +} diff --git a/message_generator/src/main/java/org/ros/exception/package-info.java b/message_generator/src/main/java/org/ros/exception/package-info.java new file mode 100644 index 0000000..895f12d --- /dev/null +++ b/message_generator/src/main/java/org/ros/exception/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2012 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. + */ + +/** + * Provides the classes for representing common rosjava exceptions. + */ +package org.ros.exception; \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/internal/message/DefaultMessageDeserializer.java b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageDeserializer.java new file mode 100644 index 0000000..507f1c9 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageDeserializer.java @@ -0,0 +1,50 @@ +/* + * 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 org.jboss.netty.buffer.ChannelBuffer; +import org.ros.internal.message.field.Field; +import org.ros.message.MessageDeserializer; +import org.ros.message.MessageFactory; +import org.ros.message.MessageIdentifier; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class DefaultMessageDeserializer<T> implements MessageDeserializer<T> { + + private final MessageIdentifier messageIdentifier; + private final MessageFactory messageFactory; + + public DefaultMessageDeserializer(MessageIdentifier messageIdentifier, + MessageFactory messageFactory) { + this.messageIdentifier = messageIdentifier; + this.messageFactory = messageFactory; + } + + @SuppressWarnings("unchecked") + @Override + public T deserialize(ChannelBuffer buffer) { + Message message = messageFactory.newFromType(messageIdentifier.getType()); + for (Field field : message.toRawMessage().getFields()) { + if (!field.isConstant()) { + field.deserialize(buffer); + } + } + return (T) message; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/DefaultMessageFactory.java b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageFactory.java new file mode 100644 index 0000000..97d817e --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageFactory.java @@ -0,0 +1,51 @@ +/* + * 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.annotations.VisibleForTesting; + +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageFactory; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class DefaultMessageFactory implements MessageFactory { + + private final MessageDefinitionProvider messageDefinitionProvider; + private final DefaultMessageInterfaceClassProvider messageInterfaceClassProvider; + private final MessageProxyFactory messageProxyFactory; + + public DefaultMessageFactory(MessageDefinitionProvider messageDefinitionProvider) { + this.messageDefinitionProvider = messageDefinitionProvider; + messageInterfaceClassProvider = new DefaultMessageInterfaceClassProvider(); + messageProxyFactory = new MessageProxyFactory(getMessageInterfaceClassProvider(), this); + } + + @Override + public <T> T newFromType(String messageType) { + String messageDefinition = messageDefinitionProvider.get(messageType); + MessageDeclaration messageDeclaration = MessageDeclaration.of(messageType, messageDefinition); + return messageProxyFactory.newMessageProxy(messageDeclaration); + } + + @VisibleForTesting + DefaultMessageInterfaceClassProvider getMessageInterfaceClassProvider() { + return messageInterfaceClassProvider; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/DefaultMessageInterfaceClassProvider.java b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageInterfaceClassProvider.java new file mode 100644 index 0000000..8de583d --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageInterfaceClassProvider.java @@ -0,0 +1,55 @@ +/* + * 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.annotations.VisibleForTesting; +import com.google.common.collect.Maps; + +import java.util.Map; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class DefaultMessageInterfaceClassProvider implements MessageInterfaceClassProvider { + + private final Map<String, Class<?>> cache; + + public DefaultMessageInterfaceClassProvider() { + cache = Maps.newConcurrentMap(); + } + + @SuppressWarnings("unchecked") + @Override + public <T> Class<T> get(String messageType) { + if (cache.containsKey(messageType)) { + return (Class<T>) cache.get(messageType); + } + try { + String className = messageType.replace("/", "."); + Class<T> messageInterfaceClass = (Class<T>) getClass().getClassLoader().loadClass(className); + cache.put(messageType, messageInterfaceClass); + return messageInterfaceClass; + } catch (ClassNotFoundException e) { + return (Class<T>) RawMessage.class; + } + } + + @VisibleForTesting + <T> void add(String messageType, Class<T> messageInterfaceClass) { + cache.put(messageType, messageInterfaceClass); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializationFactory.java b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializationFactory.java new file mode 100644 index 0000000..726b5d8 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializationFactory.java @@ -0,0 +1,80 @@ +/* + * 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 org.ros.internal.message.service.ServiceRequestMessageFactory; +import org.ros.internal.message.service.ServiceResponseMessageFactory; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageDeserializer; +import org.ros.message.MessageFactory; +import org.ros.message.MessageIdentifier; +import org.ros.message.MessageSerializationFactory; +import org.ros.message.MessageSerializer; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class DefaultMessageSerializationFactory implements MessageSerializationFactory { + + private final MessageFactory topicMessageFactory; + private final ServiceRequestMessageFactory serviceRequestMessageFactory; + private final ServiceResponseMessageFactory serviceResponseMessageFactory; + + public DefaultMessageSerializationFactory(MessageDefinitionProvider messageDefinitionProvider) { + topicMessageFactory = new DefaultMessageFactory(messageDefinitionProvider); + serviceRequestMessageFactory = new ServiceRequestMessageFactory(messageDefinitionProvider); + serviceResponseMessageFactory = new ServiceResponseMessageFactory(messageDefinitionProvider); + } + + @SuppressWarnings("unchecked") + @Override + public <T> MessageSerializer<T> newMessageSerializer(String messageType) { + return (MessageSerializer<T>) new DefaultMessageSerializer(); + } + + @Override + public <T> MessageDeserializer<T> newMessageDeserializer(String messageType) { + return new DefaultMessageDeserializer<T>(MessageIdentifier.of(messageType), + topicMessageFactory); + } + + @SuppressWarnings("unchecked") + @Override + public <T> MessageSerializer<T> newServiceRequestSerializer(String serviceType) { + return (MessageSerializer<T>) new DefaultMessageSerializer(); + } + + @Override + public <T> org.ros.message.MessageDeserializer<T> + newServiceRequestDeserializer(String serviceType) { + return new DefaultMessageDeserializer<T>(MessageIdentifier.of(serviceType), + serviceRequestMessageFactory); + } + + @SuppressWarnings("unchecked") + @Override + public <T> org.ros.message.MessageSerializer<T> newServiceResponseSerializer(String serviceType) { + return (MessageSerializer<T>) new DefaultMessageSerializer(); + } + + @Override + public <T> org.ros.message.MessageDeserializer<T> newServiceResponseDeserializer( + String serviceType) { + return new DefaultMessageDeserializer<T>(MessageIdentifier.of(serviceType), + serviceResponseMessageFactory); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializer.java b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializer.java new file mode 100644 index 0000000..a71a597 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/DefaultMessageSerializer.java @@ -0,0 +1,36 @@ +/* + * 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 org.jboss.netty.buffer.ChannelBuffer; +import org.ros.internal.message.field.Field; +import org.ros.message.MessageSerializer; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class DefaultMessageSerializer implements MessageSerializer<Message> { + + @Override + public void serialize(Message message, ChannelBuffer buffer) { + for (Field field : message.toRawMessage().getFields()) { + if (!field.isConstant()) { + field.serialize(buffer); + } + } + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/GenerateInterfaces.java b/message_generator/src/main/java/org/ros/internal/message/GenerateInterfaces.java new file mode 100644 index 0000000..c057fd4 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/GenerateInterfaces.java @@ -0,0 +1,172 @@ +/* + * 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.collect.Lists; +import com.google.common.collect.Sets; + +import org.apache.commons.io.FileUtils; +import org.ros.exception.RosMessageRuntimeException; +import org.ros.internal.message.definition.MessageDefinitionProviderChain; +import org.ros.internal.message.definition.MessageDefinitionTupleParser; +import org.ros.internal.message.service.ServiceDefinitionFileProvider; +import org.ros.internal.message.topic.TopicDefinitionFileProvider; +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageFactory; +import org.ros.message.MessageIdentifier; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class GenerateInterfaces { + + private final TopicDefinitionFileProvider topicDefinitionFileProvider; + private final ServiceDefinitionFileProvider serviceDefinitionFileProvider; + private final MessageDefinitionProviderChain messageDefinitionProviderChain; + private final MessageFactory messageFactory; + static private final String ROS_PACKAGE_PATH = "ROS_PACKAGE_PATH"; + + public GenerateInterfaces() { + messageDefinitionProviderChain = new MessageDefinitionProviderChain(); + topicDefinitionFileProvider = new TopicDefinitionFileProvider(); + messageDefinitionProviderChain.addMessageDefinitionProvider(topicDefinitionFileProvider); + serviceDefinitionFileProvider = new ServiceDefinitionFileProvider(); + messageDefinitionProviderChain.addMessageDefinitionProvider(serviceDefinitionFileProvider); + messageFactory = new DefaultMessageFactory(messageDefinitionProviderChain); + } + + /** + * @param packages + * a list of packages containing the topic types to generate + * interfaces for + * @param outputDirectory + * the directory to write the generated interfaces to + * @throws IOException + */ + private void writeTopicInterfaces(File outputDirectory, Collection<String> packages) + throws IOException { + Collection<MessageIdentifier> topicTypes = Sets.newHashSet(); + if (packages.size() == 0) { + packages = topicDefinitionFileProvider.getPackages(); + } + for (String pkg : packages) { + Collection<MessageIdentifier> messageIdentifiers = + topicDefinitionFileProvider.getMessageIdentifiersByPackage(pkg); + if (messageIdentifiers != null) { + topicTypes.addAll(messageIdentifiers); + } + } + for (MessageIdentifier topicType : topicTypes) { + String definition = messageDefinitionProviderChain.get(topicType.getType()); + MessageDeclaration messageDeclaration = new MessageDeclaration(topicType, definition); + writeInterface(messageDeclaration, outputDirectory, true); + } + } + + /** + * @param packages + * a list of packages containing the topic types to generate + * interfaces for + * @param outputDirectory + * the directory to write the generated interfaces to + * @throws IOException + */ + private void writeServiceInterfaces(File outputDirectory, Collection<String> packages) + throws IOException { + Collection<MessageIdentifier> serviceTypes = Sets.newHashSet(); + if (packages.size() == 0) { + packages = serviceDefinitionFileProvider.getPackages(); + } + for (String pkg : packages) { + Collection<MessageIdentifier> messageIdentifiers = + serviceDefinitionFileProvider.getMessageIdentifiersByPackage(pkg); + if (messageIdentifiers != null) { + serviceTypes.addAll(messageIdentifiers); + } + } + for (MessageIdentifier serviceType : serviceTypes) { + String definition = messageDefinitionProviderChain.get(serviceType.getType()); + MessageDeclaration serviceDeclaration = + MessageDeclaration.of(serviceType.getType(), definition); + writeInterface(serviceDeclaration, outputDirectory, false); + List<String> requestAndResponse = MessageDefinitionTupleParser.parse(definition, 2); + MessageDeclaration requestDeclaration = + MessageDeclaration.of(serviceType.getType() + "Request", requestAndResponse.get(0)); + MessageDeclaration responseDeclaration = + MessageDeclaration.of(serviceType.getType() + "Response", requestAndResponse.get(1)); + writeInterface(requestDeclaration, outputDirectory, true); + writeInterface(responseDeclaration, outputDirectory, true); + } + } + + private void writeInterface(MessageDeclaration messageDeclaration, File outputDirectory, + boolean addConstantsAndMethods) { + MessageInterfaceBuilder builder = new MessageInterfaceBuilder(); + builder.setPackageName(messageDeclaration.getPackage()); + builder.setInterfaceName(messageDeclaration.getName()); + builder.setMessageDeclaration(messageDeclaration); + builder.setAddConstantsAndMethods(addConstantsAndMethods); + try { + String content; + content = builder.build(messageFactory); + File file = new File(outputDirectory, messageDeclaration.getType() + ".java"); + FileUtils.writeStringToFile(file, content); + } catch (Exception e) { + System.out.printf("Failed to generate interface for %s.\n", messageDeclaration.getType()); + e.printStackTrace(); + } + } + + public void generate(File outputDirectory, Collection<String> packages, + Collection<File> packagePath) { + for (File directory : packagePath) { + topicDefinitionFileProvider.addDirectory(directory); + serviceDefinitionFileProvider.addDirectory(directory); + } + topicDefinitionFileProvider.update(); + serviceDefinitionFileProvider.update(); + try { + writeTopicInterfaces(outputDirectory, packages); + writeServiceInterfaces(outputDirectory, packages); + } catch (IOException e) { + throw new RosMessageRuntimeException(e); + } + } + + public static void main(String[] args) { + List<String> arguments = Lists.newArrayList(args); + if (arguments.size() == 0) { + arguments.add("."); + } + String rosPackagePath = System.getenv(ROS_PACKAGE_PATH); + Collection<File> packagePath = Lists.newArrayList(); + for (String path : rosPackagePath.split(File.pathSeparator)) { + File packageDirectory = new File(path); + if (packageDirectory.exists()) { + packagePath.add(packageDirectory); + } + } + GenerateInterfaces generateInterfaces = new GenerateInterfaces(); + File outputDirectory = new File(arguments.remove(0)); + generateInterfaces.generate(outputDirectory, arguments, packagePath); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/GetInstance.java b/message_generator/src/main/java/org/ros/internal/message/GetInstance.java new file mode 100644 index 0000000..5916b94 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/GetInstance.java @@ -0,0 +1,25 @@ +/* + * 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; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +interface GetInstance { + + public Object getInstance(); +} diff --git a/message_generator/src/main/java/org/ros/internal/message/Md5Generator.java b/message_generator/src/main/java/org/ros/internal/message/Md5Generator.java new file mode 100644 index 0000000..0e78b79 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/Md5Generator.java @@ -0,0 +1,96 @@ +/* + * 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.Lists; + +import org.ros.internal.message.definition.MessageDefinitionParser; +import org.ros.internal.message.definition.MessageDefinitionTupleParser; +import org.ros.internal.message.definition.MessageDefinitionParser.MessageDefinitionVisitor; + +import org.apache.commons.codec.digest.DigestUtils; +import org.ros.internal.message.field.PrimitiveFieldType; +import org.ros.message.MessageDefinitionProvider; + +import java.util.List; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class Md5Generator { + + private final MessageDefinitionProvider messageDefinitionProvider; + + public Md5Generator(MessageDefinitionProvider messageDefinitionProvider) { + this.messageDefinitionProvider = messageDefinitionProvider; + } + + public String generate(String messageType) { + String messageDefinition = messageDefinitionProvider.get(messageType); + Preconditions.checkNotNull(messageDefinition, "No definition for message type: " + messageType); + List<String> parts = MessageDefinitionTupleParser.parse(messageDefinition, -1); + StringBuilder text = new StringBuilder(); + for (String part : parts) { + text.append(generateText(messageType, part)); + } + return DigestUtils.md5Hex(text.toString()); + } + + private String generateText(String messageType, String messageDefinition) { + final List<String> constants = Lists.newArrayList(); + final List<String> variables = Lists.newArrayList(); + MessageDefinitionVisitor visitor = new MessageDefinitionVisitor() { + @Override + public void variableValue(String type, String name) { + if (!PrimitiveFieldType.existsFor(type)) { + type = generate(type); + } + variables.add(String.format("%s %s\n", type, name)); + } + + @Override + public void variableList(String type, int size, String name) { + if (!PrimitiveFieldType.existsFor(type)) { + String md5Checksum = generate(type); + variables.add(String.format("%s %s\n", md5Checksum, name)); + } else { + if (size != -1) { + variables.add(String.format("%s[%d] %s\n", type, size, name)); + } else { + variables.add(String.format("%s[] %s\n", type, name)); + } + } + } + + @Override + public void constantValue(String type, String name, String value) { + constants.add(String.format("%s %s=%s\n", type, name, value)); + } + }; + MessageDefinitionParser messageDefinitionParser = new MessageDefinitionParser(visitor); + messageDefinitionParser.parse(messageType, messageDefinition); + String text = ""; + for (String constant : constants) { + text += constant; + } + for (String variable : variables) { + text += variable; + } + return text.trim(); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/Message.java b/message_generator/src/main/java/org/ros/internal/message/Message.java new file mode 100644 index 0000000..055db82 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/Message.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 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; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface Message { + + /** + * @return returns this {@link Message} as a {@link RawMessage} + */ + RawMessage toRawMessage(); +} diff --git a/message_generator/src/main/java/org/ros/internal/message/MessageBufferPool.java b/message_generator/src/main/java/org/ros/internal/message/MessageBufferPool.java new file mode 100644 index 0000000..73246ed --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/MessageBufferPool.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 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 org.apache.commons.pool.ObjectPool; +import org.apache.commons.pool.PoolableObjectFactory; +import org.apache.commons.pool.impl.StackObjectPool; +import org.jboss.netty.buffer.ChannelBuffer; +import org.ros.exception.RosMessageRuntimeException; + +/** + * A pool of {@link ChannelBuffer}s for serializing and deserializing messages. + * <p> + * By contract, {@link ChannelBuffer}s provided by {@link #acquire()} must be + * returned using {@link #release(ChannelBuffer)}. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageBufferPool { + + private final ObjectPool<ChannelBuffer> pool; + + public MessageBufferPool() { + pool = new StackObjectPool<ChannelBuffer>(new PoolableObjectFactory<ChannelBuffer>() { + @Override + public ChannelBuffer makeObject() throws Exception { + return MessageBuffers.dynamicBuffer(); + } + + @Override + public void destroyObject(ChannelBuffer channelBuffer) throws Exception { + } + + @Override + public boolean validateObject(ChannelBuffer channelBuffer) { + return true; + } + + @Override + public void activateObject(ChannelBuffer channelBuffer) throws Exception { + } + + @Override + public void passivateObject(ChannelBuffer channelBuffer) throws Exception { + channelBuffer.clear(); + } + }); + } + + /** + * Acquired {@link ChannelBuffer}s must be returned using + * {@link #release(ChannelBuffer)}. + * + * @return an unused {@link ChannelBuffer} + */ + public ChannelBuffer acquire() { + try { + return pool.borrowObject(); + } catch (Exception e) { + throw new RosMessageRuntimeException(e); + } + } + + /** + * Release a previously acquired {@link ChannelBuffer}. + * + * @param channelBuffer + * the {@link ChannelBuffer} to release + */ + public void release(ChannelBuffer channelBuffer) { + try { + pool.returnObject(channelBuffer); + } catch (Exception e) { + throw new RosMessageRuntimeException(e); + } + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/MessageBuffers.java b/message_generator/src/main/java/org/ros/internal/message/MessageBuffers.java new file mode 100644 index 0000000..a5934ec --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/MessageBuffers.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 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 org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; + +import java.nio.ByteOrder; + +/** + * Provides {@link ChannelBuffer}s for serializing and deserializing messages. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageBuffers { + + static final int ESTIMATED_LENGTH = 256; + + private MessageBuffers() { + // Utility class. + } + + /** + * @return a new {@link ChannelBuffer} for {@link Message} serialization that + * grows dynamically + */ + public static ChannelBuffer dynamicBuffer() { + return ChannelBuffers.dynamicBuffer(ByteOrder.LITTLE_ENDIAN, ESTIMATED_LENGTH); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/MessageImpl.java b/message_generator/src/main/java/org/ros/internal/message/MessageImpl.java new file mode 100644 index 0000000..d7824dc --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/MessageImpl.java @@ -0,0 +1,491 @@ +/* + * 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 org.jboss.netty.buffer.ChannelBuffer; +import org.ros.exception.RosMessageRuntimeException; +import org.ros.internal.message.context.MessageContext; +import org.ros.internal.message.field.Field; +import org.ros.internal.message.field.MessageFieldType; +import org.ros.internal.message.field.MessageFields; +import org.ros.message.Duration; +import org.ros.message.MessageIdentifier; +import org.ros.message.Time; + +import java.util.List; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +class MessageImpl implements RawMessage, GetInstance { + + private final MessageContext messageContext; + private final MessageFields messageFields; + + public MessageImpl(MessageContext messageContext) { + this.messageContext = messageContext; + messageFields = new MessageFields(messageContext); + } + + public MessageContext getMessageContext() { + return messageContext; + } + + public MessageFields getMessageFields() { + return messageFields; + } + + @Override + public RawMessage toRawMessage() { + return (RawMessage) this; + } + + @Override + public MessageIdentifier getIdentifier() { + return messageContext.getMessageIdentifer(); + } + + @Override + public String getType() { + return messageContext.getType(); + } + + @Override + public String getPackage() { + return messageContext.getPackage(); + } + + @Override + public String getName() { + return messageContext.getName(); + } + + @Override + public String getDefinition() { + return messageContext.getDefinition(); + } + + @Override + public List<Field> getFields() { + return messageFields.getFields(); + } + + @Override + public boolean getBool(String name) { + return (Boolean) messageFields.getFieldValue(name); + } + + @Override + public boolean[] getBoolArray(String name) { + return (boolean[]) messageFields.getFieldValue(name); + } + + @Override + public Duration getDuration(String name) { + return (Duration) messageFields.getFieldValue(name); + } + + @SuppressWarnings("unchecked") + @Override + public List<Duration> getDurationList(String name) { + return (List<Duration>) messageFields.getFieldValue(name); + } + + @Override + public float getFloat32(String name) { + return (Float) messageFields.getFieldValue(name); + } + + @Override + public float[] getFloat32Array(String name) { + return (float[]) messageFields.getFieldValue(name); + } + + @Override + public double getFloat64(String name) { + return (Double) messageFields.getFieldValue(name); + } + + @Override + public double[] getFloat64Array(String name) { + return (double[]) messageFields.getFieldValue(name); + } + + @Override + public short getInt16(String name) { + return (Short) messageFields.getFieldValue(name); + } + + @Override + public short[] getInt16Array(String name) { + return (short[]) messageFields.getFieldValue(name); + } + + @Override + public int getInt32(String name) { + return (Integer) messageFields.getFieldValue(name); + } + + @Override + public int[] getInt32Array(String name) { + return (int[]) messageFields.getFieldValue(name); + } + + @Override + public long getInt64(String name) { + return (Long) messageFields.getFieldValue(name); + } + + @Override + public long[] getInt64Array(String name) { + return (long[]) messageFields.getFieldValue(name); + } + + @Override + public byte getInt8(String name) { + return (Byte) messageFields.getFieldValue(name); + } + + @Override + public byte[] getInt8Array(String name) { + return (byte[]) messageFields.getFieldValue(name); + } + + @Override + public <T extends Message> T getMessage(String name) { + if (messageFields.getField(name).getType() instanceof MessageFieldType) { + return messageFields.getField(name).<T>getValue(); + } + throw new RosMessageRuntimeException("Failed to access message field: " + name); + } + + @Override + public <T extends Message> List<T> getMessageList(String name) { + if (messageFields.getField(name).getType() instanceof MessageFieldType) { + return messageFields.getField(name).<List<T>>getValue(); + } + throw new RosMessageRuntimeException("Failed to access list field: " + name); + } + + @Override + public String getString(String name) { + return (String) messageFields.getFieldValue(name); + } + + @SuppressWarnings("unchecked") + @Override + public List<String> getStringList(String name) { + return (List<String>) messageFields.getFieldValue(name); + } + + @Override + public Time getTime(String name) { + return (Time) messageFields.getFieldValue(name); + } + + @SuppressWarnings("unchecked") + @Override + public List<Time> getTimeList(String name) { + return (List<Time>) messageFields.getFieldValue(name); + } + + @Override + public short getUInt16(String name) { + return (Short) messageFields.getFieldValue(name); + } + + @Override + public short[] getUInt16Array(String name) { + return (short[]) messageFields.getFieldValue(name); + } + + @Override + public int getUInt32(String name) { + return (Integer) messageFields.getFieldValue(name); + } + + @Override + public int[] getUInt32Array(String name) { + return (int[]) messageFields.getFieldValue(name); + } + + @Override + public long getUInt64(String name) { + return (Long) messageFields.getFieldValue(name); + } + + @Override + public long[] getUInt64Array(String name) { + return (long[]) messageFields.getFieldValue(name); + } + + @Override + public short getUInt8(String name) { + return (Short) messageFields.getFieldValue(name); + } + + @Override + public short[] getUInt8Array(String name) { + return (short[]) messageFields.getFieldValue(name); + } + + @Override + public void setBool(String name, boolean value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setBoolArray(String name, boolean[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setDurationList(String name, List<Duration> value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setDuration(String name, Duration value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setFloat32(String name, float value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setFloat32Array(String name, float[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setFloat64(String name, double value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setFloat64Array(String name, double[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt16(String name, short value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt16Array(String name, short[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt32(String name, int value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt32Array(String name, int[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt64(String name, long value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt64Array(String name, long[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt8(String name, byte value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setInt8Array(String name, byte[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setMessage(String name, Message value) { + // TODO(damonkohler): Verify the type of the provided Message? + messageFields.setFieldValue(name, value); + } + + @Override + public void setMessageList(String name, List<Message> value) { + // TODO(damonkohler): Verify the type of all Messages in the provided list? + messageFields.setFieldValue(name, value); + } + + @Override + public void setString(String name, String value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setStringList(String name, List<String> value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setTime(String name, Time value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setTimeList(String name, List<Time> value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt16(String name, short value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt16Array(String name, short[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt32(String name, int value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt32Array(String name, int[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt64(String name, long value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt64Array(String name, long[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt8(String name, byte value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setUInt8Array(String name, byte[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public byte getByte(String name) { + return (Byte) messageFields.getFieldValue(name); + } + + @Override + public short getChar(String name) { + return (Short) messageFields.getFieldValue(name); + } + + @Override + public void setByte(String name, byte value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setChar(String name, short value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setByteArray(String name, byte[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public void setCharArray(String name, short[] value) { + messageFields.setFieldValue(name, value); + } + + @Override + public byte[] getByteArray(String name) { + return (byte[]) messageFields.getFieldValue(name); + } + + @Override + public short[] getCharArray(String name) { + return (short[]) messageFields.getFieldValue(name); + } + + @Override + public ChannelBuffer getChannelBuffer(String name) { + return (ChannelBuffer) messageFields.getFieldValue(name); + } + + @Override + public void setChannelBuffer(String name, ChannelBuffer value) { + messageFields.setFieldValue(name, value); + } + + @Override + public Object getInstance() { + return this; + } + + @Override + public String toString() { + return String.format("MessageImpl<%s>", getType()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((messageContext == null) ? 0 : messageContext.hashCode()); + result = prime * result + ((messageFields == null) ? 0 : messageFields.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof GetInstance)) + return false; + obj = ((GetInstance) obj).getInstance(); + if (getClass() != obj.getClass()) + return false; + MessageImpl other = (MessageImpl) obj; + if (messageContext == null) { + if (other.messageContext != null) + return false; + } else if (!messageContext.equals(other.messageContext)) + return false; + if (messageFields == null) { + if (other.messageFields != null) + return false; + } else if (!messageFields.equals(other.messageFields)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/MessageInterfaceBuilder.java b/message_generator/src/main/java/org/ros/internal/message/MessageInterfaceBuilder.java new file mode 100644 index 0000000..43b8caa --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/MessageInterfaceBuilder.java @@ -0,0 +1,193 @@ +/* + * 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.RosMessageRuntimeException; +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 RosMessageRuntimeException("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)); + } + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/MessageInterfaceClassProvider.java b/message_generator/src/main/java/org/ros/internal/message/MessageInterfaceClassProvider.java new file mode 100644 index 0000000..544c315 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/MessageInterfaceClassProvider.java @@ -0,0 +1,32 @@ +/* + * 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; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface MessageInterfaceClassProvider { + + /** + * @param <T> + * the message interface class type + * @param messageType + * the type of message to provide an interface class for + * @return the interface class for the specified message type + */ + <T> Class<T> get(String messageType); +} diff --git a/message_generator/src/main/java/org/ros/internal/message/MessageProxyFactory.java b/message_generator/src/main/java/org/ros/internal/message/MessageProxyFactory.java new file mode 100644 index 0000000..cc2e7f2 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/MessageProxyFactory.java @@ -0,0 +1,80 @@ +/* + * 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 org.ros.internal.message.context.MessageContext; +import org.ros.internal.message.context.MessageContextProvider; +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageFactory; + +import java.lang.reflect.Proxy; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageProxyFactory { + + // We can't use the constant here since the rosjava_messages package depends + // on rosjava_bootstrap. + private static final String HEADER_MESSAGE_TYPE = "std_msgs/Header"; + private static final String SEQUENCE_FIELD_NAME = "seq"; + private static final AtomicInteger SEQUENCE_NUMBER = new AtomicInteger(0); + + private final MessageInterfaceClassProvider messageInterfaceClassProvider; + private final MessageContextProvider messageContextProvider; + + public MessageProxyFactory(MessageInterfaceClassProvider messageInterfaceClassProvider, + MessageFactory messageFactory) { + this.messageInterfaceClassProvider = messageInterfaceClassProvider; + messageContextProvider = new MessageContextProvider(messageFactory); + } + + @SuppressWarnings("unchecked") + public <T> T newMessageProxy(MessageDeclaration messageDeclaration) { + Preconditions.checkNotNull(messageDeclaration); + MessageContext messageContext = messageContextProvider.get(messageDeclaration); + MessageImpl messageImpl = new MessageImpl(messageContext); + // Header messages are automatically populated with a monotonically + // increasing sequence number. + if (messageImpl.getType().equals(HEADER_MESSAGE_TYPE)) { + messageImpl.setUInt32(SEQUENCE_FIELD_NAME, SEQUENCE_NUMBER.getAndIncrement()); + } + Class<T> messageInterfaceClass = + (Class<T>) messageInterfaceClassProvider.get(messageDeclaration.getType()); + return newProxy(messageInterfaceClass, messageImpl); + } + + /** + * @param interfaceClass + * the interface class to provide + * @param messageImpl + * the instance to proxy + * @return a new proxy for {@code implementation} that implements + * {@code interfaceClass} + */ + @SuppressWarnings("unchecked") + private <T> T newProxy(Class<T> interfaceClass, final MessageImpl messageImpl) { + ClassLoader classLoader = messageImpl.getClass().getClassLoader(); + Class<?>[] interfaces = new Class<?>[] { interfaceClass, GetInstance.class }; + MessageProxyInvocationHandler invocationHandler = + new MessageProxyInvocationHandler(messageImpl); + return (T) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/MessageProxyInvocationHandler.java b/message_generator/src/main/java/org/ros/internal/message/MessageProxyInvocationHandler.java new file mode 100644 index 0000000..2f1c2e2 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/MessageProxyInvocationHandler.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 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 org.ros.internal.message.field.Field; +import org.ros.internal.message.field.MessageFields; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageProxyInvocationHandler implements InvocationHandler { + + private final MessageImpl messageImpl; + + MessageProxyInvocationHandler(MessageImpl messageImpl) { + this.messageImpl = messageImpl; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String methodName = method.getName(); + MessageFields mesageFields = messageImpl.getMessageFields(); + Field getterField = mesageFields.getGetterField(methodName); + if (getterField != null) { + return getterField.getValue(); + } + Field setterField = mesageFields.getSetterField(methodName); + if (setterField != null) { + setterField.setValue(args[0]); + return null; + } + return method.invoke(messageImpl, args); + } +} \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/internal/message/RawMessage.java b/message_generator/src/main/java/org/ros/internal/message/RawMessage.java new file mode 100644 index 0000000..999db7a --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/RawMessage.java @@ -0,0 +1,207 @@ +/* + * 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 org.jboss.netty.buffer.ChannelBuffer; +import org.ros.internal.message.field.Field; +import org.ros.message.Duration; +import org.ros.message.MessageIdentifier; +import org.ros.message.Time; + +import java.util.List; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface RawMessage extends Message { + + boolean getBool(String name); + + boolean[] getBoolArray(String name); + + /** + * @deprecated replaced by {@link #getInt8(String)} + */ + byte getByte(String name); + + /** + * @deprecated replaced by {@link #getInt8Array(String)} + */ + byte[] getByteArray(String name); + + /** + * @deprecated replaced by {@link #getUInt8(String)} + */ + short getChar(String name); + + /** + * @deprecated replaced by {@link #getUInt8Array(String)} + */ + short[] getCharArray(String name); + + String getDefinition(); + + Duration getDuration(String name); + + List<Duration> getDurationList(String name); + + List<Field> getFields(); + + float getFloat32(String name); + + float[] getFloat32Array(String name); + + double getFloat64(String name); + + double[] getFloat64Array(String name); + + MessageIdentifier getIdentifier(); + + short getInt16(String name); + + short[] getInt16Array(String name); + + int getInt32(String name); + + int[] getInt32Array(String name); + + long getInt64(String name); + + long[] getInt64Array(String name); + + byte getInt8(String name); + + byte[] getInt8Array(String name); + + <T extends Message> T getMessage(String name); + + <T extends Message> List<T> getMessageList(String name); + + String getName(); + + String getPackage(); + + String getString(String name); + + List<String> getStringList(String name); + + Time getTime(String name); + + List<Time> getTimeList(String name); + + String getType(); + + short getUInt16(String name); + + short[] getUInt16Array(String name); + + int getUInt32(String name); + + int[] getUInt32Array(String name); + + long getUInt64(String name); + + long[] getUInt64Array(String name); + + short getUInt8(String name); + + short[] getUInt8Array(String name); + + void setBool(String name, boolean value); + + void setBoolArray(String name, boolean[] value); + + /** + * @deprecated replaced by {@link #setInt8(String, byte)} + */ + void setByte(String name, byte value); + + /** + * @deprecated replaced by {@link #setInt8Array(String, byte[])} + */ + void setByteArray(String name, byte[] value); + + /** + * @deprecated replaced by {@link #setUInt8(String, byte)} + */ + void setChar(String name, short value); + + /** + * @deprecated replaced by {@link #setUInt8Array(String, byte[])} + */ + void setCharArray(String name, short[] value); + + void setDuration(String name, Duration value); + + void setDurationList(String name, List<Duration> value); + + void setFloat32(String name, float value); + + void setFloat32Array(String name, float[] value); + + void setFloat64(String name, double value); + + void setFloat64Array(String name, double[] value); + + void setInt16(String name, short value); + + void setInt16Array(String name, short[] value); + + void setInt32(String name, int value); + + void setInt32Array(String name, int[] value); + + void setInt64(String name, long value); + + void setInt64Array(String name, long[] value); + + void setInt8(String name, byte value); + + void setInt8Array(String name, byte[] value); + + void setMessage(String name, Message value); + + void setMessageList(String name, List<Message> value); + + void setString(String name, String value); + + void setStringList(String name, List<String> value); + + void setTime(String name, Time value); + + void setTimeList(String name, List<Time> value); + + void setUInt16(String name, short value); + + void setUInt16Array(String name, short[] value); + + void setUInt32(String name, int value); + + void setUInt32Array(String name, int[] value); + + void setUInt64(String name, long value); + + void setUInt64Array(String name, long[] value); + + void setUInt8(String name, byte value); + + void setUInt8Array(String name, byte[] value); + + void setChannelBuffer(String name, ChannelBuffer value); + + ChannelBuffer getChannelBuffer(String name); +} diff --git a/message_generator/src/main/java/org/ros/internal/message/StringFileProvider.java b/message_generator/src/main/java/org/ros/internal/message/StringFileProvider.java new file mode 100644 index 0000000..2f9ddfa --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/StringFileProvider.java @@ -0,0 +1,130 @@ +/* + * 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.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import org.apache.commons.io.DirectoryWalker; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.ros.exception.RosMessageRuntimeException; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class StringFileProvider { + + private final Collection<File> directories; + private final Map<File, String> strings; + private final StringFileDirectoryWalker stringFileDirectoryWalker; + + private final class StringFileDirectoryWalker extends DirectoryWalker { + + private final Set<File> directories; + + private StringFileDirectoryWalker(FileFilter filter, int depthLimit) { + super(filter, depthLimit); + directories = Sets.newHashSet(); + } + + // TODO(damonkohler): Update Apache Commons IO to the latest version. + @SuppressWarnings("rawtypes") + @Override + protected boolean handleDirectory(File directory, int depth, Collection results) + throws IOException { + File canonicalDirectory = directory.getCanonicalFile(); + if (directories.contains(canonicalDirectory)) { + return false; + } + directories.add(canonicalDirectory); + return true; + } + + @SuppressWarnings("rawtypes") + @Override + protected void handleFile(File file, int depth, Collection results) { + String content; + try { + content = FileUtils.readFileToString(file, "US-ASCII"); + } catch (IOException e) { + throw new RosMessageRuntimeException(e); + } + strings.put(file, content); + } + + public void update(File directory) { + try { + walk(directory, null); + } catch (IOException e) { + throw new RosMessageRuntimeException(e); + } + } + } + + public StringFileProvider(IOFileFilter ioFileFilter) { + directories = Lists.newArrayList(); + strings = Maps.newConcurrentMap(); + IOFileFilter directoryFilter = FileFilterUtils.directoryFileFilter(); + FileFilter fileFilter = FileFilterUtils.orFileFilter(directoryFilter, ioFileFilter); + stringFileDirectoryWalker = new StringFileDirectoryWalker(fileFilter, -1); + } + + public void update() { + for (File directory : directories) { + stringFileDirectoryWalker.update(directory); + } + } + + /** + * Adds a new directory to be scanned for topic definition files. + * + * @param directory + * the directory to add + */ + public void addDirectory(File directory) { + Preconditions.checkArgument(directory.isDirectory()); + directories.add(directory); + } + + public Map<File, String> getStrings() { + return ImmutableMap.copyOf(strings); + } + + public String get(File file) { + if (!has(file)) { + throw new NoSuchElementException("File does not exist: " + file); + } + return strings.get(file); + } + + public boolean has(File file) { + return strings.containsKey(file); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/StringResourceProvider.java b/message_generator/src/main/java/org/ros/internal/message/StringResourceProvider.java new file mode 100644 index 0000000..c7de05f --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/StringResourceProvider.java @@ -0,0 +1,73 @@ +/* + * 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.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import org.ros.exception.RosMessageRuntimeException; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.Map; +import java.util.NoSuchElementException; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class StringResourceProvider { + + private final Map<String, String> cache; + + public StringResourceProvider() { + cache = Maps.newConcurrentMap(); + } + + public String get(String resourceName) { + if (!has(resourceName)) { + throw new NoSuchElementException("Resource does not exist: " + resourceName); + } + if (!cache.containsKey(resourceName)) { + InputStream in = getClass().getResourceAsStream(resourceName); + StringBuilder out = new StringBuilder(); + Charset charset = Charset.forName("US-ASCII"); + byte[] buffer = new byte[8192]; + try { + for (int bytesRead; (bytesRead = in.read(buffer)) != -1;) { + out.append(new String(buffer, 0, bytesRead, charset)); + } + } catch (IOException e) { + throw new RosMessageRuntimeException("Failed to read resource: " + resourceName, e); + } + cache.put(resourceName, out.toString()); + } + return cache.get(resourceName); + } + + public boolean has(String resourceName) { + return cache.containsKey(resourceName) || getClass().getResource(resourceName) != null; + } + + public Map<String, String> getCachedStrings() { + return ImmutableMap.copyOf(cache); + } + + public void addStringToCache(String resourceName, String resourceContent) { + cache.put(resourceName, resourceContent); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/context/MessageContext.java b/message_generator/src/main/java/org/ros/internal/message/context/MessageContext.java new file mode 100644 index 0000000..11f4a2b --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/context/MessageContext.java @@ -0,0 +1,144 @@ +/* + * 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.context; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import org.ros.internal.message.field.FieldFactory; +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageFactory; +import org.ros.message.MessageIdentifier; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Encapsulates the immutable metadata that describes a message type. + * <p> + * Note that this class is not thread safe. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageContext { + + private final MessageDeclaration messageDeclaration; + private final MessageFactory messageFactory; + private final Map<String, FieldFactory> fieldFactories; + private final Map<String, String> fieldGetterNames; + private final Map<String, String> fieldSetterNames; + private final List<String> fieldNames; + + public MessageContext(MessageDeclaration messageDeclaration, MessageFactory messageFactory) { + this.messageDeclaration = messageDeclaration; + this.messageFactory = messageFactory; + this.fieldFactories = Maps.newHashMap(); + this.fieldGetterNames = Maps.newHashMap(); + this.fieldSetterNames = Maps.newHashMap(); + this.fieldNames = Lists.newArrayList(); + } + + public MessageFactory getMessageFactory() { + return messageFactory; + } + + public MessageIdentifier getMessageIdentifer() { + return messageDeclaration.getMessageIdentifier(); + } + + public String getType() { + return messageDeclaration.getType(); + } + + public String getPackage() { + return messageDeclaration.getPackage(); + } + + public String getName() { + return messageDeclaration.getName(); + } + + public String getDefinition() { + return messageDeclaration.getDefinition(); + } + + public void addFieldFactory(String name, FieldFactory fieldFactory) { + fieldFactories.put(name, fieldFactory); + fieldGetterNames.put(name, "get" + getJavaName(name)); + fieldSetterNames.put(name, "set" + getJavaName(name)); + fieldNames.add(name); + } + + private String getJavaName(String name) { + String[] parts = name.split("_"); + StringBuilder fieldName = new StringBuilder(); + for (String part : parts) { + fieldName.append(part.substring(0, 1).toUpperCase() + part.substring(1)); + } + return fieldName.toString(); + } + + public boolean hasField(String name) { + // O(1) instead of an O(n) check against the list of field names. + return fieldFactories.containsKey(name); + } + + public String getFieldGetterName(String name) { + return fieldGetterNames.get(name); + } + + public String getFieldSetterName(String name) { + return fieldSetterNames.get(name); + } + + public FieldFactory getFieldFactory(String name) { + return fieldFactories.get(name); + } + + /** + * @return a {@link List} of field names in the order they were added + */ + public List<String> getFieldNames() { + return Collections.unmodifiableList(fieldNames); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((messageDeclaration == null) ? 0 : messageDeclaration.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MessageContext other = (MessageContext) obj; + if (messageDeclaration == null) { + if (other.messageDeclaration != null) + return false; + } else if (!messageDeclaration.equals(other.messageDeclaration)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/context/MessageContextBuilder.java b/message_generator/src/main/java/org/ros/internal/message/context/MessageContextBuilder.java new file mode 100644 index 0000000..dd14924 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/context/MessageContextBuilder.java @@ -0,0 +1,85 @@ +/* + * 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.context; + +import com.google.common.base.Preconditions; + +import org.ros.internal.message.definition.MessageDefinitionParser.MessageDefinitionVisitor; +import org.ros.internal.message.field.Field; +import org.ros.internal.message.field.FieldFactory; +import org.ros.internal.message.field.FieldType; +import org.ros.internal.message.field.MessageFieldType; +import org.ros.internal.message.field.PrimitiveFieldType; +import org.ros.message.MessageIdentifier; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +class MessageContextBuilder implements MessageDefinitionVisitor { + + private final MessageContext messageContext; + + public MessageContextBuilder(MessageContext context) { + this.messageContext = context; + } + + private FieldType getFieldType(String type) { + Preconditions.checkArgument(!type.equals(messageContext.getType()), + "Message definitions may not be self-referential."); + FieldType fieldType; + if (PrimitiveFieldType.existsFor(type)) { + fieldType = PrimitiveFieldType.valueOf(type.toUpperCase()); + } else { + fieldType = + new MessageFieldType(MessageIdentifier.of(type), messageContext.getMessageFactory()); + } + return fieldType; + } + + @Override + public void variableValue(String type, final String name) { + final FieldType fieldType = getFieldType(type); + messageContext.addFieldFactory(name, new FieldFactory() { + @Override + public Field create() { + return fieldType.newVariableValue(name); + } + }); + } + + @Override + public void variableList(String type, final int size, final String name) { + final FieldType fieldType = getFieldType(type); + messageContext.addFieldFactory(name, new FieldFactory() { + @Override + public Field create() { + return fieldType.newVariableList(name, size); + } + }); + } + + @Override + public void constantValue(String type, final String name, final String value) { + final FieldType fieldType = getFieldType(type); + messageContext.addFieldFactory(name, new FieldFactory() { + @Override + public Field create() { + return fieldType.newConstantValue(name, fieldType.parseFromString(value)); + } + }); + } +} \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/internal/message/context/MessageContextProvider.java b/message_generator/src/main/java/org/ros/internal/message/context/MessageContextProvider.java new file mode 100644 index 0000000..0782970 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/context/MessageContextProvider.java @@ -0,0 +1,55 @@ +/* + * 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.context; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; + +import org.ros.internal.message.definition.MessageDefinitionParser; +import org.ros.internal.message.definition.MessageDefinitionParser.MessageDefinitionVisitor; +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageFactory; + +import java.util.Map; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageContextProvider { + + private final Map<MessageDeclaration, MessageContext> cache; + private final MessageFactory messageFactory; + + public MessageContextProvider(MessageFactory messageFactory) { + Preconditions.checkNotNull(messageFactory); + this.messageFactory = messageFactory; + cache = Maps.newConcurrentMap(); + } + + public MessageContext get(MessageDeclaration messageDeclaration) { + MessageContext messageContext = cache.get(messageDeclaration); + if (messageContext == null) { + messageContext = new MessageContext(messageDeclaration, messageFactory); + MessageDefinitionVisitor visitor = new MessageContextBuilder(messageContext); + MessageDefinitionParser messageDefinitionParser = new MessageDefinitionParser(visitor); + messageDefinitionParser.parse(messageDeclaration.getType(), + messageDeclaration.getDefinition()); + cache.put(messageDeclaration, messageContext); + } + return messageContext; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionFileProvider.java b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionFileProvider.java new file mode 100644 index 0000000..4aa0389 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionFileProvider.java @@ -0,0 +1,114 @@ +/* + * 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.definition; + +import com.google.common.collect.Maps; + +import org.ros.internal.message.StringFileProvider; + +import org.apache.commons.io.FilenameUtils; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageIdentifier; + +import java.io.File; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageDefinitionFileProvider implements MessageDefinitionProvider { + + private final StringFileProvider stringFileProvider; + private final Map<String, Collection<MessageIdentifier>> messageIdentifiers; + private final Map<String, String> definitions; + + public MessageDefinitionFileProvider(StringFileProvider stringFileProvider) { + this.stringFileProvider = stringFileProvider; + messageIdentifiers = Maps.newConcurrentMap(); + definitions = Maps.newConcurrentMap(); + } + + private static String getParent(String filename) { + return FilenameUtils.getFullPathNoEndSeparator(filename); + } + + protected static String getParentBaseName(String filename) { + return FilenameUtils.getBaseName(getParent(filename)); + } + + private static MessageIdentifier fileToMessageIdentifier(File file) { + String filename = file.getAbsolutePath(); + String name = FilenameUtils.getBaseName(filename); + String pkg = getParentBaseName(getParent(filename)); + return MessageIdentifier.of(pkg, name); + } + + private void addDefinition(File file, String definition) { + MessageIdentifier topicType = fileToMessageIdentifier(file); + if (definitions.containsKey(topicType.getType())) { + // First definition wins. + return; + } + definitions.put(topicType.getType(), definition); + if (!messageIdentifiers.containsKey(topicType.getPackage())) { + messageIdentifiers.put(topicType.getPackage(), new HashSet<MessageIdentifier>()); + } + messageIdentifiers.get(topicType.getPackage()).add(topicType); + } + + /** + * Updates the topic definition cache. + * + * @see StringFileProvider#update() + */ + public void update() { + stringFileProvider.update(); + for (Entry<File, String> entry : stringFileProvider.getStrings().entrySet()) { + addDefinition(entry.getKey(), entry.getValue()); + } + } + + /** + * @see StringFileProvider#addDirectory(File) + */ + public void addDirectory(File directory) { + stringFileProvider.addDirectory(directory); + } + + @Override + public Collection<String> getPackages() { + return messageIdentifiers.keySet(); + } + + @Override + public Collection<MessageIdentifier> getMessageIdentifiersByPackage(String pkg) { + return messageIdentifiers.get(pkg); + } + + @Override + public String get(String type) { + return definitions.get(type); + } + + @Override + public boolean has(String type) { + return definitions.containsKey(type); + } +} \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionParser.java b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionParser.java new file mode 100644 index 0000000..e0bbe1e --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionParser.java @@ -0,0 +1,176 @@ +/* + * 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.definition; + +import com.google.common.base.Preconditions; + +import org.ros.exception.RosMessageRuntimeException; +import org.ros.internal.message.field.PrimitiveFieldType; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; + +/** + * Parses message definitions and invokes a {@link MessageDefinitionVisitor} for + * each field. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageDefinitionParser { + + private final MessageDefinitionVisitor visitor; + + public interface MessageDefinitionVisitor { + /** + * Called for each constant in the message definition. + * + * @param type + * the type of the constant + * @param name + * the name of the constant + * @param value + * the value of the constant + */ + void constantValue(String type, String name, String value); + + /** + * Called for each scalar in the message definition. + * + * @param type + * the type of the scalar + * @param name + * the name of the scalar + */ + void variableValue(String type, String name); + + /** + * Called for each array in the message definition. + * + * @param type + * the type of the array + * @param size + * the size of the array or -1 if the size is unbounded + * @param name + * the name of the array + */ + void variableList(String type, int size, String name); + } + + /** + * @param visitor + * the {@link MessageDefinitionVisitor} that will be called for each + * field + */ + public MessageDefinitionParser(MessageDefinitionVisitor visitor) { + this.visitor = visitor; + } + + /** + * Parses the message definition + * + * @param messageType + * the type of message defined (e.g. std_msgs/String) + * @param messageDefinition + * the message definition (e.g. "string data") + */ + public void parse(String messageType, String messageDefinition) { + Preconditions.checkNotNull(messageType); + Preconditions.checkNotNull(messageDefinition); + BufferedReader reader = new BufferedReader(new StringReader(messageDefinition)); + String line; + try { + while (true) { + line = reader.readLine(); + if (line == null) { + break; + } + line = line.trim(); + if (line.startsWith("#")) { + continue; + } + if (line.length() > 0) { + parseField(messageType, line); + } + } + } catch (IOException e) { + throw new RosMessageRuntimeException(e); + } + } + + private void parseField(String messageType, String fieldDefinition) { + // TODO(damonkohler): Regex input validation. + String[] typeAndName = fieldDefinition.split("\\s+", 2); + Preconditions.checkState(typeAndName.length == 2, + String.format("Invalid field definition: \"%s\"", fieldDefinition)); + String type = typeAndName[0]; + String name = typeAndName[1]; + String value = null; + if (name.contains("=") && (!name.contains("#") || name.indexOf('#') > name.indexOf('='))) { + String[] nameAndValue = name.split("=", 2); + name = nameAndValue[0].trim(); + value = nameAndValue[1].trim(); + } else if (name.contains("#")) { + // Stripping comments from constants is deferred until we also know the + // type since strings are handled differently. + Preconditions.checkState(!name.startsWith("#"), String.format( + "Fields must define a name. Field definition in %s was: \"%s\"", messageType, + fieldDefinition)); + name = name.substring(0, name.indexOf('#')); + name = name.trim(); + } + boolean array = false; + int size = -1; + if (type.endsWith("]")) { + int leftBracketIndex = type.lastIndexOf('['); + int rightBracketIndex = type.lastIndexOf(']'); + array = true; + if (rightBracketIndex - leftBracketIndex > 1) { + size = Integer.parseInt(type.substring(leftBracketIndex + 1, rightBracketIndex)); + } + type = type.substring(0, leftBracketIndex); + } + if (type.equals("Header")) { + // The header field is treated as though it were a built-in and silently + // expanded to "std_msgs/Header." + Preconditions.checkState(name.equals("header"), "Header field must be named \"header.\""); + type = "std_msgs/Header"; + } else if (!PrimitiveFieldType.existsFor(type) && !type.contains("/")) { + // Handle package relative message names. + type = messageType.substring(0, messageType.lastIndexOf('/') + 1) + type; + } + if (value != null) { + if (array) { + // TODO(damonkohler): Handle array constants? + throw new UnsupportedOperationException("Array constants are not supported."); + } + // Comments inline with string constants are treated as data. + if (!type.equals(PrimitiveFieldType.STRING.getName()) && value.contains("#")) { + Preconditions.checkState(!value.startsWith("#"), "Constants must define a value."); + value = value.substring(0, value.indexOf('#')); + value = value.trim(); + } + visitor.constantValue(type, name, value); + } else { + if (array) { + visitor.variableList(type, size, name); + } else { + visitor.variableValue(type, name); + } + } + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionProviderChain.java b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionProviderChain.java new file mode 100644 index 0000000..9bf71de --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionProviderChain.java @@ -0,0 +1,86 @@ +/* + * 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.definition; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageIdentifier; + +import java.util.Collection; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageDefinitionProviderChain implements MessageDefinitionProvider { + + private final Collection<MessageDefinitionProvider> messageDefinitionProviders; + + public MessageDefinitionProviderChain() { + messageDefinitionProviders = Lists.newArrayList(); + } + + public void addMessageDefinitionProvider(MessageDefinitionProvider messageDefinitionProvider) { + messageDefinitionProviders.add(messageDefinitionProvider); + } + + @Override + public String get(String messageType) { + for (MessageDefinitionProvider messageDefinitionProvider : messageDefinitionProviders) { + if (messageDefinitionProvider.has(messageType)) { + return messageDefinitionProvider.get(messageType); + } + } + throw new NoSuchElementException("No message definition available for: " + messageType); + } + + @Override + public boolean has(String messageType) { + for (MessageDefinitionProvider messageDefinitionProvider : messageDefinitionProviders) { + if (messageDefinitionProvider.has(messageType)) { + return true; + } + } + return false; + } + + @Override + public Collection<String> getPackages() { + Set<String> result = Sets.newHashSet(); + for (MessageDefinitionProvider messageDefinitionProvider : messageDefinitionProviders) { + Collection<String> packages = messageDefinitionProvider.getPackages(); + result.addAll(packages); + } + return result; + } + + @Override + public Collection<MessageIdentifier> getMessageIdentifiersByPackage(String pkg) { + Set<MessageIdentifier> result = Sets.newHashSet(); + for (MessageDefinitionProvider messageDefinitionProvider : messageDefinitionProviders) { + Collection<MessageIdentifier> messageIdentifiers = + messageDefinitionProvider.getMessageIdentifiersByPackage(pkg); + if (messageIdentifiers != null) { + result.addAll(messageIdentifiers); + } + } + return result; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionReflectionProvider.java b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionReflectionProvider.java new file mode 100644 index 0000000..6a5097e --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionReflectionProvider.java @@ -0,0 +1,88 @@ +/* + * 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.definition; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Maps; + +import org.ros.exception.RosMessageRuntimeException; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageIdentifier; + +import java.util.Collection; +import java.util.Map; + +/** + * A {@link MessageDefinitionProvider} that uses reflection to load the message + * definition {@link String} from a generated interface {@link Class}. + * <p> + * Note that this {@link MessageDefinitionProvider} does not support enumerating + * messages by package. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageDefinitionReflectionProvider implements MessageDefinitionProvider { + + private static final String DEFINITION_FIELD = "_DEFINITION"; + + private final Map<String, String> cache; + + public MessageDefinitionReflectionProvider() { + cache = Maps.newConcurrentMap(); + } + + @Override + public String get(String messageType) { + String messageDefinition = cache.get(messageType); + if (messageDefinition == null) { + String className = messageType.replace("/", "."); + try { + Class<?> loadedClass = getClass().getClassLoader().loadClass(className); + messageDefinition = (String) loadedClass.getDeclaredField(DEFINITION_FIELD).get(null); + cache.put(messageType, messageDefinition); + } catch (Exception e) { + throw new RosMessageRuntimeException(e); + } + } + return messageDefinition; + } + + @Override + public boolean has(String messageType) { + try { + get(messageType); + } catch (Exception e) { + return false; + } + return true; + } + + @Override + public Collection<String> getPackages() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<MessageIdentifier> getMessageIdentifiersByPackage(String pkg) { + throw new UnsupportedOperationException(); + } + + @VisibleForTesting + public void add(String messageType, String messageDefinition) { + cache.put(messageType, messageDefinition); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionTupleParser.java b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionTupleParser.java new file mode 100644 index 0000000..e7cdc9f --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/definition/MessageDefinitionTupleParser.java @@ -0,0 +1,68 @@ +/* + * 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.definition; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; + +import java.util.List; + +/** + * Splits message definitions tuples (e.g. service definitions) into separate + * message definitions. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageDefinitionTupleParser { + + private static final String SEPARATOR = "---"; + + /** + * Splits the message definition tuple into a {@link List} of message + * definitions. Split message definitions may be empty (e.g. std_srvs/Empty). + * + * @param definition + * the message definition tuple + * @param size + * the expected tuple size, or -1 to ignore this requirement + * @return a {@link List} of the specified size + */ + public static List<String> parse(String definition, int size) { + Preconditions.checkNotNull(definition); + List<String> definitions = Lists.newArrayList(); + StringBuilder current = new StringBuilder(); + for (String line : definition.split("\n")) { + if (line.startsWith(SEPARATOR)) { + definitions.add(current.toString()); + current = new StringBuilder(); + continue; + } + current.append(line); + current.append("\n"); + } + if (current.length() > 0) { + current.deleteCharAt(current.length() - 1); + } + definitions.add(current.toString()); + Preconditions.checkState(size == -1 || definitions.size() <= size, + String.format("Message tuple exceeds expected size: %d > %d", definitions.size(), size)); + while (definitions.size() < size) { + definitions.add(""); + } + return definitions; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/BooleanArrayField.java b/message_generator/src/main/java/org/ros/internal/message/field/BooleanArrayField.java new file mode 100644 index 0000000..75a9fe1 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/BooleanArrayField.java @@ -0,0 +1,117 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.Arrays; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class BooleanArrayField extends Field { + + private final int size; + + private boolean[] value; + + public static BooleanArrayField newVariable(String name, int size) { + return new BooleanArrayField(PrimitiveFieldType.BOOL, name, size); + } + + private BooleanArrayField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + setValue(new boolean[Math.max(0, size)]); + } + + @SuppressWarnings("unchecked") + @Override + public boolean[] getValue() { + return value; + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(size < 0 || ((boolean[]) value).length == size); + this.value = (boolean[]) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.length); + } + for (boolean v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = new boolean[currentSize]; + for (int i = 0; i < currentSize; i++) { + value[i] = buffer.readByte() == 1; + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName() + "[]"; + } + + @Override + public String toString() { + return "BooleanArrayField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + BooleanArrayField other = (BooleanArrayField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/ByteArrayField.java b/message_generator/src/main/java/org/ros/internal/message/field/ByteArrayField.java new file mode 100644 index 0000000..02e08bf --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/ByteArrayField.java @@ -0,0 +1,117 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.Arrays; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ByteArrayField extends Field { + + private final int size; + + private byte[] value; + + public static ByteArrayField newVariable(FieldType type, String name, int size) { + return new ByteArrayField(type, name, size); + } + + private ByteArrayField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + setValue(new byte[Math.max(0, size)]); + } + + @SuppressWarnings("unchecked") + @Override + public byte[] getValue() { + return value; + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(size < 0 || ((byte[]) value).length == size); + this.value = (byte[]) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.length); + } + for (byte v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = new byte[currentSize]; + for (int i = 0; i < currentSize; i++) { + value[i] = buffer.readByte(); + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName() + "[]"; + } + + @Override + public String toString() { + return "ByteArrayField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + ByteArrayField other = (ByteArrayField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/ChannelBufferField.java b/message_generator/src/main/java/org/ros/internal/message/field/ChannelBufferField.java new file mode 100644 index 0000000..a13f542 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/ChannelBufferField.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2012 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.ros.internal.message.MessageBuffers; + +import java.nio.ByteOrder; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ChannelBufferField extends Field { + + private final int size; + + private ChannelBuffer value; + + public static ChannelBufferField newVariable(FieldType type, String name, int size) { + return new ChannelBufferField(type, name, size); + } + + private ChannelBufferField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + value = MessageBuffers.dynamicBuffer(); + } + + @SuppressWarnings("unchecked") + @Override + public ChannelBuffer getValue() { + // Return a defensive duplicate. Unlike with copy(), duplicated + // ChannelBuffers share the same backing array, so this is relatively cheap. + return value.duplicate(); + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(((ChannelBuffer) value).order() == ByteOrder.LITTLE_ENDIAN); + Preconditions.checkArgument(size < 0 || ((ChannelBuffer) value).readableBytes() == size); + this.value = (ChannelBuffer) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.readableBytes()); + } + // By specifying the start index and length we avoid modifying value's + // indices and marks. + buffer.writeBytes(value, 0, value.readableBytes()); + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = buffer.readSlice(currentSize); + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return "org.jboss.netty.buffer.ChannelBuffer"; + } + + @Override + public String toString() { + return "ChannelBufferField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + ChannelBufferField other = (ChannelBufferField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/DoubleArrayField.java b/message_generator/src/main/java/org/ros/internal/message/field/DoubleArrayField.java new file mode 100644 index 0000000..a0c3945 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/DoubleArrayField.java @@ -0,0 +1,117 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.Arrays; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class DoubleArrayField extends Field { + + private final int size; + + private double[] value; + + public static DoubleArrayField newVariable(String name, int size) { + return new DoubleArrayField(PrimitiveFieldType.FLOAT64, name, size); + } + + private DoubleArrayField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + setValue(new double[Math.max(0, size)]); + } + + @SuppressWarnings("unchecked") + @Override + public double[] getValue() { + return value; + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(size < 0 || ((double[]) value).length == size); + this.value = (double[]) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.length); + } + for (double v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = new double[currentSize]; + for (int i = 0; i < currentSize; i++) { + value[i] = buffer.readDouble(); + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName() + "[]"; + } + + @Override + public String toString() { + return "DoubleArrayField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + DoubleArrayField other = (DoubleArrayField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/Field.java b/message_generator/src/main/java/org/ros/internal/message/field/Field.java new file mode 100644 index 0000000..d714dfc --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/Field.java @@ -0,0 +1,113 @@ +/* + * 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.field; + +import org.jboss.netty.buffer.ChannelBuffer; + + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public abstract class Field { + + protected final FieldType type; + protected final String name; + protected final boolean isConstant; + + protected Field(FieldType type, String name, boolean isConstant) { + this.name = name; + this.type = type; + this.isConstant = isConstant; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the type + */ + public FieldType getType() { + return type; + } + + /** + * @return <code>true</code> if this {@link ListField} represents a constant + */ + public boolean isConstant() { + return isConstant; + } + + /** + * @return the textual representation of this field used for computing the MD5 + * of a message definition + */ + public String getMd5String() { + if (isConstant()) { + return String.format("%s %s=%s\n", getType().getMd5String(), getName(), getValue()); + } + return String.format("%s %s\n", getType().getMd5String(), getName()); + } + + public abstract void serialize(ChannelBuffer buffer); + + public abstract void deserialize(ChannelBuffer buffer); + + public abstract <T> T getValue(); + + // TODO(damonkohler): Why not make Field generic? + public abstract void setValue(Object value); + + public abstract String getJavaTypeName(); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (isConstant ? 1231 : 1237); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Field other = (Field) obj; + if (isConstant != other.isConstant) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equals(other.type)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/FieldFactory.java b/message_generator/src/main/java/org/ros/internal/message/field/FieldFactory.java new file mode 100644 index 0000000..24b3053 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/FieldFactory.java @@ -0,0 +1,25 @@ +/* + * 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.field; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface FieldFactory { + + Field create(); +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/FieldType.java b/message_generator/src/main/java/org/ros/internal/message/field/FieldType.java new file mode 100644 index 0000000..b227b4d --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/FieldType.java @@ -0,0 +1,50 @@ +/* + * 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.field; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface FieldType { + + public <T> T getDefaultValue(); + + public String getName(); + + public <T> T parseFromString(String value); + + public String getMd5String(); + + public String getJavaTypeName(); + + /** + * @return the serialized size of this {@link FieldType} in bytes + */ + public int getSerializedSize(); + + public <T> void serialize(T value, ChannelBuffer buffer); + + public <T> T deserialize(ChannelBuffer buffer); + + public Field newVariableValue(String name); + + public Field newVariableList(String name, int size); + + public <T> Field newConstantValue(String name, T value); +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/FloatArrayField.java b/message_generator/src/main/java/org/ros/internal/message/field/FloatArrayField.java new file mode 100644 index 0000000..fcbf50c --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/FloatArrayField.java @@ -0,0 +1,117 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.Arrays; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class FloatArrayField extends Field { + + private final int size; + + private float[] value; + + public static FloatArrayField newVariable(String name, int size) { + return new FloatArrayField(PrimitiveFieldType.FLOAT32, name, size); + } + + private FloatArrayField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + setValue(new float[Math.max(0, size)]); + } + + @SuppressWarnings("unchecked") + @Override + public float[] getValue() { + return value; + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(size < 0 || ((float[]) value).length == size); + this.value = (float[]) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.length); + } + for (float v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = new float[currentSize]; + for (int i = 0; i < currentSize; i++) { + value[i] = buffer.readFloat(); + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName() + "[]"; + } + + @Override + public String toString() { + return "FloatArrayField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + FloatArrayField other = (FloatArrayField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/IntegerArrayField.java b/message_generator/src/main/java/org/ros/internal/message/field/IntegerArrayField.java new file mode 100644 index 0000000..adb0753 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/IntegerArrayField.java @@ -0,0 +1,117 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.Arrays; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class IntegerArrayField extends Field { + + private final int size; + + private int[] value; + + public static IntegerArrayField newVariable(FieldType type, String name, int size) { + return new IntegerArrayField(type, name, size); + } + + private IntegerArrayField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + setValue(new int[Math.max(0, size)]); + } + + @SuppressWarnings("unchecked") + @Override + public int[] getValue() { + return value; + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(size < 0 || ((int[]) value).length == size); + this.value = (int[]) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.length); + } + for (int v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = new int[currentSize]; + for (int i = 0; i < currentSize; i++) { + value[i] = buffer.readInt(); + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName() + "[]"; + } + + @Override + public String toString() { + return "IntegerArrayField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + IntegerArrayField other = (IntegerArrayField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/ListField.java b/message_generator/src/main/java/org/ros/internal/message/field/ListField.java new file mode 100644 index 0000000..4f4caeb --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/ListField.java @@ -0,0 +1,115 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author damonkohler@google.com (Damon Kohler) + * + * @param <T> + * the value type + */ +public class ListField<T> extends Field { + + private List<T> value; + + public static <T> ListField<T> newVariable(FieldType type, String name) { + return new ListField<T>(type, name); + } + + private ListField(FieldType type, String name) { + super(type, name, false); + value = new ArrayList<T>(); + } + + @SuppressWarnings("unchecked") + @Override + public List<T> getValue() { + return value; + } + + @SuppressWarnings("unchecked") + @Override + public void setValue(Object value) { + Preconditions.checkNotNull(value); + this.value = (List<T>) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + buffer.writeInt(value.size()); + for (T v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + value.clear(); + int size = buffer.readInt(); + for (int i = 0; i < size; i++) { + value.add(type.<T>deserialize(buffer)); + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return String.format("java.util.List<%s>", type.getJavaTypeName()); + } + + @Override + public String toString() { + return "ListField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @SuppressWarnings("rawtypes") + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + ListField other = (ListField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/LongArrayField.java b/message_generator/src/main/java/org/ros/internal/message/field/LongArrayField.java new file mode 100644 index 0000000..8c2a611 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/LongArrayField.java @@ -0,0 +1,119 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.Arrays; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class LongArrayField extends Field { + + private final int size; + + private long[] value; + + public static LongArrayField newVariable(FieldType type, String name, int size) { + Preconditions.checkArgument(type.equals(PrimitiveFieldType.UINT32) + || type.equals(PrimitiveFieldType.INT64) || type.equals(PrimitiveFieldType.UINT64)); + return new LongArrayField(type, name, size); + } + + private LongArrayField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + setValue(new long[Math.max(0, size)]); + } + + @SuppressWarnings("unchecked") + @Override + public long[] getValue() { + return value; + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(size < 0 || ((long[]) value).length == size); + this.value = (long[]) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.length); + } + for (long v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = new long[currentSize]; + for (int i = 0; i < currentSize; i++) { + value[i] = buffer.readLong(); + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName() + "[]"; + } + + @Override + public String toString() { + return "LongArrayField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + LongArrayField other = (LongArrayField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/MessageFieldType.java b/message_generator/src/main/java/org/ros/internal/message/field/MessageFieldType.java new file mode 100644 index 0000000..b70e6fa --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/MessageFieldType.java @@ -0,0 +1,136 @@ +/* + * 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.field; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.ros.internal.message.DefaultMessageDeserializer; +import org.ros.internal.message.DefaultMessageSerializer; +import org.ros.internal.message.Message; +import org.ros.message.MessageDeserializer; +import org.ros.message.MessageFactory; +import org.ros.message.MessageIdentifier; +import org.ros.message.MessageSerializer; + + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageFieldType implements FieldType { + + private final MessageIdentifier messageIdentifier; + private final MessageFactory messageFactory; + private final MessageSerializer<Message> serializer; + private final MessageDeserializer<Message> deserializer; + + public MessageFieldType(MessageIdentifier messageIdentifier, MessageFactory messageFactory) { + this.messageIdentifier = messageIdentifier; + this.messageFactory = messageFactory; + serializer = new DefaultMessageSerializer(); + deserializer = new DefaultMessageDeserializer<Message>(messageIdentifier, messageFactory); + } + + public MessageFactory getMessageFactory() { + return messageFactory; + } + + @Override + public Field newVariableValue(String name) { + return ValueField.newVariable(this, name); + } + + @Override + public <T> Field newConstantValue(String name, T value) { + throw new UnsupportedOperationException(); + } + + @Override + public Field newVariableList(String name, int size) { + return ListField.newVariable(this, name); + } + + @Override + public <T> T getDefaultValue() { + return getMessageFactory().newFromType(messageIdentifier.getType()); + } + + @Override + public String getMd5String() { + return null; + } + + @Override + public String getJavaTypeName() { + return String.format("%s.%s", messageIdentifier.getPackage(), messageIdentifier.getName()); + } + + @Override + public int getSerializedSize() { + throw new UnsupportedOperationException(); + } + + @Override + public String getName() { + return messageIdentifier.getType(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + serializer.serialize((Message) value, buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Message deserialize(ChannelBuffer buffer) { + return deserializer.deserialize(buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Void parseFromString(String value) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return "MessageField<" + messageIdentifier + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((messageIdentifier == null) ? 0 : messageIdentifier.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MessageFieldType other = (MessageFieldType) obj; + if (messageIdentifier == null) { + if (other.messageIdentifier != null) + return false; + } else if (!messageIdentifier.equals(other.messageIdentifier)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/MessageFields.java b/message_generator/src/main/java/org/ros/internal/message/field/MessageFields.java new file mode 100644 index 0000000..c79f3f3 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/MessageFields.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2012 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.field; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import org.ros.exception.RosMessageRuntimeException; +import org.ros.internal.message.context.MessageContext; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageFields { + + private final Map<String, Field> fields; + private final Map<String, Field> setters; + private final Map<String, Field> getters; + private final List<Field> orderedFields; + + public MessageFields(MessageContext messageContext) { + fields = Maps.newHashMap(); + setters = Maps.newHashMap(); + getters = Maps.newHashMap(); + orderedFields = Lists.newArrayList(); + for (String name : messageContext.getFieldNames()) { + Field field = messageContext.getFieldFactory(name).create(); + fields.put(name, field); + getters.put(messageContext.getFieldGetterName(name), field); + setters.put(messageContext.getFieldSetterName(name), field); + orderedFields.add(field); + } + } + + public Field getField(String name) { + return fields.get(name); + } + + public Field getSetterField(String name) { + return setters.get(name); + } + + public Field getGetterField(String name) { + return getters.get(name); + } + + public List<Field> getFields() { + return Collections.unmodifiableList(orderedFields); + } + + public Object getFieldValue(String name) { + Field field = fields.get(name); + if (field != null) { + return field.getValue(); + } + throw new RosMessageRuntimeException("Uknown field: " + name); + } + + public void setFieldValue(String name, Object value) { + Field field = fields.get(name); + if (field != null) { + field.setValue(value); + } else { + throw new RosMessageRuntimeException("Uknown field: " + name); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((fields == null) ? 0 : fields.hashCode()); + result = prime * result + ((orderedFields == null) ? 0 : orderedFields.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MessageFields other = (MessageFields) obj; + if (fields == null) { + if (other.fields != null) + return false; + } else if (!fields.equals(other.fields)) + return false; + if (orderedFields == null) { + if (other.orderedFields != null) + return false; + } else if (!orderedFields.equals(other.orderedFields)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/PrimitiveFieldType.java b/message_generator/src/main/java/org/ros/internal/message/field/PrimitiveFieldType.java new file mode 100644 index 0000000..bed4916 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/PrimitiveFieldType.java @@ -0,0 +1,714 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.ros.message.Duration; +import org.ros.message.Time; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public enum PrimitiveFieldType implements FieldType { + + BOOL { + @SuppressWarnings("unchecked") + @Override + public Boolean getDefaultValue() { + return Boolean.FALSE; + } + + @Override + public BooleanArrayField newVariableList(String name, int size) { + return BooleanArrayField.newVariable(name, size); + } + + @Override + public int getSerializedSize() { + return 1; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Boolean); + buffer.writeByte((byte) ((Boolean) value ? 1 : 0)); + } + + @SuppressWarnings("unchecked") + @Override + public Boolean deserialize(ChannelBuffer buffer) { + return buffer.readByte() == 1; + } + + @SuppressWarnings("unchecked") + @Override + public Boolean parseFromString(String value) { + return value.equals("1"); + } + + @Override + public String getJavaTypeName() { + return "boolean"; + } + }, + INT8 { + @SuppressWarnings("unchecked") + @Override + public Byte getDefaultValue() { + return Byte.valueOf((byte) 0); + } + + @Override + public Field newVariableList(String name, int size) { + return ChannelBufferField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return 1; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Byte); + buffer.writeByte((Byte) value); + } + + @SuppressWarnings("unchecked") + @Override + public Byte deserialize(ChannelBuffer buffer) { + return buffer.readByte(); + } + + @SuppressWarnings("unchecked") + @Override + public Byte parseFromString(String value) { + return Byte.parseByte(value); + } + + @Override + public String getJavaTypeName() { + return "byte"; + } + }, + /** + * @deprecated replaced by {@link PrimitiveFieldType#INT8} + */ + BYTE { + @SuppressWarnings("unchecked") + @Override + public Byte getDefaultValue() { + return INT8.getDefaultValue(); + } + + @Override + public Field newVariableList(String name, int size) { + return ChannelBufferField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return INT8.getSerializedSize(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + INT8.serialize(value, buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Byte deserialize(ChannelBuffer buffer) { + return INT8.deserialize(buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Byte parseFromString(String value) { + return INT8.parseFromString(value); + } + + @Override + public String getJavaTypeName() { + return INT8.getJavaTypeName(); + } + }, + UINT8 { + @SuppressWarnings("unchecked") + @Override + public Byte getDefaultValue() { + return INT8.getDefaultValue(); + } + + @Override + public Field newVariableList(String name, int size) { + return ChannelBufferField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return INT8.getSerializedSize(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + INT8.serialize(value, buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Byte deserialize(ChannelBuffer buffer) { + return INT8.deserialize(buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Byte parseFromString(String value) { + return (byte) Short.parseShort(value); + } + + @Override + public String getJavaTypeName() { + return INT8.getJavaTypeName(); + } + }, + /** + * @deprecated replaced by {@link PrimitiveFieldType#UINT8} + */ + CHAR { + @SuppressWarnings("unchecked") + @Override + public Byte getDefaultValue() { + return UINT8.getDefaultValue(); + } + + @Override + public Field newVariableList(String name, int size) { + return ChannelBufferField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return UINT8.getSerializedSize(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + UINT8.serialize(value, buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Byte deserialize(ChannelBuffer buffer) { + return UINT8.deserialize(buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Byte parseFromString(String value) { + return UINT8.parseFromString(value); + } + + @Override + public String getJavaTypeName() { + return UINT8.getJavaTypeName(); + } + }, + INT16 { + @SuppressWarnings("unchecked") + @Override + public Short getDefaultValue() { + return Short.valueOf((short) 0); + } + + @Override + public Field newVariableList(String name, int size) { + return ShortArrayField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return 2; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Short); + buffer.writeShort((Short) value); + } + + @SuppressWarnings("unchecked") + @Override + public Short deserialize(ChannelBuffer buffer) { + return buffer.readShort(); + } + + @SuppressWarnings("unchecked") + @Override + public Short parseFromString(String value) { + return Short.parseShort(value); + } + + @Override + public String getJavaTypeName() { + return "short"; + } + }, + UINT16 { + @SuppressWarnings("unchecked") + @Override + public Short getDefaultValue() { + return INT16.getDefaultValue(); + } + + @Override + public Field newVariableList(String name, int size) { + return ShortArrayField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return INT16.getSerializedSize(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + INT16.serialize(value, buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Short deserialize(ChannelBuffer buffer) { + return INT16.deserialize(buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Short parseFromString(String value) { + return (short) Integer.parseInt(value); + } + + @Override + public String getJavaTypeName() { + return INT16.getJavaTypeName(); + } + }, + INT32 { + @SuppressWarnings("unchecked") + @Override + public Integer getDefaultValue() { + return Integer.valueOf(0); + } + + @Override + public Field newVariableList(String name, int size) { + return IntegerArrayField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return 4; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Integer); + buffer.writeInt((Integer) value); + } + + @SuppressWarnings("unchecked") + @Override + public Integer deserialize(ChannelBuffer buffer) { + return buffer.readInt(); + } + + @SuppressWarnings("unchecked") + @Override + public Integer parseFromString(String value) { + return Integer.parseInt(value); + } + + @Override + public String getJavaTypeName() { + return "int"; + } + }, + UINT32 { + @SuppressWarnings("unchecked") + @Override + public Integer getDefaultValue() { + return INT32.getDefaultValue(); + } + + @Override + public Field newVariableList(String name, int size) { + return IntegerArrayField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return INT32.getSerializedSize(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + INT32.serialize(value, buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Integer deserialize(ChannelBuffer buffer) { + return INT32.deserialize(buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Integer parseFromString(String value) { + return (int) Long.parseLong(value); + } + + @Override + public String getJavaTypeName() { + return INT32.getJavaTypeName(); + } + }, + INT64 { + @SuppressWarnings("unchecked") + @Override + public Long getDefaultValue() { + return Long.valueOf(0); + } + + @Override + public Field newVariableList(String name, int size) { + return LongArrayField.newVariable(this, name, size); + } + + @Override + public int getSerializedSize() { + return 8; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Long); + buffer.writeLong((Long) value); + } + + @SuppressWarnings("unchecked") + @Override + public Long deserialize(ChannelBuffer buffer) { + return buffer.readLong(); + } + + @SuppressWarnings("unchecked") + @Override + public Long parseFromString(String value) { + return Long.parseLong(value); + } + + @Override + public String getJavaTypeName() { + return "long"; + } + }, + UINT64 { + @SuppressWarnings("unchecked") + @Override + public Long getDefaultValue() { + return INT64.getDefaultValue(); + } + + @Override + public Field newVariableList(String name, int size) { + return INT64.newVariableList(name, size); + } + + @Override + public int getSerializedSize() { + return INT64.getSerializedSize(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + INT64.serialize(value, buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Long deserialize(ChannelBuffer buffer) { + return INT64.deserialize(buffer); + } + + @SuppressWarnings("unchecked") + @Override + public Long parseFromString(String value) { + return INT64.parseFromString(value); + } + + @Override + public String getJavaTypeName() { + return INT64.getJavaTypeName(); + } + }, + FLOAT32 { + @SuppressWarnings("unchecked") + @Override + public Float getDefaultValue() { + return Float.valueOf(0); + } + + @Override + public Field newVariableList(String name, int size) { + return FloatArrayField.newVariable(name, size); + } + + @Override + public int getSerializedSize() { + return 4; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Float); + buffer.writeFloat((Float) value); + } + + @SuppressWarnings("unchecked") + @Override + public Float deserialize(ChannelBuffer buffer) { + return buffer.readFloat(); + } + + @SuppressWarnings("unchecked") + @Override + public Float parseFromString(String value) { + return Float.parseFloat(value); + } + + @Override + public String getJavaTypeName() { + return "float"; + } + }, + FLOAT64 { + @SuppressWarnings("unchecked") + @Override + public Double getDefaultValue() { + return Double.valueOf(0); + } + + @Override + public int getSerializedSize() { + return 8; + } + + @Override + public Field newVariableList(String name, int size) { + return DoubleArrayField.newVariable(name, size); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Double); + buffer.writeDouble((Double) value); + } + + @SuppressWarnings("unchecked") + @Override + public Double deserialize(ChannelBuffer buffer) { + return buffer.readDouble(); + } + + @SuppressWarnings("unchecked") + @Override + public Double parseFromString(String value) { + return Double.parseDouble(value); + } + + @Override + public String getJavaTypeName() { + return "double"; + } + }, + STRING { + @SuppressWarnings("unchecked") + @Override + public String getDefaultValue() { + return ""; + } + + @Override + public Field newVariableList(String name, int size) { + return ListField.newVariable(this, name); + } + + @Override + public int getSerializedSize() { + throw new UnsupportedOperationException(); + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof String); + byte[] bytes = ((String) value).getBytes(); + buffer.writeInt(bytes.length); + buffer.writeBytes(bytes); + } + + @SuppressWarnings("unchecked") + @Override + public String deserialize(ChannelBuffer buffer) { + int length = buffer.readInt(); + ByteBuffer stringBuffer = buffer.readSlice(length).toByteBuffer(); + return Charset.forName("US-ASCII").decode(stringBuffer).toString(); + } + + @SuppressWarnings("unchecked") + @Override + public String parseFromString(String value) { + return value; + } + + @Override + public String getJavaTypeName() { + return "java.lang.String"; + } + }, + TIME { + @SuppressWarnings("unchecked") + @Override + public Time getDefaultValue() { + return new Time(); + } + + @Override + public Field newVariableList(String name, int size) { + return ListField.newVariable(this, name); + } + + @Override + public int getSerializedSize() { + return 8; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Time); + buffer.writeInt(((Time) value).secs); + buffer.writeInt(((Time) value).nsecs); + } + + @SuppressWarnings("unchecked") + @Override + public Time deserialize(ChannelBuffer buffer) { + return new Time(buffer.readInt(), buffer.readInt()); + } + + @SuppressWarnings("unchecked") + @Override + public Void parseFromString(String value) { + throw new UnsupportedOperationException(); + } + + @Override + public String getJavaTypeName() { + return Time.class.getName(); + } + }, + DURATION { + @SuppressWarnings("unchecked") + @Override + public Duration getDefaultValue() { + return new Duration(); + } + + @Override + public Field newVariableList(String name, int size) { + return ListField.newVariable(this, name); + } + + @Override + public int getSerializedSize() { + return 8; + } + + @Override + public <T> void serialize(T value, ChannelBuffer buffer) { + Preconditions.checkArgument(value instanceof Duration); + buffer.writeInt(((Duration) value).secs); + buffer.writeInt(((Duration) value).nsecs); + } + + @SuppressWarnings("unchecked") + @Override + public Duration deserialize(ChannelBuffer buffer) { + return new Duration(buffer.readInt(), buffer.readInt()); + } + + @SuppressWarnings("unchecked") + @Override + public Void parseFromString(String value) { + throw new UnsupportedOperationException(); + } + + @Override + public String getJavaTypeName() { + return Duration.class.getName(); + } + }; + + private static final ImmutableSet<String> TYPE_NAMES; + + static { + ImmutableSet.Builder<String> builder = ImmutableSet.<String>builder(); + for (PrimitiveFieldType type : values()) { + builder.add(type.getName()); + } + TYPE_NAMES = builder.build(); + } + + public static boolean existsFor(String name) { + return TYPE_NAMES.contains(name); + } + + @Override + public Field newVariableValue(String name) { + return ValueField.newVariable(this, name); + } + + @Override + public <T> Field newConstantValue(String name, T value) { + return ValueField.newConstant(this, name, value); + } + + @Override + public String getName() { + return toString().toLowerCase(); + } + + @Override + public String getMd5String() { + return getName(); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/ShortArrayField.java b/message_generator/src/main/java/org/ros/internal/message/field/ShortArrayField.java new file mode 100644 index 0000000..e77b72a --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/ShortArrayField.java @@ -0,0 +1,117 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +import java.util.Arrays; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ShortArrayField extends Field { + + private final int size; + + private short[] value; + + public static ShortArrayField newVariable(FieldType type, String name, int size) { + return new ShortArrayField(type, name, size); + } + + private ShortArrayField(FieldType type, String name, int size) { + super(type, name, false); + this.size = size; + setValue(new short[Math.max(0, size)]); + } + + @SuppressWarnings("unchecked") + @Override + public short[] getValue() { + return value; + } + + @Override + public void setValue(Object value) { + Preconditions.checkArgument(size < 0 || ((short[]) value).length == size); + this.value = (short[]) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + if (size < 0) { + buffer.writeInt(value.length); + } + for (short v : value) { + type.serialize(v, buffer); + } + } + + @Override + public void deserialize(ChannelBuffer buffer) { + int currentSize = size; + if (currentSize < 0) { + currentSize = buffer.readInt(); + } + value = new short[currentSize]; + for (int i = 0; i < currentSize; i++) { + value[i] = buffer.readShort(); + } + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName() + "[]"; + } + + @Override + public String toString() { + return "ShortArrayField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + ShortArrayField other = (ShortArrayField) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!Arrays.equals(value, other.value)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/field/ValueField.java b/message_generator/src/main/java/org/ros/internal/message/field/ValueField.java new file mode 100644 index 0000000..d2baacf --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/field/ValueField.java @@ -0,0 +1,110 @@ +/* + * 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.field; + +import com.google.common.base.Preconditions; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +class ValueField<T> extends Field { + + private T value; + + static <T> ValueField<T> newConstant(FieldType type, String name, T value) { + return new ValueField<T>(type, name, value, true); + } + + static <T> ValueField<T> newVariable(FieldType type, String name) { + return new ValueField<T>(type, name, null, false); + } + + private ValueField(FieldType type, String name, T value, boolean isConstant) { + super(type, name, isConstant); + this.value = value; + } + + @SuppressWarnings("unchecked") + @Override + public T getValue() { + if (value == null) { + setValue(type.getDefaultValue()); + } + return value; + } + + @SuppressWarnings("unchecked") + @Override + public void setValue(Object value) { + Preconditions.checkNotNull(value); + Preconditions.checkState(!isConstant); + this.value = (T) value; + } + + @Override + public void serialize(ChannelBuffer buffer) { + type.serialize(getValue(), buffer); + } + + @Override + public void deserialize(ChannelBuffer buffer) { + Preconditions.checkState(!isConstant); + setValue(type.<T>deserialize(buffer)); + } + + @Override + public String getMd5String() { + return String.format("%s %s\n", type, name); + } + + @Override + public String getJavaTypeName() { + return type.getJavaTypeName(); + } + + @Override + public String toString() { + return "ValueField<" + type + ", " + name + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((getValue() == null) ? 0 : getValue().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + Field other = (Field) obj; + if (getValue() == null) { + if (other.getValue() != null) + return false; + } else if (!getValue().equals(other.getValue())) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/package-info.java b/message_generator/src/main/java/org/ros/internal/message/package-info.java new file mode 100644 index 0000000..a59b1c8 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 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. + */ + +/** + * Provides internal classes for representing messages. + * <p> + * These classes should _not_ be used directly outside of the org.ros package. + */ +package org.ros.internal.message; \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionFileProvider.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionFileProvider.java new file mode 100644 index 0000000..31b258f --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionFileProvider.java @@ -0,0 +1,51 @@ +/* + * 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.service; + +import org.ros.internal.message.definition.MessageDefinitionFileProvider; + +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.ros.internal.message.StringFileProvider; + +import java.io.File; +import java.io.FileFilter; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceDefinitionFileProvider extends MessageDefinitionFileProvider { + + private static final String PARENT = "srv"; + private static final String SUFFIX = "srv"; + + private static StringFileProvider newStringFileProvider() { + IOFileFilter extensionFilter = FileFilterUtils.suffixFileFilter(SUFFIX); + IOFileFilter parentBaseNameFilter = FileFilterUtils.asFileFilter(new FileFilter() { + @Override + public boolean accept(File file) { + return getParentBaseName(file.getAbsolutePath()).equals(PARENT); + } + }); + IOFileFilter fileFilter = FileFilterUtils.andFileFilter(extensionFilter, parentBaseNameFilter); + return new StringFileProvider(fileFilter); + } + + public ServiceDefinitionFileProvider() { + super(newStringFileProvider()); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionResourceProvider.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionResourceProvider.java new file mode 100644 index 0000000..af35e3f --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDefinitionResourceProvider.java @@ -0,0 +1,69 @@ +/* + * 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.service; + +import com.google.common.base.Preconditions; + +import org.ros.internal.message.StringResourceProvider; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageIdentifier; + +import java.util.Collection; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceDefinitionResourceProvider implements MessageDefinitionProvider { + + private final StringResourceProvider stringResourceProvider; + + public ServiceDefinitionResourceProvider() { + stringResourceProvider = new StringResourceProvider(); + } + + private String serviceTypeToResourceName(String serviceType) { + Preconditions.checkArgument(serviceType.contains("/"), "Service type must be fully qualified: " + + serviceType); + String[] packageAndType = serviceType.split("/", 2); + return String.format("/%s/srv/%s.srv", packageAndType[0], packageAndType[1]); + } + + @Override + public String get(String serviceType) { + return stringResourceProvider.get(serviceTypeToResourceName(serviceType)); + } + + @Override + public boolean has(String serviceType) { + return stringResourceProvider.has(serviceTypeToResourceName(serviceType)); + } + + public void add(String serviceType, String serviceDefinition) { + stringResourceProvider.addStringToCache(serviceTypeToResourceName(serviceType), + serviceDefinition); + } + + @Override + public Collection<String> getPackages() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<MessageIdentifier> getMessageIdentifiersByPackage(String pkg) { + throw new UnsupportedOperationException(); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceDescription.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDescription.java new file mode 100644 index 0000000..95251a0 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDescription.java @@ -0,0 +1,98 @@ +/* + * 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.service; + +import org.ros.internal.message.definition.MessageDefinitionTupleParser; + +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageIdentifier; + +import java.util.List; + +/** + * The description of a ROS service. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceDescription extends MessageDeclaration { + + private final String requestType; + private final String requestDefinition; + private final String responseType; + private final String responseDefinition; + private final String md5Checksum; + + public ServiceDescription(String type, String definition, String md5Checksum) { + super(MessageIdentifier.of(type), definition); + this.md5Checksum = md5Checksum; + List<String> requestAndResponse = MessageDefinitionTupleParser.parse(definition, 2); + requestType = type + "Request"; + responseType = type + "Response"; + requestDefinition = requestAndResponse.get(0); + responseDefinition = requestAndResponse.get(1); + } + + public String getMd5Checksum() { + return md5Checksum; + } + + public String getRequestType() { + return requestType; + } + + public String getRequestDefinition() { + return requestDefinition; + } + + public String getResponseType() { + return responseType; + } + + public String getResponseDefinition() { + return responseDefinition; + } + + @Override + public String toString() { + return "ServiceDescription<" + getType() + ", " + md5Checksum + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((md5Checksum == null) ? 0 : md5Checksum.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + ServiceDescription other = (ServiceDescription) obj; + if (md5Checksum == null) { + if (other.md5Checksum != null) + return false; + } else if (!md5Checksum.equals(other.md5Checksum)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceDescriptionFactory.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDescriptionFactory.java new file mode 100644 index 0000000..269d402 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceDescriptionFactory.java @@ -0,0 +1,44 @@ +/* + * 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.service; + +import org.ros.internal.message.Md5Generator; +import org.ros.message.MessageDefinitionProvider; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceDescriptionFactory { + + private final MessageDefinitionProvider messageDefinitionProvider; + private final Md5Generator md5Generator; + + public ServiceDescriptionFactory(MessageDefinitionProvider messageDefinitionProvider) { + this.messageDefinitionProvider = messageDefinitionProvider; + md5Generator = new Md5Generator(messageDefinitionProvider); + } + + public ServiceDescription newFromType(String serviceType) { + String serviceDefinition = messageDefinitionProvider.get(serviceType); + String md5Checksum = md5Generator.generate(serviceType); + return new ServiceDescription(serviceType, serviceDefinition, md5Checksum); + } + + public boolean hasType(String serviceType) { + return messageDefinitionProvider.has(serviceType); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageFactory.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageFactory.java new file mode 100644 index 0000000..862b20d --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageFactory.java @@ -0,0 +1,50 @@ +/* + * 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.service; + +import org.ros.internal.message.DefaultMessageFactory; +import org.ros.internal.message.DefaultMessageInterfaceClassProvider; +import org.ros.internal.message.MessageProxyFactory; +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageFactory; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceRequestMessageFactory implements MessageFactory { + + private final ServiceDescriptionFactory serviceDescriptionFactory; + private final MessageFactory messageFactory; + private final MessageProxyFactory messageProxyFactory; + + public ServiceRequestMessageFactory(MessageDefinitionProvider messageDefinitionProvider) { + serviceDescriptionFactory = new ServiceDescriptionFactory(messageDefinitionProvider); + messageFactory = new DefaultMessageFactory(messageDefinitionProvider); + messageProxyFactory = + new MessageProxyFactory(new DefaultMessageInterfaceClassProvider(), messageFactory); + } + + @Override + public <T> T newFromType(String serviceType) { + ServiceDescription serviceDescription = serviceDescriptionFactory.newFromType(serviceType); + MessageDeclaration messageDeclaration = + MessageDeclaration.of(serviceDescription.getRequestType(), + serviceDescription.getRequestDefinition()); + return messageProxyFactory.newMessageProxy(messageDeclaration); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageInterfaceClassProvider.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageInterfaceClassProvider.java new file mode 100644 index 0000000..24b4b52 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceRequestMessageInterfaceClassProvider.java @@ -0,0 +1,37 @@ +/* + * 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.service; + +import org.ros.internal.message.MessageInterfaceClassProvider; +import org.ros.internal.message.RawMessage; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceRequestMessageInterfaceClassProvider implements MessageInterfaceClassProvider { + + @SuppressWarnings("unchecked") + @Override + public <T> Class<T> get(String messageType) { + try { + String className = messageType.replace("/", ".") + "$Request"; + return (Class<T>) getClass().getClassLoader().loadClass(className); + } catch (ClassNotFoundException e) { + return (Class<T>) RawMessage.class; + } + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageFactory.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageFactory.java new file mode 100644 index 0000000..c325c44 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageFactory.java @@ -0,0 +1,50 @@ +/* + * 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.service; + +import org.ros.internal.message.DefaultMessageFactory; +import org.ros.internal.message.DefaultMessageInterfaceClassProvider; +import org.ros.internal.message.MessageProxyFactory; +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageFactory; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceResponseMessageFactory implements MessageFactory { + + private final ServiceDescriptionFactory serviceDescriptionFactory; + private final MessageFactory messageFactory; + private final MessageProxyFactory messageProxyFactory; + + public ServiceResponseMessageFactory(MessageDefinitionProvider messageDefinitionProvider) { + serviceDescriptionFactory = new ServiceDescriptionFactory(messageDefinitionProvider); + messageFactory = new DefaultMessageFactory(messageDefinitionProvider); + messageProxyFactory = + new MessageProxyFactory(new DefaultMessageInterfaceClassProvider(), messageFactory); + } + + @Override + public <T> T newFromType(String serviceType) { + ServiceDescription serviceDescription = serviceDescriptionFactory.newFromType(serviceType); + MessageDeclaration messageDeclaration = + MessageDeclaration.of(serviceDescription.getResponseType(), + serviceDescription.getResponseDefinition()); + return messageProxyFactory.newMessageProxy(messageDeclaration); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageInterfaceClassProvider.java b/message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageInterfaceClassProvider.java new file mode 100644 index 0000000..0e61fb9 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/ServiceResponseMessageInterfaceClassProvider.java @@ -0,0 +1,37 @@ +/* + * 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.service; + +import org.ros.internal.message.MessageInterfaceClassProvider; +import org.ros.internal.message.RawMessage; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class ServiceResponseMessageInterfaceClassProvider implements MessageInterfaceClassProvider { + + @SuppressWarnings("unchecked") + @Override + public <T> Class<T> get(String messageType) { + try { + String className = messageType.replace("/", ".") + "$Response"; + return (Class<T>) getClass().getClassLoader().loadClass(className); + } catch (ClassNotFoundException e) { + return (Class<T>) RawMessage.class; + } + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/service/package-info.java b/message_generator/src/main/java/org/ros/internal/message/service/package-info.java new file mode 100644 index 0000000..82c8038 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/service/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 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. + */ + +/** + * Provides internal classes for representing service messages. + * <p> + * These classes should _not_ be used directly outside of the org.ros package. + */ +package org.ros.internal.message.service; \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionFileProvider.java b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionFileProvider.java new file mode 100644 index 0000000..5cc8e1e --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionFileProvider.java @@ -0,0 +1,51 @@ +/* + * 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.topic; + +import org.ros.internal.message.definition.MessageDefinitionFileProvider; + +import org.apache.commons.io.filefilter.FileFilterUtils; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.ros.internal.message.StringFileProvider; + +import java.io.File; +import java.io.FileFilter; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class TopicDefinitionFileProvider extends MessageDefinitionFileProvider { + + private static final String PARENT = "msg"; + private static final String SUFFIX = "msg"; + + private static StringFileProvider newStringFileProvider() { + IOFileFilter extensionFilter = FileFilterUtils.suffixFileFilter(SUFFIX); + IOFileFilter parentBaseNameFilter = FileFilterUtils.asFileFilter(new FileFilter() { + @Override + public boolean accept(File file) { + return getParentBaseName(file.getAbsolutePath()).equals(PARENT); + } + }); + IOFileFilter fileFilter = FileFilterUtils.andFileFilter(extensionFilter, parentBaseNameFilter); + return new StringFileProvider(fileFilter); + } + + public TopicDefinitionFileProvider() { + super(newStringFileProvider()); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionResourceProvider.java b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionResourceProvider.java new file mode 100644 index 0000000..08dce89 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDefinitionResourceProvider.java @@ -0,0 +1,68 @@ +/* + * 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.topic; + +import com.google.common.annotations.VisibleForTesting; + +import org.ros.internal.message.StringResourceProvider; +import org.ros.message.MessageDefinitionProvider; +import org.ros.message.MessageIdentifier; + +import java.util.Collection; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class TopicDefinitionResourceProvider implements MessageDefinitionProvider { + + private final StringResourceProvider stringResourceProvider; + + public TopicDefinitionResourceProvider() { + stringResourceProvider = new StringResourceProvider(); + } + + private String topicTypeToResourceName(String topicType) { + MessageIdentifier messageIdentifier = MessageIdentifier.of(topicType); + return String.format("/%s/msg/%s.msg", messageIdentifier.getPackage(), + messageIdentifier.getName()); + } + + @Override + public String get(String topicType) { + return stringResourceProvider.get(topicTypeToResourceName(topicType)); + } + + @Override + public boolean has(String topicType) { + return stringResourceProvider.has(topicTypeToResourceName(topicType)); + } + + @VisibleForTesting + public void add(String topicType, String topicDefinition) { + stringResourceProvider.addStringToCache(topicTypeToResourceName(topicType), topicDefinition); + } + + @Override + public Collection<String> getPackages() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<MessageIdentifier> getMessageIdentifiersByPackage(String pkg) { + throw new UnsupportedOperationException(); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/topic/TopicDescription.java b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDescription.java new file mode 100644 index 0000000..50c9ad3 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDescription.java @@ -0,0 +1,69 @@ +/* + * 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.topic; + +import org.ros.message.MessageDeclaration; +import org.ros.message.MessageIdentifier; + +/** + * The description of a ROS topic. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class TopicDescription extends MessageDeclaration { + + private final String md5Checksum; + + public TopicDescription(String type, String definition, String md5Checksum) { + super(MessageIdentifier.of(type), definition); + this.md5Checksum = md5Checksum; + } + + public String getMd5Checksum() { + return md5Checksum; + } + + @Override + public String toString() { + return "TopicDescription<" + getType() + ", " + md5Checksum + ">"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((md5Checksum == null) ? 0 : md5Checksum.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + TopicDescription other = (TopicDescription) obj; + if (md5Checksum == null) { + if (other.md5Checksum != null) + return false; + } else if (!md5Checksum.equals(other.md5Checksum)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/topic/TopicDescriptionFactory.java b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDescriptionFactory.java new file mode 100644 index 0000000..27e8620 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/topic/TopicDescriptionFactory.java @@ -0,0 +1,44 @@ +/* + * 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.topic; + +import org.ros.internal.message.Md5Generator; +import org.ros.message.MessageDefinitionProvider; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class TopicDescriptionFactory { + + private final MessageDefinitionProvider messageDefinitionProvider; + private final Md5Generator md5Generator; + + public TopicDescriptionFactory(MessageDefinitionProvider messageDefinitionProvider) { + this.messageDefinitionProvider = messageDefinitionProvider; + md5Generator = new Md5Generator(messageDefinitionProvider); + } + + public TopicDescription newFromType(String topicType) { + String md5Checksum = md5Generator.generate(topicType); + String topicDefinition = messageDefinitionProvider.get(topicType); + return new TopicDescription(topicType, topicDefinition, md5Checksum); + } + + public boolean hasType(String topicType) { + return messageDefinitionProvider.has(topicType); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/topic/TopicMessageFactory.java b/message_generator/src/main/java/org/ros/internal/message/topic/TopicMessageFactory.java new file mode 100644 index 0000000..b329386 --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/topic/TopicMessageFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 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.topic; + +import org.ros.internal.message.DefaultMessageFactory; +import org.ros.message.MessageDefinitionProvider; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public class TopicMessageFactory extends DefaultMessageFactory { + + public TopicMessageFactory(MessageDefinitionProvider messageDefinitionProvider) { + super(messageDefinitionProvider); + } +} diff --git a/message_generator/src/main/java/org/ros/internal/message/topic/package-info.java b/message_generator/src/main/java/org/ros/internal/message/topic/package-info.java new file mode 100644 index 0000000..d270dee --- /dev/null +++ b/message_generator/src/main/java/org/ros/internal/message/topic/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 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. + */ + +/** + * Provides internal classes for representing topic messages. + * <p> + * These classes should _not_ be used directly outside of the org.ros package. + */ +package org.ros.internal.message.topic; \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/message/Duration.java b/message_generator/src/main/java/org/ros/message/Duration.java new file mode 100644 index 0000000..d67c8c8 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/Duration.java @@ -0,0 +1,167 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2008, Willow Garage, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Willow Garage, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package org.ros.message; + +/** + * ROS Duration representation. Time and Duration are primitive types in ROS. + * ROS represents each as two 32-bit integers: seconds and nanoseconds since + * epoch. + * + * http://www.ros.org/wiki/msg + * + * @author Jason Wolfe + * @author kwc@willowgarage.com (Ken Conley) + * + */ +public class Duration implements Comparable<Duration> { + + public static final Duration MAX_VALUE = new Duration(Integer.MAX_VALUE, 999999999); + + public int secs; + public int nsecs; + + public Duration() { + } + + public Duration(int secs, int nsecs) { + this.secs = secs; + this.nsecs = nsecs; + normalize(); + } + + public Duration(double secs) { + this.secs = (int) secs; + this.nsecs = (int) ((secs - this.secs) * 1000000000); + normalize(); + } + + public Duration(Duration t) { + this.secs = t.secs; + this.nsecs = t.nsecs; + } + + public Duration add(Duration d) { + return new Duration(secs + d.secs, nsecs + d.nsecs); + } + + public Duration subtract(Duration d) { + return new Duration(secs - d.secs, nsecs - d.nsecs); + } + + public static Duration fromMillis(long durationInMillis) { + int secs = (int) (durationInMillis / 1000); + int nsecs = (int) (durationInMillis % 1000) * 1000000; + return new Duration(secs, nsecs); + } + + public static Duration fromNano(long durationInNs) { + int secs = (int) (durationInNs / 1000000000); + int nsecs = (int) (durationInNs % 1000000000); + return new Duration(secs, nsecs); + } + + public void normalize() { + while (nsecs < 0) { + nsecs += 1000000000; + secs -= 1; + } + while (nsecs >= 1000000000) { + nsecs -= 1000000000; + secs += 1; + } + } + + public long totalNsecs() { + return ((long) secs) * 1000000000 + nsecs; + } + + public boolean isZero() { + return totalNsecs() == 0; + } + + public boolean isPositive() { + return totalNsecs() > 0; + } + + public boolean isNegative() { + return totalNsecs() < 0; + } + + @Override + public String toString() { + return secs + ":" + nsecs; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + nsecs; + result = prime * result + secs; + return result; + } + + @Override + /** + * Check for equality between Time objects. + * equals() does not normalize Time representations, so fields must match exactly. + */ + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Duration other = (Duration) obj; + if (nsecs != other.nsecs) + return false; + if (secs != other.secs) + return false; + return true; + } + + @Override + public int compareTo(Duration d) { + if ((secs > d.secs) || ((secs == d.secs) && nsecs > d.nsecs)) { + return 1; + } + if ((secs == d.secs) && (nsecs == d.nsecs)) { + return 0; + } + return -1; + } + +} diff --git a/message_generator/src/main/java/org/ros/message/MessageDeclaration.java b/message_generator/src/main/java/org/ros/message/MessageDeclaration.java new file mode 100644 index 0000000..57a846e --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageDeclaration.java @@ -0,0 +1,108 @@ +/* + * 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.message; + +import com.google.common.base.Preconditions; + +/** + * An {@link MessageIdentifier} and definition pair from which all qualities of + * the message uniquely identifiable by the {@link MessageIdentifier} can be + * derived. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageDeclaration { + + private final MessageIdentifier messageIdentifier; + private final String definition; + + public static MessageDeclaration of(String type, String definition) { + Preconditions.checkNotNull(type); + Preconditions.checkNotNull(definition); + return new MessageDeclaration(MessageIdentifier.of(type), definition); + } + + /** + * @param messageIdentifier + * the {@link MessageIdentifier} + * @param definition + * the message definition + */ + public MessageDeclaration(MessageIdentifier messageIdentifier, String definition) { + Preconditions.checkNotNull(messageIdentifier); + Preconditions.checkNotNull(definition); + this.messageIdentifier = messageIdentifier; + this.definition = definition; + } + + public MessageIdentifier getMessageIdentifier() { + return messageIdentifier; + } + + public String getType() { + return messageIdentifier.getType(); + } + + public String getPackage() { + return messageIdentifier.getPackage(); + } + + public String getName() { + return messageIdentifier.getName(); + } + + public String getDefinition() { + Preconditions.checkNotNull(definition); + return definition; + } + + @Override + public String toString() { + return String.format("MessageDeclaration<%s>", messageIdentifier.toString()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((definition == null) ? 0 : definition.hashCode()); + result = prime * result + ((messageIdentifier == null) ? 0 : messageIdentifier.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MessageDeclaration other = (MessageDeclaration) obj; + if (definition == null) { + if (other.definition != null) + return false; + } else if (!definition.equals(other.definition)) + return false; + if (messageIdentifier == null) { + if (other.messageIdentifier != null) + return false; + } else if (!messageIdentifier.equals(other.messageIdentifier)) + return false; + return true; + } +} \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/message/MessageDefinitionProvider.java b/message_generator/src/main/java/org/ros/message/MessageDefinitionProvider.java new file mode 100644 index 0000000..b62715c --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageDefinitionProvider.java @@ -0,0 +1,50 @@ +/* + * 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.message; + +import java.util.Collection; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface MessageDefinitionProvider { + + /** + * @param messageType + * the type of message definition to provide + * @return the message definition for the specified type + */ + String get(String messageType); + + /** + * @param messageType + * the type of message definition to provide + * @return {@code true} if the definition for the specified type is available, + * {@code false} otherwise + */ + boolean has(String messageType); + + Collection<String> getPackages(); + + /** + * @param pkg + * the name of the package to filter on + * @return the {@link MessageIdentifier}s for all messages defined in the + * specified package + */ + Collection<MessageIdentifier> getMessageIdentifiersByPackage(String pkg); +} diff --git a/message_generator/src/main/java/org/ros/message/MessageDeserializer.java b/message_generator/src/main/java/org/ros/message/MessageDeserializer.java new file mode 100644 index 0000000..326c510 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageDeserializer.java @@ -0,0 +1,31 @@ +/* + * 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.message; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * @author damonkohler@google.com (Damon Kohler) + * + * @param <T> + * the type of message that this {@link MessageDeserializer} can + * deserialize + */ +public interface MessageDeserializer<T> { + + T deserialize(ChannelBuffer buffer); +} diff --git a/message_generator/src/main/java/org/ros/message/MessageFactory.java b/message_generator/src/main/java/org/ros/message/MessageFactory.java new file mode 100644 index 0000000..9babe2f --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageFactory.java @@ -0,0 +1,30 @@ +/* + * 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.message; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface MessageFactory { + + /** + * @param messageType + * the type of message to create + * @return a new message + */ + <T> T newFromType(String messageType); +} diff --git a/message_generator/src/main/java/org/ros/message/MessageFactoryProvider.java b/message_generator/src/main/java/org/ros/message/MessageFactoryProvider.java new file mode 100644 index 0000000..24e8713 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageFactoryProvider.java @@ -0,0 +1,24 @@ +/* + * 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.message; + +public interface MessageFactoryProvider { + + MessageFactory get(MessageIdentifier messageIdentifier); + + boolean has(MessageIdentifier messageIdentifier); +} diff --git a/message_generator/src/main/java/org/ros/message/MessageIdentifier.java b/message_generator/src/main/java/org/ros/message/MessageIdentifier.java new file mode 100644 index 0000000..9895c39 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageIdentifier.java @@ -0,0 +1,121 @@ +/* + * 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.message; + +import com.google.common.base.Preconditions; + +/** + * Uniquely identifies a message. + * + * @author damonkohler@google.com (Damon Kohler) + */ +public class MessageIdentifier { + + private String type; + private String pkg; + private String name; + + public static MessageIdentifier of(String pkg, String name) { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(name); + return new MessageIdentifier(pkg, name); + } + + public static MessageIdentifier of(String type) { + Preconditions.checkNotNull(type); + // We're not using Preconditions.checkArgument() here because we want a + // useful error message without paying the performance penalty of + // constructing it every time. + if (!type.contains("/")) { + throw new IllegalArgumentException(String.format( + "Type name is invalid or not fully qualified: \"%s\"", type)); + } + return new MessageIdentifier(type); + } + + private MessageIdentifier(String type) { + this.type = type; + } + + private MessageIdentifier(String pkg, String name) { + this.pkg = pkg; + this.name = name; + } + + public String getType() { + if (type == null) { + // Using StringBuilder like this is about 40% faster than using the + + // operator. + StringBuilder stringBuilder = new StringBuilder(pkg.length() + name.length() + 1); + stringBuilder.append(pkg); + stringBuilder.append("/"); + stringBuilder.append(name); + type = stringBuilder.toString(); + } + return type; + } + + private void splitType() { + String[] packageAndName = type.split("/", 2); + pkg = packageAndName[0]; + name = packageAndName[1]; + } + + public String getPackage() { + if (pkg == null) { + splitType(); + } + return pkg; + } + + public String getName() { + if (name == null) { + splitType(); + } + return name; + } + + @Override + public String toString() { + return String.format("MessageIdentifier<%s>", type); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + MessageIdentifier other = (MessageIdentifier) obj; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equals(other.type)) + return false; + return true; + } +} diff --git a/message_generator/src/main/java/org/ros/message/MessageListener.java b/message_generator/src/main/java/org/ros/message/MessageListener.java new file mode 100644 index 0000000..6fa0d1e --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageListener.java @@ -0,0 +1,36 @@ +/* + * 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.message; + +/** + * A callback for asynchronous message-related operations. + * + * @author damonkohler@google.com (Damon Kohler) + * + * @param <T> + * the type of message expected + */ +public interface MessageListener<T> { + + /** + * Called when a new message arrives. + * + * @param message + * the new message + */ + void onNewMessage(T message); +} \ No newline at end of file diff --git a/message_generator/src/main/java/org/ros/message/MessageSerializationFactory.java b/message_generator/src/main/java/org/ros/message/MessageSerializationFactory.java new file mode 100644 index 0000000..8971583 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageSerializationFactory.java @@ -0,0 +1,75 @@ +/* + * 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.message; + +/** + * @author damonkohler@google.com (Damon Kohler) + */ +public interface MessageSerializationFactory { + + /** + * @param messageType + * the type of message that the new {@link MessageSerializer} should + * serialize + * @return a new {@link MessageSerializer} for the provided message type + */ + <T> MessageSerializer<T> newMessageSerializer(String messageType); + + /** + * @param messageType + * the type of message that the new {@link MessageDeserializer} + * should deserialize + * @return a new {@link MessageDeserializer} for the provided message type + */ + <T> MessageDeserializer<T> newMessageDeserializer(String messageType); + + /** + * @param serviceType + * the type of service that the new {@link MessageSerializer} should + * serialize requests for + * @return a new {@link MessageSerializer} for requests to the provided + * service type + */ + <T> MessageSerializer<T> newServiceRequestSerializer(String serviceType); + + /** + * @param serviceType + * the type of service that the new {@link MessageDeserializer} + * should deserialize requests for + * @return a new {@link MessageDeserializer} for requests to the provided + * service type + */ + <T> MessageDeserializer<T> newServiceRequestDeserializer(String serviceType); + + /** + * @param serviceType + * the type of service that the new {@link MessageSerializer} should + * serialize responses for + * @return a new {@link MessageSerializer} for responses from the provided + * service type + */ + <T> MessageSerializer<T> newServiceResponseSerializer(String serviceType); + + /** + * @param serviceType + * the type of service that the new {@link MessageDeserializer} + * should deserialize responses for + * @return a new {@link MessageDeserializer} for responses from the provided + * service type + */ + <T> MessageDeserializer<T> newServiceResponseDeserializer(String serviceType); +} diff --git a/message_generator/src/main/java/org/ros/message/MessageSerializer.java b/message_generator/src/main/java/org/ros/message/MessageSerializer.java new file mode 100644 index 0000000..ffeb218 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/MessageSerializer.java @@ -0,0 +1,30 @@ +/* + * 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.message; + +import org.jboss.netty.buffer.ChannelBuffer; + +/** + * @author damonkohler@google.com (Damon Kohler) + * + * @param <T> + * the type of message that the {@link MessageSerializer} can serialize + */ +public interface MessageSerializer<T> { + + void serialize(T message, ChannelBuffer buffer); +} diff --git a/message_generator/src/main/java/org/ros/message/Time.java b/message_generator/src/main/java/org/ros/message/Time.java new file mode 100644 index 0000000..7805610 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/Time.java @@ -0,0 +1,156 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2008, Willow Garage, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * Redistributions in binary + * form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided + * with the distribution. * Neither the name of Willow Garage, Inc. nor the + * names of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package org.ros.message; + +/** + * ROS Time representation. Time and Time are primitive types in ROS. ROS + * represents each as two 32-bit integers: seconds and nanoseconds since epoch. + * + * @see "http://www.ros.org/wiki/msg" + * + * @author Jason Wolfe + * @author kwc@willowgarage.com (Ken Conley) + */ +public class Time implements Comparable<Time> { + + public int secs; + public int nsecs; + + public Time() { + secs = 0; + nsecs = 0; + } + + public Time(int secs, int nsecs) { + this.secs = secs; + this.nsecs = nsecs; + normalize(); + } + + public Time(double secs) { + this.secs = (int) secs; + this.nsecs = (int) ((secs - this.secs) * 1000000000); + normalize(); + } + + public Time(Time t) { + this.secs = t.secs; + this.nsecs = t.nsecs; + } + + public Time add(Duration d) { + return new Time(secs + d.secs, nsecs + d.nsecs); + } + + public Time subtract(Duration d) { + return new Time(secs - d.secs, nsecs - d.nsecs); + } + + public Duration subtract(Time t) { + return new Duration(secs - t.secs, nsecs - t.nsecs); + } + + public static Time fromMillis(long timeInMillis) { + int secs = (int) (timeInMillis / 1000); + int nsecs = (int) (timeInMillis % 1000) * 1000000; + return new Time(secs, nsecs); + } + + public static Time fromNano(long timeInNs) { + int secs = (int) (timeInNs / 1000000000); + int nsecs = (int) (timeInNs % 1000000000); + return new Time(secs, nsecs); + } + + @Override + public String toString() { + return secs + ":" + nsecs; + } + + public double toSeconds() { + return totalNsecs() / 1e9; + } + + public long totalNsecs() { + return ((long) secs) * 1000000000 + nsecs; + } + + public boolean isZero() { + return totalNsecs() == 0; + } + + public void normalize() { + while (nsecs < 0) { + nsecs += 1000000000; + secs -= 1; + } + while (nsecs >= 1000000000) { + nsecs -= 1000000000; + secs += 1; + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + nsecs; + result = prime * result + secs; + return result; + } + + /** + * Check for equality between {@link Time} objects. + * <p> + * This method does not normalize {@link Time} representations, so fields must match + * exactly. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Time other = (Time) obj; + if (nsecs != other.nsecs) return false; + if (secs != other.secs) return false; + return true; + } + + @Override + public int compareTo(Time t) { + if ((secs > t.secs) || ((secs == t.secs) && nsecs > t.nsecs)) { + return 1; + } + if ((secs == t.secs) && (nsecs == t.nsecs)) { + return 0; + } + return -1; + } +} diff --git a/message_generator/src/main/java/org/ros/message/package-info.java b/message_generator/src/main/java/org/ros/message/package-info.java new file mode 100644 index 0000000..2f57561 --- /dev/null +++ b/message_generator/src/main/java/org/ros/message/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 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. + */ + +/** + * Provides the classes for representing messages. + * + * @see <a href="http://ros.org/wiki/Messages">messages documentation</a> + */ +package org.ros.message; \ No newline at end of file diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..db623cb --- /dev/null +++ b/package.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<package> + <name>rosjava_bootstrap</name> + <version>0.1.0</version> + <description> + Bootstrap utilities for rosjava builds. + </description> + <url>http://ros.org/wiki/rosjava_bootstrap</url> + <maintainer email="d.stonier@gmail.com">Daniel Stonier</maintainer> + <author email="d.stonier@gmail.com">Daniel Stonier</author> + <author email="damonkohler@google.com">Damon Kohler</author> + <license>Apache 2.0</license> + <buildtool_depend>catkin</buildtool_depend> + <build_depend>rosjava_tools</build_depend> +</package> + diff --git a/settings.gradle b/settings.gradle index 98689ec..af55cd9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,4 +16,5 @@ /* rootProject.name = 'catkin' */ -include 'rosjava_gradle_plugins' \ No newline at end of file +include 'gradle_plugins' +include 'message_generator' \ No newline at end of file -- GitLab