Compare commits
14 Commits
f5a1bb7aba
...
a8f0156c52
Author | SHA1 | Date |
---|---|---|
|
a8f0156c52 | 3 years ago |
|
78e75ccd7b | 3 years ago |
|
6a708f9eb5 | 3 years ago |
|
31287ba213 | 3 years ago |
|
c9b91966e7 | 3 years ago |
|
1bee5f4b6d | 3 years ago |
|
6d497797da | 3 years ago |
|
432db2dbd9 | 3 years ago |
|
999025cef6 | 3 years ago |
|
f710a75090 | 3 years ago |
|
3b1e54fea7 | 3 years ago |
|
dde3be2d62 | 3 years ago |
|
1061e38ead | 3 years ago |
|
9f18899626 | 3 years ago |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,20 @@
|
||||
{
|
||||
"version": 3,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "com.example.logistics",
|
||||
"variantName": "release",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"attributes": [],
|
||||
"versionCode": 1,
|
||||
"versionName": "1.0",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
],
|
||||
"elementType": "File"
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,121 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<script type="text/javascript" type="text/javascript">
|
||||
|
||||
function callJS(){
|
||||
var ros = new ROSLIB.Ros({
|
||||
url : 'ws://192.168.43.164:9090'
|
||||
});
|
||||
|
||||
ros.on('connection', function() {
|
||||
console.log('Connected to websocket server.');
|
||||
});
|
||||
|
||||
ros.on('error', function(error) {
|
||||
console.log('Error connecting to websocket server: ', error);
|
||||
});
|
||||
|
||||
ros.on('close', function() {
|
||||
console.log('Connection to websocket server closed.');
|
||||
});
|
||||
|
||||
// 发布一个话题
|
||||
|
||||
|
||||
|
||||
var move_base= new ROSLIB.ActionClient({
|
||||
ros : ros,
|
||||
serverName : '/move_base',
|
||||
actionName : 'move_base_msgs/MoveBaseAction'
|
||||
});
|
||||
|
||||
var currentTime = new Date();
|
||||
var secs = Math.floor(currentTime.getTime()/1000)
|
||||
var nsecs = Math.round(1000000000*(currentTime.getTime()/1000-secs))
|
||||
|
||||
var goal = new ROSLIB.Goal({
|
||||
actionClient: move_base,
|
||||
goalMessage:{
|
||||
target_pose:{
|
||||
header:{
|
||||
frame_id:'map',
|
||||
stamp:{
|
||||
secs: secs,
|
||||
nsecs:nsecs
|
||||
}
|
||||
},
|
||||
pose:{
|
||||
position:{
|
||||
x:-3.97, //-0.743 -0.0273 取件点
|
||||
y:1.68, //3.00 -0.09
|
||||
z:0.000
|
||||
},
|
||||
orientation:{
|
||||
x:0.000,
|
||||
y:0.000,
|
||||
z:0.000,
|
||||
w:1.000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
goal.on('feedback', function(feedback) {
|
||||
console.log('Feedback: ' + feedback.sequence);
|
||||
});
|
||||
|
||||
goal.on('result', function(result) {
|
||||
console.log('Final Result: ' + result.sequence);
|
||||
});
|
||||
|
||||
ros.on('connection', function() {
|
||||
console.log('Connected to websocket server.');
|
||||
});
|
||||
|
||||
ros.on('error', function(error) {
|
||||
console.log('Error connecting to websocket server: ', error);
|
||||
});
|
||||
|
||||
ros.on('close', function() {
|
||||
console.log('Connection to websocket server closed.');
|
||||
});
|
||||
|
||||
goal.send();
|
||||
|
||||
/*var cmdVel = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/cmd_vel_mux/input/navi',
|
||||
messageType : 'geometry_msgs/Twist'
|
||||
});
|
||||
|
||||
var twist = new ROSLIB.Message({
|
||||
linear : {
|
||||
x : 0.2,
|
||||
y : 0.0,
|
||||
z : 0.0
|
||||
},
|
||||
angular : {
|
||||
x : 0.0,
|
||||
y : 0.0,
|
||||
z : 0.0
|
||||
}
|
||||
});
|
||||
cmdVel.publish(twist);*/
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Simple roslib Example</h1>
|
||||
<p>Check your Web Console for output.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,42 @@
|
||||
package com.example.logistics.tools;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.jilk.ros.rosbridge.ROSBridgeClient;
|
||||
|
||||
/**
|
||||
* @ Create by dadac on 2018/10/8.
|
||||
* @Function:
|
||||
* @Return:
|
||||
*/
|
||||
public class RCApplication extends Application {
|
||||
|
||||
|
||||
ROSBridgeClient client;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
if (client != null)
|
||||
client.disconnect();
|
||||
super.onTerminate();
|
||||
|
||||
}
|
||||
|
||||
public ROSBridgeClient getRosClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public void setRosClient(ROSBridgeClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,123 @@
|
||||
package com.example.logistics.ui;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.media.Image;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SimpleAdapter;
|
||||
import android.widget.AbsListView.OnScrollListener;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.example.logistics.R;
|
||||
import com.example.logistics.dao.goodDao;
|
||||
import com.example.logistics.dao.operationDao;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HistoryActivity extends Activity implements OnItemClickListener, OnScrollListener, View.OnClickListener {
|
||||
|
||||
private String TAG = "HistoryActivity";
|
||||
private ListView lv_history;
|
||||
private ArrayAdapter<String> arr_adapter;
|
||||
private SimpleAdapter simp_adapter;
|
||||
private String phonenum;
|
||||
private List<Map<String, Object>> dataList;
|
||||
private ImageButton sync_his;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_history);
|
||||
sync_his = (ImageButton) findViewById(R.id.sync_his);
|
||||
dataList=new ArrayList<Map<String,Object>>();
|
||||
lv_history = (ListView) findViewById(R.id.lv_history);
|
||||
|
||||
simp_adapter=new SimpleAdapter(this, dataList, R.layout.item, new String[]{"pickupcode","time"}, new int[]{R.id.np_id,R.id.np_time});
|
||||
lv_history.setAdapter(simp_adapter);
|
||||
lv_history.setOnItemClickListener(this);
|
||||
lv_history.setOnScrollListener(this);
|
||||
sync_his.setOnClickListener(this);
|
||||
|
||||
Intent intent = getIntent();
|
||||
phonenum = intent.getStringExtra("user");
|
||||
|
||||
sync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// TODO Auto-generated method stub
|
||||
String text=lv_history.getItemAtPosition(position)+"";
|
||||
Toast.makeText(this, "position="+position+" text="+text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v){
|
||||
switch(v.getId()){
|
||||
case R.id.sync_his:
|
||||
sync();
|
||||
Toast.makeText(this, "同步成功", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState){
|
||||
// TODO Auto-generated method stub
|
||||
switch(scrollState){
|
||||
case SCROLL_STATE_FLING:
|
||||
Log.i(TAG, "用户在手指离开屏幕之前,由于用力划了一下,试图仍依靠惯性继续滑动");
|
||||
break;
|
||||
case SCROLL_STATE_IDLE:
|
||||
Log.i(TAG, "视图已经停止滑动");
|
||||
break;
|
||||
case SCROLL_STATE_TOUCH_SCROLL:
|
||||
Log.i(TAG, "手指没有离开屏幕,视图正在滑动");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(AbsListView view, int arg1, int arg2, int arg3){
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void sync(){
|
||||
new Thread(){
|
||||
@Override
|
||||
public void run(){
|
||||
operationDao operationDao = new operationDao();
|
||||
dataList = operationDao.history(phonenum);
|
||||
|
||||
int msg = 1;
|
||||
hand1.sendEmptyMessage(msg);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
@SuppressLint("HandlerLeak")
|
||||
final Handler hand1 = new Handler(){
|
||||
@Override
|
||||
public void handleMessage(Message msg){
|
||||
if(msg.what == 1){
|
||||
simp_adapter=new SimpleAdapter(HistoryActivity.this, dataList, R.layout.item, new String[]{"pickupcode","time"}, new int[]{R.id.np_id,R.id.np_time});
|
||||
lv_history.setAdapter(simp_adapter);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package com.example.logistics.ui;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AbsListView.OnScrollListener;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.SimpleAdapter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.example.logistics.R;
|
||||
import com.example.logistics.dao.goodDao;
|
||||
import com.example.logistics.dao.userDao;
|
||||
import com.example.logistics.entity.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class NoPickActivity extends Activity implements OnItemClickListener, OnScrollListener, View.OnClickListener {
|
||||
|
||||
private String TAG = "NoPickActivity";
|
||||
private ListView lv_nopick;
|
||||
private ArrayAdapter<String> arr_adapter;
|
||||
private SimpleAdapter simp_adapter;
|
||||
private String phonenum;
|
||||
private List<Map<String, Object>> dataList;
|
||||
private ImageButton sync_np;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_no_pick);
|
||||
|
||||
dataList=new ArrayList<Map<String,Object>>();
|
||||
lv_nopick = (ListView) findViewById(R.id.lv_nopick);
|
||||
sync_np = (ImageButton) findViewById(R.id.sync_np);
|
||||
|
||||
simp_adapter=new SimpleAdapter(this, dataList, R.layout.item, new String[]{"id","time"}, new int[]{R.id.np_id,R.id.np_time});
|
||||
lv_nopick.setAdapter(simp_adapter);
|
||||
lv_nopick.setOnItemClickListener(this);
|
||||
lv_nopick.setOnScrollListener(this);
|
||||
sync_np.setOnClickListener(this);
|
||||
|
||||
Intent intent = getIntent();
|
||||
phonenum = intent.getStringExtra("user");
|
||||
|
||||
sync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// TODO Auto-generated method stub
|
||||
String text=lv_nopick.getItemAtPosition(position)+"";
|
||||
Toast.makeText(this, "position="+position+" text="+text, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v){
|
||||
switch(v.getId()){
|
||||
case R.id.sync_np:
|
||||
sync();
|
||||
Toast.makeText(this, "同步成功", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState){
|
||||
// TODO Auto-generated method stub
|
||||
switch(scrollState){
|
||||
case SCROLL_STATE_FLING:
|
||||
Log.i(TAG, "用户在手指离开屏幕之前,由于用力划了一下,试图仍依靠惯性继续滑动");
|
||||
break;
|
||||
case SCROLL_STATE_IDLE:
|
||||
Log.i(TAG, "视图已经停止滑动");
|
||||
break;
|
||||
case SCROLL_STATE_TOUCH_SCROLL:
|
||||
Log.i(TAG, "手指没有离开屏幕,视图正在滑动");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(AbsListView view, int arg1, int arg2, int arg3){
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void sync(){
|
||||
new Thread(){
|
||||
@Override
|
||||
public void run(){
|
||||
goodDao goodDao = new goodDao();
|
||||
dataList = goodDao.nopick(phonenum);
|
||||
|
||||
int msg = 1;
|
||||
hand1.sendEmptyMessage(msg);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
@SuppressLint("HandlerLeak")
|
||||
final Handler hand1 = new Handler(){
|
||||
@Override
|
||||
public void handleMessage(Message msg){
|
||||
if(msg.what == 1){
|
||||
simp_adapter=new SimpleAdapter(NoPickActivity.this, dataList, R.layout.item, new String[]{"id","time"}, new int[]{R.id.np_id,R.id.np_time});
|
||||
lv_nopick.setAdapter(simp_adapter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros;
|
||||
|
||||
import com.jilk.ros.message.Clock;
|
||||
import com.jilk.ros.message.Log;
|
||||
import com.jilk.ros.rosapi.message.Empty;
|
||||
import com.jilk.ros.rosapi.message.GetTime;
|
||||
import com.jilk.ros.rosapi.message.MessageDetails;
|
||||
import com.jilk.ros.rosapi.message.Type;
|
||||
import com.jilk.ros.rosbridge.ROSBridgeClient;
|
||||
|
||||
public class Example {
|
||||
|
||||
public Example() {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ROSBridgeClient client = new ROSBridgeClient("ws://162.243.238.80:9090");
|
||||
client.connect();
|
||||
//testTopic(client);
|
||||
try {
|
||||
testService(client);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
client.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public static void testService(ROSBridgeClient client) {
|
||||
try {
|
||||
Service<Empty, GetTime> timeService =
|
||||
new Service<Empty, GetTime>("/rosapi/get_time", Empty.class, GetTime.class, client);
|
||||
timeService.verify();
|
||||
//System.out.println("Time (secs): " + timeService.callBlocking(new Empty()).time.sec);
|
||||
|
||||
Service<com.jilk.ros.rosapi.message.Service, Type> serviceTypeService =
|
||||
new Service<com.jilk.ros.rosapi.message.Service, Type>("/rosapi/service_type",
|
||||
com.jilk.ros.rosapi.message.Service.class, Type.class, client);
|
||||
serviceTypeService.verify();
|
||||
String type = serviceTypeService.callBlocking(new com.jilk.ros.rosapi.message.Service("/rosapi/service_response_details")).type;
|
||||
|
||||
Service<Type, MessageDetails> serviceDetails =
|
||||
new Service<Type, MessageDetails>("/rosapi/service_response_details",
|
||||
Type.class, MessageDetails.class, client);
|
||||
serviceDetails.verify();
|
||||
//serviceDetails.callBlocking(new Type(type)).print();
|
||||
|
||||
Topic<Log> logTopic =
|
||||
new Topic<Log>("/rosout", Log.class, client);
|
||||
logTopic.verify();
|
||||
|
||||
/*
|
||||
System.out.println("Nodes");
|
||||
for (String s : client.getNodes())
|
||||
System.out.println(" " + s);
|
||||
System.out.println("Topics");
|
||||
for (String s : client.getTopics()) {
|
||||
System.out.println(s + ":");
|
||||
client.getTopicMessageDetails(s).print();
|
||||
}
|
||||
System.out.println("Services");
|
||||
for (String s : client.getServices()) {
|
||||
System.out.println(s + ":");
|
||||
client.getServiceRequestDetails(s).print();
|
||||
System.out.println("-----------------");
|
||||
client.getServiceResponseDetails(s).print();
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
System.out.println("Process was interrupted.");
|
||||
}
|
||||
/*
|
||||
Service<Empty, Topics> topicService =
|
||||
new Service<Empty, Topics>("/rosapi/topics", Empty.class, Topics.class, client);
|
||||
Service<Topic, Type> typeService =
|
||||
new Service<Topic, Type>("/rosapi/topic_type", Topic.class, Type.class, client);
|
||||
Service<Type, MessageDetails> messageService =
|
||||
new Service<Type, MessageDetails>("/rosapi/message_details", Type.class, MessageDetails.class, client);
|
||||
try {
|
||||
Topics topics = topicService.callBlocking(new Empty());
|
||||
for (String topicString : topics.topics) {
|
||||
Topic topic = new Topic();
|
||||
topic.topic = topicString;
|
||||
Type type = typeService.callBlocking(topic);
|
||||
MessageDetails details = messageService.callBlocking(type);
|
||||
System.out.println("Topic: " + topic.topic + " Type: " + type.type);
|
||||
details.print();
|
||||
System.out.println();
|
||||
}
|
||||
Type type = new Type();
|
||||
type.type = "time";
|
||||
System.out.print("Single type check on \'time\': ");
|
||||
messageService.callBlocking(type).print();
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
System.out.println("testService: process was interrupted.");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public static void testTopic(ROSBridgeClient client) {
|
||||
Topic<Clock> clockTopic = new Topic<Clock>("/clock", Clock.class, client);
|
||||
clockTopic.subscribe();
|
||||
try {
|
||||
Thread.sleep(20000);} catch(InterruptedException ex) {}
|
||||
Clock cl = null;
|
||||
try {
|
||||
cl = clockTopic.take(); // just gets one
|
||||
}
|
||||
catch (InterruptedException ex) {}
|
||||
cl.print();
|
||||
cl.clock.nsecs++;
|
||||
clockTopic.unsubscribe();
|
||||
clockTopic.advertise();
|
||||
clockTopic.publish(cl);
|
||||
clockTopic.unadvertise();
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
|
||||
public interface MessageHandler<T extends Message> {
|
||||
public void onMessage(T message);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.rosapi.message.TypeDef;
|
||||
import com.jilk.ros.rosbridge.FullMessageHandler;
|
||||
import com.jilk.ros.rosbridge.ROSBridgeClient;
|
||||
import com.jilk.ros.rosbridge.operation.Operation;
|
||||
|
||||
public abstract class ROSClient {
|
||||
|
||||
public ROSClient() {}
|
||||
|
||||
public static ROSClient create(String uriString) {
|
||||
// if we ever implement other ROSClient types, we'll key off the URI protocol (e.g., ws://)
|
||||
// we'd also have to abstract out Topic and Service since they depend on the ROSBridge operations
|
||||
return new ROSBridgeClient(uriString);
|
||||
}
|
||||
|
||||
public abstract boolean connect();
|
||||
public abstract boolean connect(ConnectionStatusListener listener);
|
||||
public abstract void disconnect();
|
||||
public abstract void send(Operation operation);
|
||||
public abstract void send(String json);
|
||||
public abstract void register(Class<? extends Operation> c,
|
||||
String s,
|
||||
Class<? extends Message> m,
|
||||
FullMessageHandler h);
|
||||
public abstract void unregister(Class<? extends Operation> c, String s);
|
||||
public abstract void setDebug(boolean debug);
|
||||
public abstract String[] getNodes() throws InterruptedException;
|
||||
public abstract String[] getTopics() throws InterruptedException;
|
||||
public abstract String[] getServices() throws InterruptedException;
|
||||
public abstract TypeDef getTopicMessageDetails(String topic) throws InterruptedException;
|
||||
public abstract TypeDef[] getTopicMessageList(String topic) throws InterruptedException;
|
||||
public abstract TypeDef getServiceRequestDetails(String service) throws InterruptedException;
|
||||
public abstract TypeDef[] getServiceRequestList(String service) throws InterruptedException;
|
||||
public abstract TypeDef getServiceResponseDetails(String service) throws InterruptedException;
|
||||
public abstract TypeDef[] getServiceResponseList(String service) throws InterruptedException;
|
||||
public abstract TypeDef getTypeDetails(String type) throws InterruptedException;
|
||||
public abstract TypeDef[] getTypeList(String type) throws InterruptedException;
|
||||
public abstract void typeMatch(TypeDef t, Class<? extends Message> c) throws InterruptedException;
|
||||
public abstract Object getUnderlyingClient(); // for debugging
|
||||
|
||||
public interface ConnectionStatusListener {
|
||||
public void onConnect();
|
||||
public void onDisconnect(boolean normal, String reason, int code);
|
||||
public void onError(Exception ex);
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.rosbridge.FullMessageHandler;
|
||||
import com.jilk.ros.rosbridge.operation.CallService;
|
||||
import com.jilk.ros.rosbridge.operation.ServiceResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class Service<CallType extends Message, ResponseType extends Message> extends Message implements FullMessageHandler {
|
||||
private String service;
|
||||
private Class<? extends ResponseType> responseType;
|
||||
private Class<? extends CallType> callType;
|
||||
private ROSClient client;
|
||||
private Map<String, CallRecord> calls;
|
||||
|
||||
public Service(String service, Class<? extends CallType> callType,
|
||||
Class<? extends ResponseType> responseType, ROSClient client) {
|
||||
this.service = service;
|
||||
this.client = client;
|
||||
this.responseType = responseType;
|
||||
this.callType = callType;
|
||||
calls = new HashMap<String, CallRecord>();
|
||||
}
|
||||
|
||||
// A result can only be returned once; it is cleared from the hash before
|
||||
// being sent/returned. This is to ensure that results do not accumulate
|
||||
// indefinitely. If callers need to keep these around they can set up their
|
||||
// own hash.
|
||||
|
||||
@Override
|
||||
public void onMessage(String id, Message response) {
|
||||
//System.out.print("Service.onMessage: ");
|
||||
//response.print();
|
||||
CallRecord call = calls.get(id);
|
||||
if(call == null) {
|
||||
System.out.print("No caller service response");
|
||||
return;
|
||||
}
|
||||
if (call.handler != null) {
|
||||
calls.remove(id);
|
||||
call.handler.onMessage((ResponseType) response);
|
||||
}
|
||||
else {
|
||||
call.result = (ResponseType) response;
|
||||
call.latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
public String call(CallType args) {
|
||||
return callImpl(args, null);
|
||||
}
|
||||
|
||||
public void callWithHandler(CallType args, MessageHandler<ResponseType> responseHandler) {
|
||||
callImpl(args, responseHandler);
|
||||
}
|
||||
|
||||
public ResponseType callBlocking(CallType args) throws InterruptedException {
|
||||
return take(call(args));
|
||||
}
|
||||
|
||||
private String callImpl(CallType args, MessageHandler<ResponseType> responseHandler) {
|
||||
client.register(ServiceResponse.class, service, responseType, this); // do this once on creation?
|
||||
CallService messageCallService = new CallService(service, args);
|
||||
String id = messageCallService.id;
|
||||
CallRecord callRecord = new CallRecord(responseHandler);
|
||||
calls.put(id, callRecord);
|
||||
client.send(messageCallService);
|
||||
return id;
|
||||
}
|
||||
|
||||
public ResponseType poll(String id) {
|
||||
CallRecord call = calls.get(id);
|
||||
if (call.result != null)
|
||||
calls.remove(id);
|
||||
return call.result;
|
||||
}
|
||||
|
||||
public ResponseType take(String id) throws InterruptedException {
|
||||
CallRecord call = calls.get(id);
|
||||
call.latch.await();
|
||||
calls.remove(id);
|
||||
return call.result;
|
||||
}
|
||||
|
||||
public void verify() throws InterruptedException {
|
||||
|
||||
boolean hasService = false;
|
||||
for (String s : client.getServices()) {
|
||||
if (s.equals(service)) {
|
||||
hasService = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasService)
|
||||
throw new RuntimeException("Service \'" + service + "\' not available.");
|
||||
|
||||
client.typeMatch(client.getServiceRequestDetails(service), callType);
|
||||
client.typeMatch(client.getServiceResponseDetails(service), responseType);
|
||||
}
|
||||
|
||||
private class CallRecord {
|
||||
public ResponseType result;
|
||||
public CountDownLatch latch;
|
||||
public MessageHandler<ResponseType> handler;
|
||||
|
||||
public CallRecord(MessageHandler<ResponseType> handler) {
|
||||
this.result = null;
|
||||
this.latch = new CountDownLatch(1);
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.rosbridge.FullMessageHandler;
|
||||
import com.jilk.ros.rosbridge.operation.Advertise;
|
||||
import com.jilk.ros.rosbridge.operation.Operation;
|
||||
import com.jilk.ros.rosbridge.operation.Publish;
|
||||
import com.jilk.ros.rosbridge.operation.Subscribe;
|
||||
import com.jilk.ros.rosbridge.operation.Unadvertise;
|
||||
import com.jilk.ros.rosbridge.operation.Unsubscribe;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
|
||||
public class Topic<T extends Message> extends LinkedBlockingQueue<T> implements FullMessageHandler {
|
||||
protected String topic;
|
||||
private Class<? extends T> type;
|
||||
private String messageType;
|
||||
private ROSClient client;
|
||||
private Thread handlerThread;
|
||||
|
||||
public Topic(String topic, Class<? extends T> type, ROSClient client) {
|
||||
this.topic = topic;
|
||||
this.client = client;
|
||||
this.type = type;
|
||||
messageType = Message.getMessageType(type);
|
||||
handlerThread = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String id, Message message) {
|
||||
add((T) message);
|
||||
}
|
||||
|
||||
|
||||
// warning: there is a delay between the completion of this method and
|
||||
// the completion of the subscription; it takes longer than
|
||||
// publishing multiple other messages, for example.
|
||||
public void subscribe(MessageHandler<T> handler) {
|
||||
startRunner(handler);
|
||||
subscribe();
|
||||
}
|
||||
|
||||
public void subscribe() {
|
||||
client.register(Publish.class, topic, type, this);
|
||||
send(new Subscribe(topic, messageType));
|
||||
}
|
||||
|
||||
public void unsubscribe() {
|
||||
// need to handle race conditions in incoming message handler
|
||||
// so that once unsubscribe has happened the handler gets no more
|
||||
// messages
|
||||
send(new Unsubscribe(topic));
|
||||
client.unregister(Publish.class, topic);
|
||||
stopRunner();
|
||||
}
|
||||
|
||||
private void startRunner(MessageHandler<T> handler) {
|
||||
stopRunner();
|
||||
handlerThread = new Thread(new MessageRunner(handler));
|
||||
handlerThread.setName("Message handler for " + topic);
|
||||
handlerThread.start();
|
||||
}
|
||||
|
||||
private void stopRunner() {
|
||||
if (handlerThread != null) {
|
||||
handlerThread.interrupt();
|
||||
clear();
|
||||
handlerThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void advertise() {
|
||||
send(new Advertise(topic, messageType));
|
||||
}
|
||||
|
||||
public void publish(T message) {
|
||||
send(new Publish(topic, message));
|
||||
}
|
||||
|
||||
public void unadvertise() {
|
||||
send(new Unadvertise(topic));
|
||||
}
|
||||
|
||||
private void send(Operation operation) {
|
||||
client.send(operation);
|
||||
}
|
||||
|
||||
public void verify() throws InterruptedException {
|
||||
|
||||
boolean hasTopic = false;
|
||||
for (String s : client.getTopics()) {
|
||||
if (s.equals(topic)) {
|
||||
hasTopic = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasTopic)
|
||||
throw new RuntimeException("Topic \'" + topic + "\' not available.");
|
||||
|
||||
client.typeMatch(client.getTopicMessageDetails(topic), type);
|
||||
}
|
||||
|
||||
private class MessageRunner implements Runnable {
|
||||
private MessageHandler<T> handler;
|
||||
|
||||
public MessageRunner(MessageHandler<T> handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.interrupted()) {
|
||||
try {
|
||||
handler.onMessage(take());
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.jilk.ros.message;
|
||||
|
||||
/**
|
||||
* Created by xxhong on 16-11-17.
|
||||
*/
|
||||
@MessageType(string = "std_msgs/Int16MultiArray")
|
||||
public class AudioMsg extends Message {
|
||||
public short[] data;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "rosgraph_msgs/Clock")
|
||||
public class Clock extends Message {
|
||||
public TimePrimitive clock;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "std_msgs/Duration")
|
||||
public class Duration extends DurationPrimitive {
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "duration")
|
||||
public class DurationPrimitive extends TimePrimitive {
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "std_srvs/Empty")
|
||||
public class Empty extends Message {
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "std_msgs/Header")
|
||||
public class Header extends Message {
|
||||
public long seq;
|
||||
public TimePrimitive stamp;
|
||||
public String frame_id;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "rosgraph_msgs/Log")
|
||||
public class Log extends Message {
|
||||
public Header header;
|
||||
public byte level;
|
||||
public String name;
|
||||
public String msg;
|
||||
public String file;
|
||||
public String function;
|
||||
public long line;
|
||||
public String[] topics;
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@MessageType(string = "message")
|
||||
public abstract class Message {
|
||||
|
||||
// Some requirements about message types:
|
||||
// - It must have a MessageType declaration to be recognized on inbound messages
|
||||
// - Every field must be explicitly designated as public
|
||||
// - Every field that is not a primitive or near-primitive must be another Message class
|
||||
// - If there is a non-empty constructor, you must also have an empty constructor
|
||||
// - If it is set up as an inner class, it needs an explicit nullary constructor
|
||||
// (note: I have seen an inner class otherwise fail, I have not tested it with the explicit constructor)
|
||||
|
||||
public static void register(Class c, Map<String, Class> messageClasses) {
|
||||
try {
|
||||
typecheck(c);
|
||||
|
||||
// Must register the class and not have duplicate
|
||||
// This is not recursive because only the top level message class
|
||||
// needs to be determined from the string - others are top-down.
|
||||
String messageString = getMessageType(c);
|
||||
Class existingClass = messageClasses.get(messageString);
|
||||
if (existingClass != null && !existingClass.equals(c))
|
||||
throw new MessageException("Message String \'" + messageString +
|
||||
"\' is assigned to two different classes (" +
|
||||
c.getName() + " and " + existingClass.getName() + ")");
|
||||
messageClasses.put(messageString, c);
|
||||
}
|
||||
catch (MessageException ex) {
|
||||
// should be changed to be a hooked method to give library user control
|
||||
System.out.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static String getMessageType(Class c) {
|
||||
return ((MessageType) c.getAnnotation(MessageType.class)).string();
|
||||
}
|
||||
|
||||
// this has never been used or tested but kind of belongs here
|
||||
// commented out because it uses ReflectiveOperationException which is not available on Android
|
||||
/*
|
||||
public static Message newInstance(String className) {
|
||||
try {
|
||||
Class messageClass = Class.forName(className);
|
||||
if (Message.class.isAssignableFrom(messageClass))
|
||||
return (Message) messageClass.newInstance();
|
||||
else throw new ClassCastException();
|
||||
}
|
||||
catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Unable to create message of class \'" + className + "\'.", ex);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Could probably do more checking here, but not sure what right now
|
||||
private static void typecheck(Class c) throws MessageException {
|
||||
|
||||
// Must inherit from Message
|
||||
if (!Message.class.isAssignableFrom(c))
|
||||
throw new MessageException("Class \'" + c.getName() +
|
||||
"\' does not extend Message");
|
||||
|
||||
// Must have the MessageType annotation
|
||||
if (getMessageType(c) == null)
|
||||
throw new MessageException("Class \'" + c.getName() +
|
||||
"\' is missing the MessageType annotation");
|
||||
|
||||
// All fields must also be valid Message classes
|
||||
// Note that this also serves to force-load all the message classes
|
||||
// so that they get registered
|
||||
for (Field f : c.getFields()) {
|
||||
Class fc = f.getType();
|
||||
if (fc.isArray()) {
|
||||
Class ac = fc.getComponentType();
|
||||
if (!isPrimitive(ac))
|
||||
typecheck(ac);
|
||||
}
|
||||
else if (!isPrimitive(fc))
|
||||
typecheck(fc);
|
||||
}
|
||||
}
|
||||
|
||||
public void print() {
|
||||
printMessage(this, "");
|
||||
}
|
||||
|
||||
private static void printMessage(Object o, String indent) {
|
||||
for (Field f : o.getClass().getFields()) {
|
||||
Class c = f.getType();
|
||||
Object fieldObject = getFieldObject(f, o);
|
||||
if (fieldObject != null) {
|
||||
if (isPrimitive(c))
|
||||
System.out.println(indent + f.getName() + ": " + fieldObject);
|
||||
else if (c.isArray()) {
|
||||
System.out.println(indent + f.getName() + ": [");
|
||||
printArray(fieldObject, indent + " ");
|
||||
System.out.println(indent + "]");
|
||||
}
|
||||
else {
|
||||
System.out.println(indent + f.getName() + ":");
|
||||
printMessage(fieldObject, indent + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void printArray(Object array, String indent) {
|
||||
Class arrayClass = array.getClass().getComponentType();
|
||||
for (int i = 0; i < Array.getLength(array); i++) {
|
||||
Object elementObject = Array.get(array, i);
|
||||
if (elementObject != null) {
|
||||
if (isPrimitive(arrayClass))
|
||||
System.out.println(indent + i + ": " + elementObject);
|
||||
else if (arrayClass.isArray()) { // this is not actually allowed in ROS
|
||||
System.out.println(indent + i + ": [");
|
||||
printArray(elementObject, indent + " ");
|
||||
System.out.println(indent + "]");
|
||||
}
|
||||
else {
|
||||
System.out.println(indent + i + ":");
|
||||
printMessage(elementObject, indent + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
// remember to print array indices
|
||||
}
|
||||
|
||||
public static boolean isPrimitive(Class c) {
|
||||
return (c.isPrimitive() ||
|
||||
c.equals(String.class) ||
|
||||
Number.class.isAssignableFrom(c) ||
|
||||
c.equals(Boolean.class));
|
||||
}
|
||||
|
||||
|
||||
// Copied from com.jilk.ros.rosbridge.JSON
|
||||
private static Object getFieldObject(Field f, Object o) {
|
||||
Object fo = null;
|
||||
try {
|
||||
fo = f.get(o);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return fo;
|
||||
}
|
||||
|
||||
public void copyFrom(Message source) {
|
||||
try {
|
||||
if (source.getClass() != getClass())
|
||||
throw new RuntimeException("Attempt to copy non-matching classes");
|
||||
for (Field f : getClass().getFields()) {
|
||||
Class fc = f.getType();
|
||||
if (fc.isArray())
|
||||
throw new RuntimeException("copyFrom - array types not implemented");
|
||||
else if (!isPrimitive(fc))
|
||||
((Message) f.get(this)).copyFrom((Message) f.get(source));
|
||||
else {
|
||||
Object value = f.get(source);
|
||||
f.set(this, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new RuntimeException("copyFrom error", ex);
|
||||
}
|
||||
catch (ClassCastException ex) {
|
||||
throw new RuntimeException("copyFrom error", ex);
|
||||
}
|
||||
// ReflectiveOperationException is not available on Android (Java 1.6)
|
||||
/*
|
||||
catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException ("copyFrom error", ex);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
public class MessageException extends Exception {
|
||||
|
||||
public MessageException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MessageException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface MessageType {
|
||||
String string() default "";
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.jilk.ros.message;
|
||||
|
||||
/**
|
||||
* Created by xxhong on 16-11-17.
|
||||
*/
|
||||
@MessageType(string = "std_msgs/String")
|
||||
public class SemanticRequest extends Message {
|
||||
public SemanticRequest(String args) {
|
||||
jsonStr = args;
|
||||
}
|
||||
|
||||
public String jsonStr;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.jilk.ros.message;
|
||||
|
||||
/**
|
||||
* Created by xxhong on 16-11-17.
|
||||
*/
|
||||
@MessageType(string = "std_msgs/String")
|
||||
public class SemanticResponse extends Message {
|
||||
public String result;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.jilk.ros.message;
|
||||
|
||||
/**
|
||||
* Created by xxhong on 16-11-17.
|
||||
*/
|
||||
@MessageType(string = "std_msgs/String")
|
||||
public class StdMsg extends Message {
|
||||
public String data;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "std_msgs/Time")
|
||||
public class Time extends TimePrimitive {
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.message;
|
||||
|
||||
@MessageType(string = "time")
|
||||
public class TimePrimitive extends Message {
|
||||
public int secs; // when requesting this format from ROSbridge, it uses 'sec' (no 's')
|
||||
public int nsecs; // when requesting this format from ROSbridge, it uses 'nsec'
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "std_msgs/Empty")
|
||||
public class Empty extends Message {
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
import com.jilk.ros.message.TimePrimitive;
|
||||
|
||||
|
||||
@MessageType(string = "rosapi/GetTimeResponse")
|
||||
public class GetTime extends Message {
|
||||
public TimePrimitive time;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/MessageDetails")
|
||||
public class MessageDetails extends Message {
|
||||
public TypeDef[] typedefs;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/Nodes")
|
||||
public class Nodes extends Message {
|
||||
public String[] nodes;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/Service")
|
||||
public class Service extends Message {
|
||||
public String service;
|
||||
|
||||
public Service() {}
|
||||
|
||||
public Service(String service) {
|
||||
this.service = service;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/Services")
|
||||
public class Services extends Message {
|
||||
public String[] services;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/Topic")
|
||||
public class Topic extends Message {
|
||||
public String topic;
|
||||
|
||||
public Topic() {}
|
||||
|
||||
public Topic(String topic) {
|
||||
this.topic = topic;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/Topics")
|
||||
public class Topics extends Message {
|
||||
public String[] topics;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/Type")
|
||||
public class Type extends Message {
|
||||
public String type;
|
||||
|
||||
public Type() {}
|
||||
|
||||
public Type(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosapi.message;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "rosapi/TypeDef")
|
||||
public class TypeDef extends Message {
|
||||
public String type;
|
||||
public String[] fieldnames;
|
||||
public String[] fieldtypes;
|
||||
public int[] fieldarraylen;
|
||||
public String[] examples;
|
||||
|
||||
public static boolean match(String type, Class c) {
|
||||
boolean result = false;
|
||||
if (
|
||||
(type.equals("bool") && ((boolean.class.equals(c)) || (Boolean.class.equals(c)))) ||
|
||||
(type.equals("int8") && ((byte.class.equals(c)) || (Byte.class.equals(c)))) ||
|
||||
(type.equals("byte") && ((byte.class.equals(c)) || (Byte.class.equals(c)))) || // deprecated
|
||||
(type.equals("uint8") && ((short.class.equals(c)) || (Short.class.equals(c)))) ||
|
||||
(type.equals("char") && ((short.class.equals(c)) || (Short.class.equals(c)))) || // deprecated
|
||||
(type.equals("int16") && ((short.class.equals(c)) || (Short.class.equals(c)))) ||
|
||||
(type.equals("uint16") && ((int.class.equals(c)) || (Integer.class.equals(c)))) ||
|
||||
(type.equals("int32") && ((int.class.equals(c)) || (Integer.class.equals(c)))) ||
|
||||
(type.equals("uint32") && ((long.class.equals(c)) || (Long.class.equals(c)))) ||
|
||||
(type.equals("int64") && ((long.class.equals(c)) || (Long.class.equals(c)))) ||
|
||||
(type.equals("float32") && ((float.class.equals(c)) || (Float.class.equals(c)))) ||
|
||||
(type.equals("float64") && ((double.class.equals(c)) || (Double.class.equals(c)))) ||
|
||||
(type.equals("uint64") && (java.math.BigInteger.class.equals(c))) ||
|
||||
(type.equals("string") && (String.class.equals(c)))
|
||||
)
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
|
||||
public interface FullMessageHandler<T extends Message> {
|
||||
public void onMessage(String id, T message);
|
||||
}
|
@ -0,0 +1,260 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge;
|
||||
|
||||
import com.jilk.ros.ROSClient;
|
||||
import com.jilk.ros.Service;
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
import com.jilk.ros.rosapi.message.Empty;
|
||||
import com.jilk.ros.rosapi.message.MessageDetails;
|
||||
import com.jilk.ros.rosapi.message.Nodes;
|
||||
import com.jilk.ros.rosapi.message.Services;
|
||||
import com.jilk.ros.rosapi.message.Topic;
|
||||
import com.jilk.ros.rosapi.message.Topics;
|
||||
import com.jilk.ros.rosapi.message.Type;
|
||||
import com.jilk.ros.rosapi.message.TypeDef;
|
||||
import com.jilk.ros.rosbridge.implementation.ROSBridgeWebSocketClient;
|
||||
import com.jilk.ros.rosbridge.operation.Operation;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ROSBridgeClient extends ROSClient {
|
||||
String uriString;
|
||||
ROSBridgeWebSocketClient client;
|
||||
|
||||
public ROSBridgeClient(String uriString) {
|
||||
this.uriString = uriString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connect() {
|
||||
return connect(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connect(ConnectionStatusListener listener) {
|
||||
boolean result = false;
|
||||
client = ROSBridgeWebSocketClient.create(uriString);
|
||||
if (client != null) {
|
||||
client.setListener(listener);
|
||||
try {
|
||||
result = client.connectBlocking();
|
||||
}
|
||||
catch (InterruptedException ex) {}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
try {
|
||||
client.closeBlocking();
|
||||
}
|
||||
catch (InterruptedException ex) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Operation operation) {
|
||||
client.send(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String json) {
|
||||
client.send(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Class<? extends Operation> c,
|
||||
String s,
|
||||
Class<? extends Message> m,
|
||||
FullMessageHandler h) {
|
||||
client.register(c, s, m, h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(Class<? extends Operation> c, String s) {
|
||||
client.unregister(c, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDebug(boolean debug) {
|
||||
client.setDebug(debug);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getNodes() throws InterruptedException {
|
||||
Service<Empty, Nodes> nodeService =
|
||||
new Service<Empty, Nodes>("/rosapi/nodes", Empty.class, Nodes.class, this);
|
||||
return nodeService.callBlocking(new Empty()).nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTopics() throws InterruptedException {
|
||||
Service<Empty, Topics> topicsService =
|
||||
new Service<Empty, Topics>("/rosapi/topics", Empty.class, Topics.class, this);
|
||||
return topicsService.callBlocking(new Empty()).topics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServices() throws InterruptedException {
|
||||
Service<Empty, Services> servicesService =
|
||||
new Service<Empty, Services>("/rosapi/services", Empty.class, Services.class, this);
|
||||
return servicesService.callBlocking(new Empty()).services;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef getTopicMessageDetails(String topic) throws InterruptedException {
|
||||
return getTypeDetails(getTopicType(topic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef[] getTopicMessageList(String topic) throws InterruptedException {
|
||||
return getTypeList(getTopicType(topic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef getServiceRequestDetails(String service) throws InterruptedException {
|
||||
return getTypeDetails(getServiceType(service), "Request", "/rosapi/service_request_details");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef[] getServiceRequestList(String service) throws InterruptedException {
|
||||
return getTypeList(getServiceType(service), "Request", "/rosapi/service_request_details");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef getServiceResponseDetails(String service) throws InterruptedException {
|
||||
return getTypeDetails(getServiceType(service), "Response", "/rosapi/service_response_details");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef[] getServiceResponseList(String service) throws InterruptedException {
|
||||
return getTypeList(getServiceType(service), "Response", "/rosapi/service_response_details");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef[] getTypeList(String type) throws InterruptedException {
|
||||
return getTypeList(type, "", "/rosapi/message_details");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDef getTypeDetails(String type) throws InterruptedException {
|
||||
return getTypeDetails(type, "", "/rosapi/message_details");
|
||||
}
|
||||
|
||||
private TypeDef[] getTypeList(String type, String suffix, String serviceName) throws InterruptedException {
|
||||
Service<Type, MessageDetails> messageDetailsService =
|
||||
new Service<Type, MessageDetails>(serviceName,
|
||||
Type.class, MessageDetails.class, this);
|
||||
return messageDetailsService.callBlocking(new Type(type)).typedefs;
|
||||
}
|
||||
|
||||
private TypeDef getTypeDetails(String type, String suffix, String serviceName) throws InterruptedException {
|
||||
Service<Type, MessageDetails> messageDetailsService =
|
||||
new Service<Type, MessageDetails>(serviceName,
|
||||
Type.class, MessageDetails.class, this);
|
||||
return findType(type + suffix, messageDetailsService.callBlocking(new Type(type)).typedefs);
|
||||
}
|
||||
|
||||
private String getTopicType(String topic) throws InterruptedException {
|
||||
Service<Topic, Type> topicTypeService =
|
||||
new Service<Topic, Type>("/rosapi/topic_type",
|
||||
Topic.class, Type.class, this);
|
||||
return topicTypeService.callBlocking(new Topic(topic)).type;
|
||||
}
|
||||
|
||||
private String getServiceType(String service) throws InterruptedException {
|
||||
Service<com.jilk.ros.rosapi.message.Service, Type> serviceTypeService =
|
||||
new Service<com.jilk.ros.rosapi.message.Service, Type>("/rosapi/service_type",
|
||||
com.jilk.ros.rosapi.message.Service.class, Type.class, this);
|
||||
return serviceTypeService.callBlocking(new com.jilk.ros.rosapi.message.Service(service)).type;
|
||||
}
|
||||
|
||||
private TypeDef findType(String type, TypeDef[] types) {
|
||||
TypeDef result = null;
|
||||
for (TypeDef t : types) {
|
||||
if (t.type.equals(type)) {
|
||||
result = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//System.out.println("ROSBridgeClient.findType: ");
|
||||
//result.print();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void typeMatch(TypeDef t, Class<? extends Message> c) throws InterruptedException {
|
||||
if (c == null)
|
||||
throw new RuntimeException("No registered message type found for: " + t.type);
|
||||
Field[] fields = c.getFields();
|
||||
for (int i = 0; i < t.fieldnames.length; i++) {
|
||||
|
||||
// Field names
|
||||
String classFieldName = fields[i].getName();
|
||||
String typeFieldName = t.fieldnames[i];
|
||||
if (!classFieldName.equals(typeFieldName))
|
||||
typeMatchError(t, c, "field name", typeFieldName, classFieldName);
|
||||
|
||||
// Array type of field
|
||||
boolean typeIsArray = (t.fieldarraylen[i] >= 0);
|
||||
boolean fieldIsArray = fields[i].getType().isArray();
|
||||
if (typeIsArray != fieldIsArray)
|
||||
typeMatchError(t, c, "array mismatch", typeFieldName, classFieldName);
|
||||
|
||||
// Get base type of field
|
||||
Class fieldClass = fields[i].getType();
|
||||
if (fieldIsArray)
|
||||
fieldClass = fields[i].getType().getComponentType();
|
||||
String type = t.fieldtypes[i];
|
||||
|
||||
// Field type for primitivesclient
|
||||
if (Message.isPrimitive(fieldClass)) {
|
||||
if (!TypeDef.match(type, fieldClass))
|
||||
typeMatchError(t, c, "type mismatch", type, fieldClass.getName());
|
||||
}
|
||||
|
||||
// Field type for non-primitive classes, and recurse
|
||||
else {
|
||||
if (!Message.class.isAssignableFrom(fieldClass))
|
||||
throw new RuntimeException("Member " + classFieldName +
|
||||
" of class " + fieldClass.getName() + " does not extend Message.");
|
||||
String fieldClassString = ((MessageType) fieldClass.getAnnotation(MessageType.class)).string();
|
||||
if (!type.equals(fieldClassString))
|
||||
typeMatchError(t, c, "message type mismatch", type, fieldClassString);
|
||||
typeMatch(getTypeDetails(type), fieldClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void typeMatchError(TypeDef t, Class<? extends Message> c,
|
||||
String error, String tString, String cString) {
|
||||
throw new RuntimeException("Type match error between " +
|
||||
t.type + " and " + c.getName() + ": " +
|
||||
error + ": \'" + tString + "\' does not match \'" + cString + "\'.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getUnderlyingClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,575 @@
|
||||
package com.jilk.ros.rosbridge.implementation;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/** A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance
|
||||
* with RFC 2045.<br><br>
|
||||
* On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster
|
||||
* on small arrays (10 - 1000 bytes) and 2-3 times as fast on larger arrays (10000 - 1000000 bytes)
|
||||
* compared to <code>sun.misc.Encoder()/Decoder()</code>.<br><br>
|
||||
*
|
||||
* On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and
|
||||
* about 50% faster for decoding large arrays. This implementation is about twice as fast on very small
|
||||
* arrays (< 30 bytes). If source/destination is a <code>String</code> this
|
||||
* version is about three times as fast due to the fact that the Commons Codec result has to be recoded
|
||||
* to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br><br>
|
||||
*
|
||||
* This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only
|
||||
* allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
|
||||
* as large as algorithms that create a temporary array. (E.g. Jakarta Commons Codec). It is unknown
|
||||
* whether Sun's <code>sun.misc.Encoder()/Decoder()</code> produce temporary arrays but since performance
|
||||
* is quite low it probably does.<br><br>
|
||||
*
|
||||
* The encoder produces the same output as the Sun one except that the Sun's encoder appends
|
||||
* a trailing line separator if the last character isn't a pad. Unclear why but it only adds to the
|
||||
* length and is probably a side effect. Both are in conformance with RFC 2045 though.<br>
|
||||
* Commons codec seem to always att a trailing line separator.<br><br>
|
||||
*
|
||||
* <b>Note!</b>
|
||||
* The encode/decode method pairs (types) come in three versions with the <b>exact</b> same algorithm and
|
||||
* thus a lot of code redundancy. This is to not create any temporary arrays for transcoding to/from different
|
||||
* format types. The methods not used can simply be commented out.<br><br>
|
||||
*
|
||||
* There is also a "fast" version of all decode methods that works the same way as the normal ones, but
|
||||
* har a few demands on the decoded input. Normally though, these fast verions should be used if the source if
|
||||
* the input is known and it hasn't bee tampered with.<br><br>
|
||||
*
|
||||
* If you find the code useful or you find a bug, please send me a note at base64 @ miginfocom . com.
|
||||
*
|
||||
* Licence (BSD):
|
||||
* ==============
|
||||
*
|
||||
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
|
||||
* 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 the MiG InfoCom AB 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.
|
||||
*
|
||||
* @version 2.2
|
||||
* @author Mikael Grev
|
||||
* Date: 2004-aug-02
|
||||
* Time: 11:31:11
|
||||
*/
|
||||
|
||||
public class Base64
|
||||
{
|
||||
private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
|
||||
private static final int[] IA = new int[256];
|
||||
static {
|
||||
Arrays.fill(IA, -1);
|
||||
for (int i = 0, iS = CA.length; i < iS; i++)
|
||||
IA[CA[i]] = i;
|
||||
IA['='] = 0;
|
||||
}
|
||||
|
||||
// ****************************************************************************************
|
||||
// * char[] version
|
||||
// ****************************************************************************************
|
||||
|
||||
/** Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045.
|
||||
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
|
||||
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
|
||||
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
|
||||
* little faster.
|
||||
* @return A BASE64 encoded array. Never <code>null</code>.
|
||||
*/
|
||||
public final static char[] encodeToChar(byte[] sArr, boolean lineSep)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = sArr != null ? sArr.length : 0;
|
||||
if (sLen == 0)
|
||||
return new char[0];
|
||||
|
||||
int eLen = (sLen / 3) * 3; // Length of even 24-bits.
|
||||
int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
|
||||
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
|
||||
char[] dArr = new char[dLen];
|
||||
|
||||
// Encode even 24-bits
|
||||
for (int s = 0, d = 0, cc = 0; s < eLen;) {
|
||||
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
|
||||
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
|
||||
|
||||
// Encode the int into four chars
|
||||
dArr[d++] = CA[(i >>> 18) & 0x3f];
|
||||
dArr[d++] = CA[(i >>> 12) & 0x3f];
|
||||
dArr[d++] = CA[(i >>> 6) & 0x3f];
|
||||
dArr[d++] = CA[i & 0x3f];
|
||||
|
||||
// Add optional line separator
|
||||
if (lineSep && ++cc == 19 && d < dLen - 2) {
|
||||
dArr[d++] = '\r';
|
||||
dArr[d++] = '\n';
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad and encode last bits if source isn't even 24 bits.
|
||||
int left = sLen - eLen; // 0 - 2.
|
||||
if (left > 0) {
|
||||
// Prepare the int
|
||||
int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
|
||||
|
||||
// Set last four chars
|
||||
dArr[dLen - 4] = CA[i >> 12];
|
||||
dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
|
||||
dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
|
||||
dArr[dLen - 1] = '=';
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
|
||||
* and without line separators.
|
||||
* @param sArr The source array. <code>null</code> or length 0 will return an empty array.
|
||||
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
|
||||
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
|
||||
*/
|
||||
public final static byte[] decode(char[] sArr)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = sArr != null ? sArr.length : 0;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
|
||||
// so we don't have to reallocate & copy it later.
|
||||
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
|
||||
for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
|
||||
if (IA[sArr[i]] < 0)
|
||||
sepCnt++;
|
||||
|
||||
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
|
||||
if ((sLen - sepCnt) % 4 != 0)
|
||||
return null;
|
||||
|
||||
int pad = 0;
|
||||
for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;)
|
||||
if (sArr[i] == '=')
|
||||
pad++;
|
||||
|
||||
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
|
||||
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
for (int s = 0, d = 0; d < len;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = 0;
|
||||
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
|
||||
int c = IA[sArr[s++]];
|
||||
if (c >= 0)
|
||||
i |= c << (18 - j * 6);
|
||||
else
|
||||
j--;
|
||||
}
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
if (d < len) {
|
||||
dArr[d++]= (byte) (i >> 8);
|
||||
if (d < len)
|
||||
dArr[d++] = (byte) i;
|
||||
}
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
|
||||
* fast as {@link #decode(char[])}. The preconditions are:<br>
|
||||
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
|
||||
* + Line separator must be "\r\n", as specified in RFC 2045
|
||||
* + The array must not contain illegal characters within the encoded string<br>
|
||||
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
|
||||
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0.
|
||||
*/
|
||||
public final static byte[] decodeFast(char[] sArr)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = sArr.length;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
|
||||
|
||||
// Trim illegal chars from start
|
||||
while (sIx < eIx && IA[sArr[sIx]] < 0)
|
||||
sIx++;
|
||||
|
||||
// Trim illegal chars from end
|
||||
while (eIx > 0 && IA[sArr[eIx]] < 0)
|
||||
eIx--;
|
||||
|
||||
// get the padding count (=) (0, 1 or 2)
|
||||
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
|
||||
int cCnt = eIx - sIx + 1; // Content count including possible separators
|
||||
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
|
||||
|
||||
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
// Decode all but the last 0 - 2 bytes.
|
||||
int d = 0;
|
||||
for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
dArr[d++] = (byte) i;
|
||||
|
||||
// If line separator, jump over it.
|
||||
if (sepCnt > 0 && ++cc == 19) {
|
||||
sIx += 2;
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (d < len) {
|
||||
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||
int i = 0;
|
||||
for (int j = 0; sIx <= eIx - pad; j++)
|
||||
i |= IA[sArr[sIx++]] << (18 - j * 6);
|
||||
|
||||
for (int r = 16; d < len; r -= 8)
|
||||
dArr[d++] = (byte) (i >> r);
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
|
||||
// ****************************************************************************************
|
||||
// * byte[] version
|
||||
// ****************************************************************************************
|
||||
|
||||
/** Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
|
||||
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
|
||||
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
|
||||
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
|
||||
* little faster.
|
||||
* @return A BASE64 encoded array. Never <code>null</code>.
|
||||
*/
|
||||
public final static byte[] encodeToByte(byte[] sArr, boolean lineSep)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = sArr != null ? sArr.length : 0;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int eLen = (sLen / 3) * 3; // Length of even 24-bits.
|
||||
int cCnt = ((sLen - 1) / 3 + 1) << 2; // Returned character count
|
||||
int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
|
||||
byte[] dArr = new byte[dLen];
|
||||
|
||||
// Encode even 24-bits
|
||||
for (int s = 0, d = 0, cc = 0; s < eLen;) {
|
||||
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
|
||||
int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
|
||||
|
||||
// Encode the int into four chars
|
||||
dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
|
||||
dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
|
||||
dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
|
||||
dArr[d++] = (byte) CA[i & 0x3f];
|
||||
|
||||
// Add optional line separator
|
||||
if (lineSep && ++cc == 19 && d < dLen - 2) {
|
||||
dArr[d++] = '\r';
|
||||
dArr[d++] = '\n';
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Pad and encode last bits if source isn't an even 24 bits.
|
||||
int left = sLen - eLen; // 0 - 2.
|
||||
if (left > 0) {
|
||||
// Prepare the int
|
||||
int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
|
||||
|
||||
// Set last four chars
|
||||
dArr[dLen - 4] = (byte) CA[i >> 12];
|
||||
dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
|
||||
dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
|
||||
dArr[dLen - 1] = '=';
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
|
||||
* and without line separators.
|
||||
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
|
||||
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
|
||||
*/
|
||||
public final static byte[] decode(byte[] sArr)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = sArr.length;
|
||||
|
||||
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
|
||||
// so we don't have to reallocate & copy it later.
|
||||
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
|
||||
for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
|
||||
if (IA[sArr[i] & 0xff] < 0)
|
||||
sepCnt++;
|
||||
|
||||
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
|
||||
if ((sLen - sepCnt) % 4 != 0)
|
||||
return null;
|
||||
|
||||
int pad = 0;
|
||||
for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;)
|
||||
if (sArr[i] == '=')
|
||||
pad++;
|
||||
|
||||
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
|
||||
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
for (int s = 0, d = 0; d < len;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = 0;
|
||||
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
|
||||
int c = IA[sArr[s++] & 0xff];
|
||||
if (c >= 0)
|
||||
i |= c << (18 - j * 6);
|
||||
else
|
||||
j--;
|
||||
}
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
if (d < len) {
|
||||
dArr[d++]= (byte) (i >> 8);
|
||||
if (d < len)
|
||||
dArr[d++] = (byte) i;
|
||||
}
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
|
||||
|
||||
/** Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
|
||||
* fast as {@link #decode(byte[])}. The preconditions are:<br>
|
||||
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
|
||||
* + Line separator must be "\r\n", as specified in RFC 2045
|
||||
* + The array must not contain illegal characters within the encoded string<br>
|
||||
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
|
||||
* @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0.
|
||||
*/
|
||||
public final static byte[] decodeFast(byte[] sArr)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = sArr.length;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
|
||||
|
||||
// Trim illegal chars from start
|
||||
while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0)
|
||||
sIx++;
|
||||
|
||||
// Trim illegal chars from end
|
||||
while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0)
|
||||
eIx--;
|
||||
|
||||
// get the padding count (=) (0, 1 or 2)
|
||||
int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end.
|
||||
int cCnt = eIx - sIx + 1; // Content count including possible separators
|
||||
int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1 : 0;
|
||||
|
||||
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
// Decode all but the last 0 - 2 bytes.
|
||||
int d = 0;
|
||||
for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
dArr[d++] = (byte) i;
|
||||
|
||||
// If line separator, jump over it.
|
||||
if (sepCnt > 0 && ++cc == 19) {
|
||||
sIx += 2;
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (d < len) {
|
||||
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||
int i = 0;
|
||||
for (int j = 0; sIx <= eIx - pad; j++)
|
||||
i |= IA[sArr[sIx++]] << (18 - j * 6);
|
||||
|
||||
for (int r = 16; d < len; r -= 8)
|
||||
dArr[d++] = (byte) (i >> r);
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
|
||||
// ****************************************************************************************
|
||||
// * String version
|
||||
// ****************************************************************************************
|
||||
|
||||
/** Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
|
||||
* @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
|
||||
* @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
|
||||
* No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
|
||||
* little faster.
|
||||
* @return A BASE64 encoded array. Never <code>null</code>.
|
||||
*/
|
||||
public final static String encodeToString(byte[] sArr, boolean lineSep)
|
||||
{
|
||||
// Reuse char[] since we can't create a String incrementally anyway and StringBuffer/Builder would be slower.
|
||||
return new String(encodeToChar(sArr, lineSep));
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with
|
||||
* and without line separators.<br>
|
||||
* <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That
|
||||
* will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
|
||||
* @param str The source string. <code>null</code> or length 0 will return an empty array.
|
||||
* @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
|
||||
* (including '=') isn't divideable by 4. (I.e. definitely corrupted).
|
||||
*/
|
||||
public final static byte[] decode(String str)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = str != null ? str.length() : 0;
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
// Count illegal characters (including '\r', '\n') to know what size the returned array will be,
|
||||
// so we don't have to reallocate & copy it later.
|
||||
int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that's a bonus...)
|
||||
for (int i = 0; i < sLen; i++) // If input is "pure" (I.e. no line separators or illegal chars) base64 this loop can be commented out.
|
||||
if (IA[str.charAt(i)] < 0)
|
||||
sepCnt++;
|
||||
|
||||
// Check so that legal chars (including '=') are evenly divideable by 4 as specified in RFC 2045.
|
||||
if ((sLen - sepCnt) % 4 != 0)
|
||||
return null;
|
||||
|
||||
// Count '=' at end
|
||||
int pad = 0;
|
||||
for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;)
|
||||
if (str.charAt(i) == '=')
|
||||
pad++;
|
||||
|
||||
int len = ((sLen - sepCnt) * 6 >> 3) - pad;
|
||||
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
for (int s = 0, d = 0; d < len;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = 0;
|
||||
for (int j = 0; j < 4; j++) { // j only increased if a valid char was found.
|
||||
int c = IA[str.charAt(s++)];
|
||||
if (c >= 0)
|
||||
i |= c << (18 - j * 6);
|
||||
else
|
||||
j--;
|
||||
}
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
if (d < len) {
|
||||
dArr[d++]= (byte) (i >> 8);
|
||||
if (d < len)
|
||||
dArr[d++] = (byte) i;
|
||||
}
|
||||
}
|
||||
return dArr;
|
||||
}
|
||||
|
||||
/** Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
|
||||
* fast as {@link #decode(String)}. The preconditions are:<br>
|
||||
* + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
|
||||
* + Line separator must be "\r\n", as specified in RFC 2045
|
||||
* + The array must not contain illegal characters within the encoded string<br>
|
||||
* + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
|
||||
* @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
|
||||
* @return The decoded array of bytes. May be of length 0.
|
||||
*/
|
||||
public final static byte[] decodeFast(String s)
|
||||
{
|
||||
// Check special case
|
||||
int sLen = s.length();
|
||||
if (sLen == 0)
|
||||
return new byte[0];
|
||||
|
||||
int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
|
||||
|
||||
// Trim illegal chars from start
|
||||
while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0)
|
||||
sIx++;
|
||||
|
||||
// Trim illegal chars from end
|
||||
while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0)
|
||||
eIx--;
|
||||
|
||||
// get the padding count (=) (0, 1 or 2)
|
||||
int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end.
|
||||
int cCnt = eIx - sIx + 1; // Content count including possible separators
|
||||
int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0;
|
||||
|
||||
int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
|
||||
byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
|
||||
|
||||
// Decode all but the last 0 - 2 bytes.
|
||||
int d = 0;
|
||||
for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
|
||||
// Assemble three bytes into an int from four "valid" characters.
|
||||
int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
|
||||
|
||||
// Add the bytes
|
||||
dArr[d++] = (byte) (i >> 16);
|
||||
dArr[d++] = (byte) (i >> 8);
|
||||
dArr[d++] = (byte) i;
|
||||
|
||||
// If line separator, jump over it.
|
||||
if (sepCnt > 0 && ++cc == 19) {
|
||||
sIx += 2;
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (d < len) {
|
||||
// Decode last 1-3 bytes (incl '=') into 1-3 bytes
|
||||
int i = 0;
|
||||
for (int j = 0; sIx <= eIx - pad; j++)
|
||||
i |= IA[s.charAt(sIx++)] << (18 - j * 6);
|
||||
|
||||
for (int r = 16; d < len; r -= 8)
|
||||
dArr[d++] = (byte) (i >> r);
|
||||
}
|
||||
|
||||
return dArr;
|
||||
}
|
||||
}
|
@ -0,0 +1,335 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.implementation;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.rosbridge.indication.Indication;
|
||||
import com.jilk.ros.rosbridge.operation.Wrapper;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
|
||||
// The slightly crazy abstractions here are designed to isolate knowledge of
|
||||
// the JSON library and data types from the Operation details of rosbridge.
|
||||
// Why is this important? A few reasons I can see. First, we might want
|
||||
// to change JSON libraries and this encapsulates all use of JSON-simple.
|
||||
// Second, as much as possible I would like the semantics of the rosbridge
|
||||
// protocol to be encapsulated in the Operation and its subclasses rather
|
||||
// than in a module that is essentially about serialization.
|
||||
//
|
||||
// Unfortunately the hierarchical Message abstraction is a bit broken
|
||||
// at the top level. Beginning at the actual operation (e.g., Publish), the
|
||||
// types of the fields are determined either by the fields themselves or by
|
||||
// an indicator. However, the type of the operation itself is not determined
|
||||
// this way, because the indicator is in the object itself, which means it
|
||||
// would have to be created before its type is known. Rather than build in
|
||||
// exceptions, I elected to create a "Wrapper" operation type that simply
|
||||
// wraps the concrete operation and copies its "op" field.
|
||||
//
|
||||
|
||||
public class JSON {
|
||||
|
||||
/**
|
||||
* Translates a Message recursively into JSON. Normally the Message is also an
|
||||
* Operation, but it does not have to be. The caller constructs a complete
|
||||
* message using @Operation and @Message types. This includes situations
|
||||
* where one or more fields are marked to be turned into arrays, using @AsArray.
|
||||
* @param m the @Message object to be recursively translated.
|
||||
* @return the complete JSON string.
|
||||
*/
|
||||
public static String toJSON(Message m) {
|
||||
JSONObject jo = convertObjectToJSONObject(m); // Object to JSON-Simple
|
||||
return jo.toJSONString(); // JSON-Simple to string
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates JSON into a hierarchical Operation/Message structure.
|
||||
* This includes handling fields that are @Indicated and @AsArray. If the
|
||||
* @Class parameter is a @Wrapper, this is a special case whereby the
|
||||
* object is wrapped to create a consistent hierarchy.
|
||||
* @param json the source JSON string
|
||||
* @param c the top level class of the JSON. Normally @Wrapper
|
||||
* @param r the @Registry containing topic registrations
|
||||
* @return the fully instantiated message hierarchy represented
|
||||
* by the JSON string.
|
||||
*/
|
||||
public static Message toMessage(String json, Class c, Registry<Class> r) {
|
||||
JSONObject joUnwrapped = convertStringToJSONObject(json); // String to JSON-Simple
|
||||
JSONObject jo = joUnwrapped;
|
||||
if (Wrapper.class.isAssignableFrom(c))
|
||||
jo = wrap(joUnwrapped, c); // wrap: a hack to make the hierarchy homogeneous
|
||||
return convertJSONObjectToMessage(jo, c, r); // JSON-Simple to Message
|
||||
}
|
||||
|
||||
// *** Create JSON from Messages *** //
|
||||
|
||||
// Translate the object into a JSON-Simple object, field-by-field,
|
||||
// recursively via convertElementToJSON.
|
||||
// except for the case where AsArray is indicated
|
||||
private static JSONObject convertObjectToJSONObject(Object o) {
|
||||
JSONObject result = new JSONObject();
|
||||
for (Field f : o.getClass().getFields()) {
|
||||
Object fieldObject = getFieldObject(f, o);
|
||||
if (fieldObject != null) {
|
||||
Object resultObject;
|
||||
if (Indication.isBase64Encoded(f))
|
||||
resultObject = convertByteArrayToBase64JSONString(fieldObject);
|
||||
else if (Indication.asArray(f))
|
||||
resultObject = convertObjectToJSONArray(fieldObject);
|
||||
else resultObject = convertElementToJSON(fieldObject);
|
||||
result.put(f.getName(), resultObject);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert an array type to a JSON-Simple array, element-by-element,
|
||||
// recursively via convertElementToJSON.
|
||||
private static JSONArray convertArrayToJSONArray(Object array) {
|
||||
JSONArray result = new JSONArray();
|
||||
for (int i = 0; i < Array.getLength(array); i++) {
|
||||
Object elementObject = Array.get(array, i);
|
||||
if (elementObject != null) {
|
||||
Object resultObject = convertElementToJSON(elementObject);
|
||||
result.add(resultObject);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// For AsArray objects, convert the object to a JSON-Simple array
|
||||
// NOTE: This relies on later versions of the JDK providing
|
||||
// the fields in order.
|
||||
private static JSONArray convertObjectToJSONArray(Object o) {
|
||||
JSONArray result = new JSONArray();
|
||||
for (Field f : o.getClass().getFields()) {
|
||||
Object fieldObject = getFieldObject(f, o);
|
||||
if (fieldObject != null) {
|
||||
Object resultObject = convertElementToJSON(fieldObject);
|
||||
result.add(resultObject);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert the individual field or array element items recursively
|
||||
private static Object convertElementToJSON(Object elementObject) {
|
||||
Class elementClass = elementObject.getClass();
|
||||
Object resultObject;
|
||||
if (Message.isPrimitive(elementClass))
|
||||
resultObject = elementObject;
|
||||
else if (elementClass.isArray())
|
||||
resultObject = convertArrayToJSONArray(elementObject);
|
||||
else
|
||||
resultObject = convertObjectToJSONObject(elementObject);
|
||||
return resultObject;
|
||||
}
|
||||
|
||||
// Special case for Base 64-encoded fields
|
||||
private static Object convertByteArrayToBase64JSONString(Object fieldObject) {
|
||||
return Base64.encodeToString((byte[]) fieldObject, false);
|
||||
}
|
||||
|
||||
// This is just to buffer the code from the exception. Better error
|
||||
// handling needed here.
|
||||
private static Object getFieldObject(Field f, Object o) {
|
||||
Object fo = null;
|
||||
try {
|
||||
fo = f.get(o);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return fo;
|
||||
}
|
||||
|
||||
// *** Create Messages from JSON *** //
|
||||
|
||||
// Use the JSON-simple parser to create the JSON-Simple object
|
||||
private static JSONObject convertStringToJSONObject(String json) {
|
||||
JSONObject result = null;
|
||||
StringReader r = new StringReader(json);
|
||||
JSONParser jp = new JSONParser();
|
||||
try {
|
||||
result = (JSONObject) jp.parse(r);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.out.println(t.getMessage());
|
||||
}
|
||||
r.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
// A bit of a hack to create a consistent hierarchy with jsonbridge operations
|
||||
// At least it does not depend on any specific field names, it just copies the
|
||||
// Indicator and Indicated fields.
|
||||
private static JSONObject wrap(JSONObject jo, Class c) {
|
||||
JSONObject result = new JSONObject();
|
||||
String indicatorName = Indication.getIndicatorName(c);
|
||||
String indicatedName = Indication.getIndicatedName(c);
|
||||
result.put(indicatorName, jo.get(indicatorName));
|
||||
result.put(indicatedName, jo);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert the JSON-Simple object to the indicated message, field-by-field
|
||||
// recursively via convertElementToField.
|
||||
private static Message convertJSONObjectToMessage(JSONObject jo, Class c, Registry<Class> r) {
|
||||
//System.out.println("JSON.convertJSONObjectToMessage: " + jo.toJSONString());
|
||||
try {
|
||||
Message result = (Message) c.newInstance();
|
||||
for (Field f : c.getFields()) {
|
||||
Class fc = getFieldClass(result, jo, f, r);
|
||||
Object lookup = jo.get(f.getName());
|
||||
if (lookup != null) {
|
||||
Object value = convertElementToField(lookup, fc, f, r);
|
||||
f.set(result, value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
//ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the JSON-Simple array to the indicated message, element-by-element
|
||||
// recursively via convertElementToField.
|
||||
private static Object convertJSONArrayToArray(JSONArray ja, Class c, Registry<Class> r) {
|
||||
Object result = Array.newInstance(c, ja.size());
|
||||
for (int i = 0; i < ja.size(); i++) {
|
||||
Object lookup = ja.get(i);
|
||||
Object value = null;
|
||||
if (lookup != null) {
|
||||
if (lookup.getClass().equals(JSONObject.class))
|
||||
value = convertJSONObjectToMessage((JSONObject) lookup, c, r);
|
||||
else if (lookup.getClass().equals(JSONArray.class)) // this is not actually allowed in ROS
|
||||
value = convertJSONArrayToArray((JSONArray) lookup, c.getComponentType(), r);
|
||||
else
|
||||
value = convertJSONPrimitiveToPrimitive(lookup, c);
|
||||
Array.set(result, i, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert a JSON-Simple array to a Message, field-by-field of the Message,
|
||||
// element-by-element of the array, recursively via convertElementToField.
|
||||
// NOTE: This relies on later versions of the JDK providing
|
||||
// the fields in order.
|
||||
private static Message convertJSONArrayToMessage(JSONArray ja, Class c, Registry<Class> r) {
|
||||
try {
|
||||
Message result = (Message) c.newInstance();
|
||||
int arrayIndex = 0;
|
||||
for (Field f : c.getFields()) {
|
||||
Class fc = getFieldClass(result, null, f, r);
|
||||
Object lookup = ja.get(arrayIndex++); // yes we are assuming that the fields are delivered in order
|
||||
if (lookup != null) {
|
||||
Object value = convertElementToField(lookup, fc, f, r);
|
||||
f.set(result, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an individual array or object element to a field in the Message,
|
||||
// recursively, and applying AsArray if needed.
|
||||
private static Object convertElementToField(Object element, Class fc, Field f, Registry<Class> r) {
|
||||
//System.out.println("JSON.convertElementToField: " + f.getName() + " " + fc.getName());
|
||||
Object value;
|
||||
if (element.getClass().equals(JSONObject.class)) {
|
||||
//System.out.println("JSON.convertElementToField: JSON Object " + ((JSONObject) element).toJSONString());
|
||||
value = convertJSONObjectToMessage((JSONObject) element, fc, r);
|
||||
}
|
||||
else if (element.getClass().equals(JSONArray.class)) {
|
||||
//System.out.println("JSON.convertElementToField: JSON Array " + ((JSONArray) element).toJSONString());
|
||||
if (Indication.asArray(f))
|
||||
value = convertJSONArrayToMessage((JSONArray) element, fc, r);
|
||||
else value = convertJSONArrayToArray((JSONArray) element, fc, r);
|
||||
}
|
||||
else {
|
||||
//System.out.println("JSON.convertElementToField: Primitive " + element);
|
||||
if (Indication.isBase64Encoded(f))
|
||||
value = convertBase64JSONStringToByteArray(element);
|
||||
else value = convertJSONPrimitiveToPrimitive(element, fc);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Note that this is not checking ranges
|
||||
public static Object convertJSONPrimitiveToPrimitive(Object o, Class c) {
|
||||
Object result = o;
|
||||
if (c.isPrimitive() || Number.class.isAssignableFrom(c)) {
|
||||
if (c.equals(double.class) || c.equals(Double.class))
|
||||
result = new Double(((Number) o).doubleValue());
|
||||
else if (c.equals(float.class) || c.equals(Float.class))
|
||||
result = new Float(((Number) o).floatValue());
|
||||
else if (c.equals(long.class) || c.equals(Long.class))
|
||||
result = new Long(((Number) o).longValue());
|
||||
else if (int.class.equals(c) || c.equals(Integer.class))
|
||||
result = new Integer(((Number) o).intValue());
|
||||
else if (c.equals(short.class) || c.equals(Short.class))
|
||||
result = new Short(((Number) o).shortValue());
|
||||
else if (c.equals(byte.class) || c.equals(Byte.class))
|
||||
result = new Byte(((Number) o).byteValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] convertBase64JSONStringToByteArray(Object element) {
|
||||
return Base64.decode((String) element);
|
||||
}
|
||||
|
||||
// Determine the target class of a field in the object or array, based
|
||||
// directly on the field's type, or using the Indicator if applicable,
|
||||
// The Indicator field only provides the topic/service, so we have to look
|
||||
// up the Class in the registry.
|
||||
public static Class getFieldClass(Message parent, JSONObject jo, Field f, Registry<Class> r) {
|
||||
Class fc;
|
||||
fc = f.getType();
|
||||
if (fc.isArray())
|
||||
fc = f.getType().getComponentType();
|
||||
if (Indication.isIndicated(f) && (jo != null)) {
|
||||
//fc = Indication.getIndication(parent,
|
||||
// (String) jo.get(Indication.getIndicatorName(parent.getClass())));
|
||||
fc = r.lookup(parent.getClass(),
|
||||
(String) jo.get(Indication.getIndicatorName(parent.getClass())));
|
||||
//System.out.println("JSON.getFieldClass: parent class " + parent.getClass().getName() +
|
||||
// " Indicator: " + Indication.getIndicatorName(parent.getClass()) +
|
||||
// " result: " + fc.getName());
|
||||
}
|
||||
return fc;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.jilk.ros.rosbridge.implementation;
|
||||
|
||||
import com.jilk.ros.rosbridge.operation.Operation;
|
||||
|
||||
/**EventBus event entity,describe ros server response info
|
||||
* Created by xxhong on 16-11-22.
|
||||
*/
|
||||
|
||||
public class PublishEvent {
|
||||
public String msg;
|
||||
public String id;
|
||||
public String name;
|
||||
public String op;
|
||||
|
||||
|
||||
public PublishEvent(Operation operation, String name, String content) {
|
||||
if(operation != null) {
|
||||
id = operation.id;
|
||||
op = operation.op;
|
||||
}
|
||||
this.name = name;
|
||||
msg = content;
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
* <p>
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
* <p>
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.implementation;
|
||||
|
||||
import com.jilk.ros.ROSClient;
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.rosbridge.FullMessageHandler;
|
||||
import com.jilk.ros.rosbridge.operation.Operation;
|
||||
import com.jilk.ros.rosbridge.operation.Publish;
|
||||
import com.jilk.ros.rosbridge.operation.ServiceResponse;
|
||||
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.framing.CloseFrame;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.Socket;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import de.greenrobot.event.EventBus;
|
||||
|
||||
public class ROSBridgeWebSocketClient extends WebSocketClient {
|
||||
private Registry<Class> classes;
|
||||
private Registry<FullMessageHandler> handlers;
|
||||
private boolean debug;
|
||||
private ROSClient.ConnectionStatusListener listener;
|
||||
|
||||
ROSBridgeWebSocketClient(URI serverURI) {
|
||||
super(serverURI);
|
||||
classes = new Registry<Class>();
|
||||
handlers = new Registry<FullMessageHandler>();
|
||||
Operation.initialize(classes); // note, this ensures that the Message Map is initialized too
|
||||
listener = null;
|
||||
}
|
||||
|
||||
public static ROSBridgeWebSocketClient create(String URIString) {
|
||||
ROSBridgeWebSocketClient client = null;
|
||||
try {
|
||||
URI uri = new URI(URIString);
|
||||
client = new ROSBridgeWebSocketClient(uri);
|
||||
} catch (URISyntaxException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
public void setListener(ROSClient.ConnectionStatusListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake handshakedata) {
|
||||
if (listener != null)
|
||||
listener.onConnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
if (debug) System.out.println("<ROS " + message);
|
||||
//System.out.println("ROSBridgeWebSocketClient.onMessage (message): " + message);
|
||||
Operation operation = Operation.toOperation(message, classes);
|
||||
//System.out.println("ROSBridgeWebSocketClient.onMessage (operation): ");
|
||||
//operation.print();
|
||||
|
||||
FullMessageHandler handler = null;
|
||||
Message msg = null;
|
||||
if (operation instanceof Publish) {
|
||||
Publish p = (Publish) operation;
|
||||
handler = handlers.lookup(Publish.class, p.topic);
|
||||
msg = p.msg;
|
||||
} else if (operation instanceof ServiceResponse) {
|
||||
ServiceResponse r = ((ServiceResponse) operation);
|
||||
handler = handlers.lookup(ServiceResponse.class, r.service);
|
||||
msg = r.values;
|
||||
}
|
||||
// later we will add clauses for Fragment, PNG, and Status. When rosbridge has it, we'll have one for service requests.
|
||||
|
||||
// need to handle "result: null" possibility for ROSBridge service responses
|
||||
// this is probably some sort of call to the operation for "validation." Do it
|
||||
// as part of error handling.
|
||||
|
||||
if (handler != null && message.contains("\"id\":"))
|
||||
handler.onMessage(operation.id, msg);
|
||||
else {
|
||||
if (debug)
|
||||
System.out.print("No handler: id# " + operation.id + ", op:" + operation.op);
|
||||
if (operation instanceof Publish) {
|
||||
Publish publish = ((Publish) operation);
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
try {
|
||||
JSONObject jsonObject = (JSONObject) jsonParser.parse(message);
|
||||
String content = jsonObject.get("msg").toString();
|
||||
EventBus.getDefault().post(new PublishEvent(operation, publish.topic, content));
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("Publish " + publish.topic);
|
||||
} else if (operation instanceof ServiceResponse) {
|
||||
ServiceResponse serviceResponse = ((ServiceResponse) operation);
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
try {
|
||||
JSONObject jsonObject = (JSONObject) jsonParser.parse(message);
|
||||
String content = jsonObject.get("values").toString();
|
||||
EventBus.getDefault().post(new PublishEvent(operation, serviceResponse.service, content));
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("Service Response " + serviceResponse.service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int code, String reason, boolean remote) {
|
||||
if (listener != null) {
|
||||
boolean normal = (remote || (code == CloseFrame.NORMAL));
|
||||
listener.onDisconnect(normal, reason, code);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
if (listener != null)
|
||||
listener.onError(ex);
|
||||
else ex.printStackTrace();
|
||||
}
|
||||
|
||||
// There is a bug in V1.2 of java_websockets that seems to appear only in Android, specifically,
|
||||
// it does not shut down the thread and starts using gobs of RAM (symptom is frequent garbage collection).
|
||||
// This method goes into the WebSocketClient object and hard-closes the socket, which causes the thread
|
||||
// to exit (note, just interrupting the thread does not work).
|
||||
@Override
|
||||
public void closeBlocking() throws InterruptedException {
|
||||
super.closeBlocking();
|
||||
try {
|
||||
Field channelField = this.getClass().getSuperclass().getDeclaredField("channel");
|
||||
channelField.setAccessible(true);
|
||||
SocketChannel channel = (SocketChannel) channelField.get(this);
|
||||
if (channel != null && channel.isOpen()) {
|
||||
Socket socket = channel.socket();
|
||||
if (socket != null)
|
||||
socket.close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Exception in Websocket close hack.");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void send(Operation operation) {
|
||||
String json = operation.toJSON();
|
||||
if (debug) System.out.println("ROS> " + json);
|
||||
send(json);
|
||||
}
|
||||
|
||||
public void register(Class<? extends Operation> c,
|
||||
String s,
|
||||
Class<? extends Message> m,
|
||||
FullMessageHandler h) {
|
||||
Message.register(m, classes.get(Message.class));
|
||||
classes.register(c, s, m);
|
||||
if (h != null)
|
||||
handlers.register(c, s, h);
|
||||
}
|
||||
|
||||
public void unregister(Class<? extends Operation> c, String s) {
|
||||
handlers.unregister(c, s);
|
||||
// Note that there is no concept of unregistering a class - it can get replaced is all
|
||||
}
|
||||
|
||||
public Class<? extends Message> getRegisteredMessage(String messageString) {
|
||||
return classes.lookup(Message.class, messageString);
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.implementation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Registry<T> extends HashMap<Class, Map<String, T>> {
|
||||
|
||||
public void register(Class c, String s, T t) {
|
||||
Map<String, T> table = get(c);
|
||||
if (table == null) {
|
||||
table = new HashMap<String, T>();
|
||||
put(c, table);
|
||||
}
|
||||
table.put(s, t);
|
||||
}
|
||||
|
||||
public void unregister(Class c, String s) {
|
||||
Map<String, T> table = get(c);
|
||||
if (table != null)
|
||||
table.remove(s);
|
||||
}
|
||||
|
||||
public T lookup(Class c, String s) {
|
||||
T result = null;
|
||||
Map<String, T> table = get(c);
|
||||
if (table != null)
|
||||
result = table.get(s);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.indication;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface AsArray {
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.indication;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Base64Encoded {
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.indication;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Indicate {
|
||||
// if later we want multiple indicated fields, use an int here
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.indication;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Indicated {
|
||||
// if later we want multiple indicated fields, use an int here
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.indication;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class Indication {
|
||||
public static boolean isIndicated(Field f) {
|
||||
return (f.getAnnotation(Indicated.class) != null);
|
||||
}
|
||||
|
||||
public static boolean asArray(Field f) {
|
||||
return (f.getAnnotation(AsArray.class) != null);
|
||||
}
|
||||
|
||||
public static boolean isBase64Encoded(Field f) {
|
||||
return ((f.getAnnotation(Base64Encoded.class) != null) &&
|
||||
f.getType().isArray() &&
|
||||
f.getType().getComponentType().equals(byte.class));
|
||||
}
|
||||
|
||||
public static String getIndicatorName(Class c) {
|
||||
return getName(c, Indicator.class);
|
||||
}
|
||||
|
||||
public static String getIndicatedName(Class c) {
|
||||
return getName(c, Indicated.class);
|
||||
}
|
||||
|
||||
private static String getName(Class c, Class annotation) {
|
||||
String result = null;
|
||||
for (Field f : c.getFields()) {
|
||||
if (f.getAnnotation(annotation) != null) {
|
||||
result = f.getName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
public static Class getIndication(Object o, String s) {
|
||||
Class c = o.getClass();
|
||||
Class result = null;
|
||||
try {
|
||||
Method m = getIndicateMethod(c);
|
||||
result = (Class) (m.invoke(o, s));
|
||||
}
|
||||
catch (ReflectiveOperationException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Method getIndicateMethod(Class c) {
|
||||
Method result = null;
|
||||
for (Method m : c.getMethods()) {
|
||||
if (m.getAnnotation(Indicate.class) != null) {
|
||||
result = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.indication;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Indicator {
|
||||
// if later we want multiple indicated fields, use an int here
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.operation;
|
||||
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "advertise")
|
||||
public class Advertise extends Operation {
|
||||
public String topic;
|
||||
public String type;
|
||||
|
||||
public Advertise() {}
|
||||
|
||||
public Advertise(String topic, String type) {
|
||||
this.topic = topic;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.operation;
|
||||
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "auth")
|
||||
public class Authenticate extends Operation {
|
||||
public String mac;
|
||||
public String client;
|
||||
public String dest;
|
||||
public String rand;
|
||||
public int t;
|
||||
public String level;
|
||||
public int end;
|
||||
|
||||
public Authenticate() {}
|
||||
|
||||
public Authenticate(
|
||||
String mac,
|
||||
String client,
|
||||
String dest,
|
||||
String rand,
|
||||
int t,
|
||||
String level,
|
||||
int end)
|
||||
{
|
||||
this.mac = mac;
|
||||
this.client = client;
|
||||
this.dest = dest;
|
||||
this.rand = rand;
|
||||
this.t = t;
|
||||
this.level = level;
|
||||
this.end = end;
|
||||
|
||||
this.id = null; // even though id is on EVERY OTHER operation type
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.operation;
|
||||
|
||||
import com.jilk.ros.message.Message;
|
||||
import com.jilk.ros.message.MessageType;
|
||||
import com.jilk.ros.rosbridge.indication.AsArray;
|
||||
import com.jilk.ros.rosbridge.indication.Indicated;
|
||||
import com.jilk.ros.rosbridge.indication.Indicator;
|
||||
|
||||
@MessageType(string = "call_service")
|
||||
public class CallService extends Operation {
|
||||
@Indicator public String service;
|
||||
@Indicated @AsArray public Message args;
|
||||
public Integer fragment_size; // use Integer for optional items
|
||||
public String compression;
|
||||
|
||||
public CallService() {}
|
||||
|
||||
public CallService(String service, Message args) {
|
||||
this.service = service;
|
||||
this.args = args;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2014 Jilk Systems, Inc.
|
||||
*
|
||||
* This file is part of the Java ROSBridge Client.
|
||||
*
|
||||
* The Java ROSBridge Client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Java ROSBridge Client is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Java ROSBridge Client. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
package com.jilk.ros.rosbridge.operation;
|
||||
|
||||
import com.jilk.ros.message.MessageType;
|
||||
|
||||
@MessageType(string = "fragment")
|
||||
public class Fragment extends Operation {
|
||||
public String data;
|
||||
public int num;
|
||||
public int total;
|
||||
|
||||
public Fragment() {}
|
||||
|
||||
public Fragment(String data, int num, int total) {
|
||||
this.data = data;
|
||||
this.num = num;
|
||||
this.total = total;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue