MIDI OUT transmitter not available - java

I've been banging my head on this all day, read everything I can find, followed the JDK source around, no luck in finding out the gory details about HOW or WHERE java looks to obtain data on a midi device and determines what's what.
I'm trying to capture midi messages through my NI Audio 8 DJ MIDI IN port, but, java isn't "seeing" the MIDI IN port, only the out, which I have successfully used to send midi with. I also get the same results with an M-Audio USB UNO midi device: MidiSystem.getMidiDeviceInfo() only "sees" the output port.
I have verified the operation of the MIDI IN port with:
amidi -p hw:2,0 -d
and sending it some signals. Works fine.
getMaxTransmitters() returns zero.
MidiSystem.getMidiDeviceInfo() shows only one entry for both devices: Audio8DJ [hw:2,0] or Interface [hw:2,0]
The code below works fine for a Receiver and I think is only the bits I need to verify that getTransmitter() grabs the port, since it just works for the other and everything works fine, up I get a MidiUnavailableException / Transmitter not available exception.
I've even taken the getMaxReceivers() trap out because I was just trying to see if the device only offered up the one entry and sorted it out, but no.
public static Transmitter getMidiIn () {
if (midiIn == null){
devices = MidiSystem.getMidiDeviceInfo();
for(MidiDevice.Info info: devices){
System.out.println("device class " + info.getClass());
MidiDevice device;
try{
device = MidiSystem.getMidiDevice(info);
if (info.toString().equals("Audio8DJ [hw:2,0]")){
if (device.getMaxTransmitters() != 0){
try{
device.open();
System.out.println("max transmitters:" + device.getMaxTransmitters());
midiIn = device.getTransmitter();
System.out.println("Found a transmitter: "+ midiIn);
break;
} catch (Exception e){
e.printStackTrace();
}
}
}
} catch (MidiUnavailableException e1){
e1.printStackTrace();
}
}
}
return midiIn;
}
So the thing that's getting me here is this: alsa lists only one entry in amidi -l and when I specify that as a port to dump, it works fine. Java gets that same text entry and can't sort out the MIDI IN, assigning it the com.sun.media.sound.MidiOutDeviceProvider class so it leaves me wondering just how does, or where does Java figure out what a device has to offer and why isn't it seeing the input port that alsa is seeing.
I'm coding with eclipse Version: 3.8.1 IDE with JDK1.6, on a linux mint OS, .
I'll be happy to provide anything asked for. Thanks for reading!

The solution to java seeing the transmitter was in the version of JDK being used, though unfortunately at this time, I do not have an answer as to why for the failure, just that one version worked and suits my needs for the time being. If I find that answer, I will edit this answer.
Of the three versions I was switching between for testing, jdk1.8.0_60, jdk1.7.0_80, jdk1.6.0_45, 1.7 did not experience the error and successfully obtained a transmitter from my device. I found this out, and that privileges were not the cause of my specific issue, by compiling and running some code I found suitable for command line execution that attempts to obtain the transmitter, prints out midi data sent to it, and modified it a little ...
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
public class MidiInputTest {
public MidiDevice input;
public MidiDevice output;
public static void main(String[] args) {
new MidiInputTest().start();
}
public void start() {
init(); // initialize your midi input device
// system dependent
try {
output.open(); // From midi device
MyReceiver myrcvr = new MyReceiver();
MidiSystem.getTransmitter().setReceiver(myrcvr);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
private class MyReceiver implements Receiver {
Receiver rcvr;
public MyReceiver() {
try {
this.rcvr = MidiSystem.getReceiver();
} catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
}
#Override
public void send(MidiMessage message, long timeStamp) {
byte[] b = message.getMessage();
if (b[0] != (byte)254) {
System.out.println((b[0] & 0xff) + " " + (b[1] & 0xff));
}
//rcvr.send(message, timeStamp); // will send out what ever you receive
}
#Override
public void close() {
rcvr.close();
}
}
public void init() {
MidiDevice.Info[] devices;
devices = MidiSystem.getMidiDeviceInfo();
try{
for (MidiDevice.Info info: devices) {
MidiDevice device;
device = MidiSystem.getMidiDevice(info);
System.out.println("MidiDevice.Info="+info + "\n" + "maxTransmitters="+device.getMaxTransmitters());
// I put the specific device I want to connect to behind an if gate here to avoid connecting to something I do not
if (info.toString().equals("Interface [hw:2,0,0]") && device.getMaxTransmitters() != 0) {
System.out.println(" Name: " + info.toString() +
", Decription: " +
info.getDescription() +
", Vendor: " +
info.getVendor());
output = MidiSystem.getMidiDevice(info);
if (! output.isOpen()) {
output.open();
}
}
}
} catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
}
}
To run this from the command line choose a version of JDK you have installed, compile and run it with those specific versions substituting jdk1.7.0_80 for the distro you wish to test.
/opt/java-jdk/jdk1.7.0_80/bin/javac MidiInputTest.java
/opt/java-jdk/jdk1.7.0_80/bin/java -cp . MidiInputTest
Though I haven't been able to verify it, Java Sound is apparently responsible for figuring out what is available for java's use from your MIDI architecture.
Thank you Mike Harris for sending me down the right path of testing on the command line, and jim829 over at java-forums.org for the example code for the command line.

I had this problem which was caused by multiple instances of device info with the same name reterned by MidiSystem.getMidiDeviceInfo(). Basically when you call MidiSystem.getMidiDevice(Info) if you're unlucky it'll return the one without the transmitter. I'm not sure why it does this but only one instance has transmitters, (I think one might be for in and one out but, not sure). By first getting just the devices that have transmitters and then selecting from these, with the desired info, it worked for me. Hope that helps
public ArrayList<MidiDevice> getTransmitterDevices() {
MidiDevice.Info[] deviceInfo = MidiSystem.getMidiDeviceInfo();
ArrayList<MidiDevice> transmitterDevices = new ArrayList<>();
for(int i=0;i<deviceInfo.length;i++) {
try {
MidiDevice device = MidiSystem.getMidiDevice(deviceInfo[i]);
if(device.getMaxTransmitters()!=0) {
transmitterDevices.add(device);
}
} catch (MidiUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return transmitterDevices;
}
//Somewhere else
//choose appropriate info somehow
MidiDevices<ArrayList> transmitterDevices = getTransmitterDevices();
for(MidiDevice tmp : transmitterDevices) {
if(tmp.getDeviceInfo().equals(info)) {
try {
midiController = tmp;
Transmitter transmitter = midiController.getTransmitter();
// something that implements receiver
midiReceiver = new MidiReceiver();
transmitter.setReceiver(midiReceiver);
midiController.open();
System.out.println("controller set ok");
} catch (MidiUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Related

Bluetooth, BlueCove and Raspberry PI

I setup using Java using BlueJ and Bluetooth using Blueman on my RaspberryPI and am using the BlueCove API.
I took the example RemoteDeviceDiscovery from:
http://bluecove.org/bluecove/apidocs/overview-summary.html#DeviceDiscovery
When I run the example from within BlueJ I get:
"
wait for device inquiry to complete...
Device Inquiry completed!
0 device(s) found
"
and when I run from the terminal window using:
pi#raspberrypi ~/java/bluetooth_jar $ /usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/jre/bin/java -jar bluetooth_jar.jar
I get:
"
BlueCove version 2.1.1-SNAPSHOT on bluez
BluetoothStateException exception: javax.bluetooth.BluetoothStateException: Bluetooth Device is not ready. [1] Operation not permitted
BlueCove stack shutdown completed
"
Why the exception is not thrown when using BlueJ I don't understand but from the commandline it appears unable to detect nearby devices because the device is not ready. However, I don't understand this error message since I can send files using Blueman Manager to nearby a Android tablet and Win7 laptop.
import java.io.IOException;
import java.util.ArrayList;
import javax.bluetooth.*;
/**
* Minimal Device Discovery example.
*/
public class RemoteDeviceDiscovery {
protected ArrayList<RemoteDevice> devicesDiscovered = new ArrayList();
protected final Object inquiryCompletedEvent = new Object();
public RemoteDeviceDiscovery()
{
DiscoveryListener listener = new MyDiscoveryListener();
synchronized(inquiryCompletedEvent) {
try
{
LocalDevice local = LocalDevice.getLocalDevice();
local.setDiscoverable(DiscoveryAgent.GIAC);
DiscoveryAgent discoveryAgent = local.getDiscoveryAgent();
// note: GIAC: The inquiry access code for General/Unlimited Inquiry Access Code (GIAC).
boolean startedInquiry = discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
if (startedInquiry)
{
System.out.println("wait for device inquiry to complete...");
inquiryCompletedEvent.wait();
System.out.println(devicesDiscovered.size() + " device(s) found");
}
}
catch ( BluetoothStateException e)
{
System.out.println("BluetoothStateException exception: " + e);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException exception: " + e);
}
}
}
public static void main(String[] args)
{
RemoteDeviceDiscovery rmd = new RemoteDeviceDiscovery();
}
class MyDiscoveryListener implements DiscoveryListener
{
public MyDiscoveryListener()
{
}
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
System.out.println("Device " + btDevice.getBluetoothAddress() + " found");
devicesDiscovered.add(btDevice);
try {
System.out.println(" name " + btDevice.getFriendlyName(false));
} catch (IOException cantGetDeviceName) {
}
}
public void inquiryCompleted(int discType) {
System.out.println("Device Inquiry completed!");
synchronized(inquiryCompletedEvent){
inquiryCompletedEvent.notifyAll();
}
}
public void serviceSearchCompleted(int transID, int respCode) {
}
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
}
} // class MyDiscoveryListener
} // class RemoteDeviceDiscovery
Discovered that if I run the jar with superuser rights then it works as expected:
pi#raspberrypi ~ sudo /java/bluetooth_jar $ /usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/jre/bin/java -jar bluetooth_jar.jar
with output:
BlueCove version 2.1.1-SNAPSHOT on bluez
wait for device inquiry to complete...
Device C4850852975B found
name GMSEED-PC
Device Inquiry completed!
1 device(s) found
BlueCove stack shutdown completed
and if I start BlueJ as superuser from the commandline rather than through the desktop menu item Menu|Programming|BlueJ; ie:
pi#raspberrypi ~ $ sudo bluej
and then the example app gives the same output.

Multiple files transfer protocol with "authentication" from Android to Server

I'm a newbie programmer looking for a way to implement a simple file transfer protocol on Android.
Problem:
Several Android phones need to connect to a server to receive/send a series of XML files saved in internal storage. The server needs to know which phone is requesting a connection so that it can save the files in the correct folder.
Possible solution/algorithm:
There are various tutorials/examples on how to send a file to a server, but none of them seem to implement some kind of "authentication".
Ideally I would like to implement the following (I'll use a metaphor):
Phone: Hello.
Server: Hi. Who are you and what do you want? [send/receive]
Phone A: I'm phone A and I would like to send files.
Server: How many files do you want to send, Phone A?
Phone A: 6 files, [+extra data like total size or whatever]
Server: Alright, you can begin the transfer.
Phone A: Transfers...
Server: I've succesfully received 6 files, have a good day. [stores the files in a PhoneA folder]
Phone A: Bye! [closes connection]
I realise this could very likely be made a lot more efficient, but I don't know where to begin...
Is it even possible to initiate a connection with a server and interact multiple times while waiting for responses?
Question :
Could anyone push me in the right direction somehow? Do I write my own protocol or can this be done with standard functionality? What are the best/easiest existing protocols for this kind of implementation?
I've found this article interesting but I don't see how it could be used for multiple files with authentication
Any help would be much appreciated!
This is easier than you think using old-school FTP, which I've used with success in collecting data from apps, and your server will surely support it.
Get a unique ID for each Android device using enter link description here. You get a 64-bit number (as a hex string) that is randomly generated on each device’s first boot. It's supposedly constant for the life of the device.
Import Apache Commons FTP and use the method describe here to create a directory name inside your working directory on the server with a name matching the unique id.
Use the same library to upload the files using FTP. You'll find many example of how to do this. It takes very minimal code.
Unlike your chat scenario, this is a very client-side solution, and phones you might not want to could upload files -- there's no blacklist -- but it's easy to implement.
For those interested in (terrible) code to perform various FTP functions, here's what worked for me.
It requires the apache commons ftp jar file which can be found on the internet.
//Button that starts it all
public void updateWorkordersList(View view) {
if (!CheckNetworkConnection.isOnline()) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(this);
String connectionString = prefs
.getString("connection_string", null);
String userName = prefs.getString("FTPusername", null);
DownloadFilesTask task = new DownloadFilesTask(connectionString,
userName);
task.execute();
Fragment frg = null;
frg = getFragmentManager()
.findFragmentByTag("buttonsContainer");
final FragmentTransaction ft = getFragmentManager()
.beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
}
}
private class DownloadFilesTask extends AsyncTask<Void, Void, Boolean> {
private FTPClient mFtpClient = new FTPClient();
private FTPFile[] mFileArray;
private String _address;
private String _user;
private String _pass;
public DownloadFilesTask(String ip, String user) {
_address = ip;
_user = user;
}
#Override
protected Boolean doInBackground(Void... params) {
try {
mFtpClient.setConnectTimeout(10 * 1000);
mFtpClient.connect(InetAddress.getByName("insert server here"));
boolean status = mFtpClient.login("username", "password");
if (FTPReply.isPositiveCompletion(mFtpClient.getReplyCode())) {
mFtpClient.setFileType(FTP.ASCII_FILE_TYPE);
mFtpClient.enterLocalPassiveMode();
mFileArray = mFtpClient.listFiles();
}
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//Download All Files
if (FTPReply.isPositiveCompletion(mFtpClient.getReplyCode())) {
File directory = null;
directory = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getPath());
for (FTPFile file : mFileArray) {
OutputStream outputStream = null;
try {
outputStream = new BufferedOutputStream(
new FileOutputStream(directory + "/"
+ file.getName()));
mFtpClient.setFileType(FTP.BINARY_FILE_TYPE);
mFtpClient.retrieveFile(file.getName(), outputStream);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//Upload All Files
if (FTPReply.isPositiveCompletion(mFtpClient.getReplyCode())) {
File directory = null;
directory = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getPath() + "/srvReady");
for (File file : directory.listFiles()) {
try {
FileInputStream srcFileStream = new FileInputStream(directory + "/" + file.getName());
boolean status = mFtpClient.storeFile(_user + "/" + file.getName(),
srcFileStream);
srcFileStream.close();
if (status){
file.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
try {
mFtpClient.logout();
mFtpClient.disconnect();
} catch (Exception e) {
// TODO: handle exception
}
return true;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(Boolean result) {
}
}
I figure this could be of some use might someone ever come across a similar problem.

errors when using the bluetooth sample code on android developer site

I am working to add Bluetooth capabilities to my app and ultimately the device that I want to use is a headset/earpiece. I have begun assembling the code and I partial functionality with it. When I got to the code for setting up a bluetooth connection by server, I got errors when adding the code. I have tried solving the problems through the hover over the error and autocorrect but every time I fix one problem a different on arises. This leads me to believe that I am missing something that autocorrect doesn't know about. I need some help fixing the errors. Useful suggestions for setting a bluetooth codin for the first time would also be appreciated. Errors are surrounded with ||#| xxx |||. Error 1:cannot be resolved. Error 2:cannot be resolved to a variable. Error 3:undefined for the type AcceptSocket.
import java.io.IOException;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
public class AcceptSocket extends Thread {
private static final String MY_UUID = null;
BluetoothServerSocket mmServerSocket;
public void AcceptThread() {
// Use a temporary object that is later asssigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = ||1|mBluetoothAdapter|||.listenUsingRfcommWithServiceRecord(||2|NAME|||,
MY_UUID);
} catch (IOException e) {
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
||3|manageConnectedSocket|||(socket);
mmServerSocket.close();
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
}
}
}
Error 1,2: There is no constant called NAME anywhere in the class.
Error 3: There is no method called manageConnectedSocket() in the class.
You can't just copy and paste something from the developer's page and expect it to work. It leads you in the correct direction and you have to fill in the missing pieces.

Music in Java (start/stop)

Ok, so I am making a game and the music changes when you are in different regions or if there is an interruption, like with an AI.
So I have JUST learned how to make music showup in my program, and now I am trying to make it stop, but I am unsure how to, below is a snippet of code where the music plays and then I try to overwite it with new music when an action occurs.
public static void songs(String word) {
String temp = word;
if (temp.equals("start")) {
try {
try {
blah = new FileInputStream("C:/Users/Austin/Desktop/Storage/programimages/game/battle.wav");
} catch (Throwable e) {
e.printStackTrace();
}
AudioStream as = new AudioStream(blah);
AudioPlayer.player.start(as);
System.out.println("going");
} catch (IOException e) {
System.err.println(e);
}
}
if (temp.equals("stop")) {
try {
try {
blah = new FileInputStream("C:/Users/Austin/Desktop/Storage/programimages/game/silence.wav");
} catch (Throwable e) {
e.printStackTrace();
}
AudioStream as = new AudioStream(blah);
AudioPlayer.player.stop(as);
System.out.println("stopping");
} catch (IOException e) {
System.err.println(e);
}
}
}
This is the only method I have been able to find that has the music play, but if you guys have any other suggestions please let me know.
Again, I want to have sound affects and music going, and right now all that happens is one song will play, and it will not stop under any circumstance until it hits the very end of its length. I want to be able to stop songs whenever a new one should come on, and also allow sound affects to pop up.
Thanks!
(since I am stuck on this and need an answer now I will probably repost on one or two more java sites so I can get a response ASAP, thank you though!!!!)
EDITED CODE: (still does not stop the current stream, any more suggestions appreciated)
public static void songs(String word) throws IOException {
String temp = word;
if (temp.equals("go")) {
try {
blah = new FileInputStream("C:/Users/Austin/Desktop/Storage/programimages/game/battle.wav");
} catch (Throwable e) {
e.printStackTrace();
}
AudioStream as = new AudioStream(blah);
AudioPlayer.player.start(as);
System.out.println("going");
}
if (temp.equals("stop")) {
//don't try and do things with a null object!
if (as != null) {
AudioPlayer.player.stop(as);
System.out.println("stopping1");
}
System.out.println("stopping2");
AudioPlayer.player.stop(as);
}
}
Currently you're creating a new AudioStream in your stop branch and calling the stop method using this. This is a different object to the one that is currently playing. Try making the AudioStream a class variable, and calling stop on that instead.
EDIT: at the top of the class containing your code...
class YourClass {
//the class member variable
private AudioStream as;
//[etc...]
In your start branch:
// 'as' has already been defined above
as = new AudioStream(blah);
AudioPlayer.player.start(as);
System.out.println("going");
In your stop branch:
try
{
//don't try and do things with a null object!
if (as != null)
{
AudioPlayer.player.stop(as);
}
System.out.println("stopping");
}
catch (IOException e)
{
System.err.println(e);
}
You may have trouble with the static identifier on your method - if you're calling this from within an instantiated class you don't need this.
I can't even access these sun.audio Objects on my Eclipse IDE--I know they are in rt.jar, but there is header info about them being proprietary and such.
Can the Java Sound library (javax.sound.sampled) handle what you want to do? Both Clip and SourceDataLine allow one to stop playback. That is a more usual way of playing sound, if you want to use native Java.
Playback into is here:
http://docs.oracle.com/javase/tutorial/sound/playing.html
But the documentation, overall, is not exactly rich with examples. There's example code at this site
http://www.jsresources.org/
and plenty of people here who could help if you run into problems with the native Java approach.

How do I discover peers and send messages in JXTA-JXSE 2.6?

Using JXTA 2.6 from http://jxse.kenai.com/ I want to create application that can run multiple peers on one or more hosts. The peers should be able to find each other in a group and send direct messages as well as propagate messages.
What would a simple hello world type of application look like that meet these requirements?
I created this question with the intention of supplying a tutorial like answer, an answer I tried very hard to find two months ago when starting to look at JXTA for a uni project. Feel free to add your own answers or improve on mine. I will wait a few days and accept the best one.
Introduction to JXTA 2.6 Peer discovery and pipe messaging
The guide I wish I had 2 months ago =)
After spending a lot of time during a university course building
a JXTA p2p application I feel a lot of the frustrations and
confusion I went through could have been avoided with a good
starting point.
The jar files you will need can be found here:
https://oss.sonatype.org/content/repositories/comkenaijxse-057/com/kenai/jxse/jxse/2.6/jxse-2.6.jar
http://sourceforge.net/projects/practicaljxta/files/lib-dependencies-2.6.zip/download
Throw them into Yourproject/lib, open up eclipse, create a new project "Yourproject" and it should sort out
importing the libraries for you.
You will soon come to realize that almost any information on the web is out dated, very out dated.
You will also run into a lot of very confusing error messages and most of them can be avoided by
going through this check list.
Is your firewall turned off or at least open for the ports you use?
You can disable iptables using "sudo service iptables stop" under Fedora.
Check spelling! Many times when joining groups or trying to send messages spelling the group name wrong or not using the
exact same advertisement when looking for peers and services or opening pipes will cause very confusing messages.
Was trying to figure out why my pipe connections timed out when I spotted the group names being "Net info" and "Net_info".
Are you using a JXTA home directory? One per each peer you run on the same computer?
Do you really use a unique peer id? The seed provided to IDFactory need to be long enough or else you will get duplicates.
Turn off SELinux. I have had SELinux turned off during the development but can imagine it causing errors.
While it is common to group all fields together I introduce them as I go to show where they are needed.
Note: This will not work in 2.7. Some issue with PSE membership I think.
public class Hello implements DiscoveryListener, PipeMsgListener {
// When developing you should handle these exceptions, I don't to lessen the clutter of start()
public static void main(String[] args) throws PeerGroupException, IOException {
// JXTA logs a lot, you can configure it setting level here
Logger.getLogger("net.jxta").setLevel(Level.ALL);
// Randomize a port to use with a number over 1000 (for non root on unix)
// JXTA uses TCP for incoming connections which will conflict if more than
// one Hello runs at the same time on one computer.
int port = 9000 + new Random().nextInt(100);
Hello hello = new Hello(port);
hello.start();
hello.fetch_advertisements();
}
private String peer_name;
private PeerID peer_id;
private File conf;
private NetworkManager manager;
public Hello(int port) {
// Add a random number to make it easier to identify by name, will also make sure the ID is unique
peer_name = "Peer " + new Random().nextInt(1000000);
// This is what you will be looking for in Wireshark instead of an IP, hint: filter by "jxta"
peer_id = IDFactory.newPeerID(PeerGroupID.defaultNetPeerGroupID, peer_name.getBytes());
// Here the local peer cache will be saved, if you have multiple peers this must be unique
conf = new File("." + System.getProperty("file.separator") + peer_name);
// Most documentation you will find use a deprecated network manager setup, use this one instead
// ADHOC is usually a good starting point, other alternatives include Edge and Rendezvous
try {
manager = new NetworkManager(
NetworkManager.ConfigMode.ADHOC,
peer_name, conf.toURI());
}
catch (IOException e) {
// Will be thrown if you specify an invalid directory in conf
e.printStackTrace();
}
NetworkConfigurator configurator;
try {
// Settings Configuration
configurator = manager.getConfigurator();
configurator.setTcpPort(port);
configurator.setTcpEnabled(true);
configurator.setTcpIncoming(true);
configurator.setTcpOutgoing(true);
configurator.setUseMulticast(true);
configurator.setPeerID(peer_id);
}
catch (IOException e) {
// Never caught this one but let me know if you do =)
e.printStackTrace();
}
}
private static final String subgroup_name = "Make sure this is spelled the same everywhere";
private static final String subgroup_desc = "...";
private static final PeerGroupID subgroup_id = IDFactory.newPeerGroupID(PeerGroupID.defaultNetPeerGroupID, subgroup_name.getBytes());
private static final String unicast_name = "This must be spelled the same too";
private static final String multicast_name = "Or else you will get the wrong PipeID";
private static final String service_name = "And dont forget it like i did a million times";
private PeerGroup subgroup;
private PipeService pipe_service;
private PipeID unicast_id;
private PipeID multicast_id;
private PipeID service_id;
private DiscoveryService discovery;
private ModuleSpecAdvertisement mdadv;
public void start() throws PeerGroupException, IOException {
// Launch the missiles, if you have logging on and see no exceptions
// after this is ran, then you probably have at least the jars setup correctly.
PeerGroup net_group = manager.startNetwork();
// Connect to our subgroup (all groups are subgroups of Netgroup)
// If the group does not exist, it will be automatically created
// Note this is suggested deprecated, not sure what the better way is
ModuleImplAdvertisement mAdv = null;
try {
mAdv = net_group.getAllPurposePeerGroupImplAdvertisement();
} catch (Exception ex) {
System.err.println(ex.toString());
}
subgroup = net_group.newGroup(subgroup_id, mAdv, subgroup_name, subgroup_desc);
// A simple check to see if connecting to the group worked
if (Module.START_OK != subgroup.startApp(new String[0]))
System.err.println("Cannot start child peergroup");
// We will spice things up to a more interesting level by sending unicast and multicast messages
// In order to be able to do that we will create to listeners that will listen for
// unicast and multicast advertisements respectively. All messages will be handled by Hello in the
// pipeMsgEvent method.
unicast_id = IDFactory.newPipeID(subgroup.getPeerGroupID(), unicast_name.getBytes());
multicast_id = IDFactory.newPipeID(subgroup.getPeerGroupID(), multicast_name.getBytes());
pipe_service = subgroup.getPipeService();
pipe_service.createInputPipe(get_advertisement(unicast_id, false), this);
pipe_service.createInputPipe(get_advertisement(multicast_id, true), this);
// In order to for other peers to find this one (and say hello) we will
// advertise a Hello Service.
discovery = subgroup.getDiscoveryService();
discovery.addDiscoveryListener(this);
ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement)
AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType());
mcadv.setName("STACK-OVERFLOW:HELLO");
mcadv.setDescription("Tutorial example to use JXTA module advertisement Framework");
ModuleClassID mcID = IDFactory.newModuleClassID();
mcadv.setModuleClassID(mcID);
// Let the group know of this service "module" / collection
discovery.publish(mcadv);
discovery.remotePublish(mcadv);
mdadv = (ModuleSpecAdvertisement)
AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType());
mdadv.setName("STACK-OVERFLOW:HELLO");
mdadv.setVersion("Version 1.0");
mdadv.setCreator("sun.com");
mdadv.setModuleSpecID(IDFactory.newModuleSpecID(mcID));
mdadv.setSpecURI("http://www.jxta.org/Ex1");
service_id = IDFactory.newPipeID(subgroup.getPeerGroupID(), service_name.getBytes());
PipeAdvertisement pipeadv = get_advertisement(service_id, false);
mdadv.setPipeAdvertisement(pipeadv);
// Let the group know of the service
discovery.publish(mdadv);
discovery.remotePublish(mdadv);
// Start listening for discovery events, received by the discoveryEvent method
pipe_service.createInputPipe(pipeadv, this);
}
private static PipeAdvertisement get_advertisement(PipeID id, boolean is_multicast) {
PipeAdvertisement adv = (PipeAdvertisement )AdvertisementFactory.
newAdvertisement(PipeAdvertisement.getAdvertisementType());
adv.setPipeID(id);
if (is_multicast)
adv.setType(PipeService.PropagateType);
else
adv.setType(PipeService.UnicastType);
adv.setName("This however");
adv.setDescription("does not really matter");
return adv;
}
#Override public void discoveryEvent(DiscoveryEvent event) {
// Found another peer! Let's say hello shall we!
// Reformatting to create a real peer id string
String found_peer_id = "urn:jxta:" + event.getSource().toString().substring(7);
send_to_peer("Hello", found_peer_id);
}
private void send_to_peer(String message, String found_peer_id) {
// This is where having the same ID is important or else we wont be
// able to open a pipe and send messages
PipeAdvertisement adv = get_advertisement(unicast_id, false);
// Send message to all peers in "ps", just one in our case
Set<PeerID> ps = new HashSet<PeerID>();
try {
ps.add((PeerID)IDFactory.fromURI(new URI(found_peer_id)));
}
catch (URISyntaxException e) {
// The JXTA peer ids need to be formatted as proper urns
e.printStackTrace();
}
// A pipe we can use to send messages with
OutputPipe sender = null;
try {
sender = pipe_service.createOutputPipe(adv, ps, 10000);
}
catch (IOException e) {
// Thrown if there was an error opening the connection, check firewall settings
e.printStackTrace();
}
Message msg = new Message();
MessageElement fromElem = null;
MessageElement msgElem = null;
try {
fromElem = new ByteArrayMessageElement("From", null, peer_id.toString().getBytes("ISO-8859-1"), null);
msgElem = new ByteArrayMessageElement("Msg", null, message.getBytes("ISO-8859-1"), null);
} catch (UnsupportedEncodingException e) {
// Yepp, you want to spell ISO-8859-1 correctly
e.printStackTrace();
}
msg.addMessageElement(fromElem);
msg.addMessageElement(msgElem);
try {
sender.send(msg);
} catch (IOException e) {
// Check, firewall, settings.
e.printStackTrace();
}
}
#Override public void pipeMsgEvent(PipeMsgEvent event) {
// Someone is sending us a message!
try {
Message msg = event.getMessage();
byte[] msgBytes = msg.getMessageElement("Msg").getBytes(true);
byte[] fromBytes = msg.getMessageElement("From").getBytes(true);
String from = new String(fromBytes);
String message = new String(msgBytes);
System.out.println(message + " says " + from);
}
catch (Exception e) {
// You will notice that JXTA is not very specific with exceptions...
e.printStackTrace();
}
}
/**
* We will not find anyone if we are not regularly looking
*/
private void fetch_advertisements() {
new Thread("fetch advertisements thread") {
public void run() {
while(true) {
discovery.getRemoteAdvertisements(null, DiscoveryService.ADV, "Name", "STACK-OVERFLOW:HELLO", 1, null);
try {
sleep(10000);
}
catch(InterruptedException e) {}
}
}
}.start();
}
}

Categories

Resources