Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Virgo » Weird ClassNotFoundException
Weird ClassNotFoundException [message #871448] Sun, 13 May 2012 16:08 Go to next message
Eduardo Frazão is currently offline Eduardo Frazão
Messages: 118
Registered: January 2012
Senior Member
Hi all.
Im working on a project that work with USB HID Devices.

I've found a Java library, that wraps some Native libs on Windows, Linux and MAC.
This library works fine. With a normal java flat class path I'vre wrote some code that runs ok.

After tests, I decide to work with OSGi on this project, So I wrap this Native library on a Bundle..

Here is the manifest:

Manifest-Version: 1.0
Bundle-Version: 1.0.0
Bundle-Name: Java JNI USB HID API
Bundle-ManifestVersion: 2
Bundle-Vendor: Wrapped by Autmix
Bundle-SymbolicName: br.com.autmix.javahidapi
Export-Package: com.codeminders.hidapi;version="1.0.0"
Bundle-NativeCode: libs/native/linux_x64/libhidapi.so;
 processor=x86_64;osname=Linux,
 libs/native/linux_x86/libhidapi.so;processor=x86;osname=Linux,
 libs/native/win_x86/libhidapi.dll;processor=x86;
 osname=WindowsXP;osname=WindowsVista;
 osname=Windows7;osname=WindowsServer2008


Again, the library os working fine. The native librarys is loading normally on Virgo Kernel 3.0.3. I can read and write data on the USB Device.

To do that I have a class that open a Thread, and this thread read values from device, and send it to listeners.
Is possible that any time, the USB Device goes away from the USB Bus, and the HID protocol sends a notification when it occours.

In this moment, I have a Class Not Found exception of a class that I've imported the package. Only in this moment. And I have not so mutch information on stack trace to debug:

This is the Class:

package br.com.autmix.bridgeusb;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.codeminders.hidapi.HIDDevice;
import com.codeminders.hidapi.HIDDeviceInfo;

import br.com.autmix.bridgeusb.AutmixHidManager.ChangeEventType;
import br.com.autmix.bridgeusb.AutmixHidManager.DeviceListChangeEvent;
import br.com.autmix.comunicador.api.Bridge;
import br.com.autmix.comunicador.api.BridgeBusType;
import br.com.autmix.comunicador.api.DeviceChangeEventType;

public class BridgeUSB extends Bridge {

	private HIDDevice device;
	
	private Integer productId;
	private Integer vendorId;
	
	private boolean threadLoopControll = false;
	
	// Cache de buffers
	private Map<Integer, int[]> bufferCache = new HashMap<Integer, int[]>();
	
	private AutmixHidManager.DeviceListChangeListener localAnonymousHidListener;
	
	public BridgeUSB(Integer vendorId, Integer productId) throws IOException {
		super();
		this.productId = productId;
		this.vendorId = vendorId;
		
		AutmixHidManager.getInstance();
		device = AutmixHidManager.openById(vendorId, productId, null);
		if(device == null) {
			AutmixHidManager.getInstance().release();
			throw new IOException(String.format("Impossivel abrir dispositivo {VendorID: %d, ProductID: %d}", vendorId, productId));
		}
		device.enableBlocking();
		startListen();
		openUSBDaemon();
	}
	
	/**
	 * Se registra como ouvinte no Manager HID, para receber eventos sobre a bridge controlada por esta instancia.
	 */
	private void startListen() {
		AutmixHidManager.getInstance().addListener(localAnonymousHidListener = new AutmixHidManager.DeviceListChangeListener() {
			@Override
			public void deviceListChanged(DeviceListChangeEvent event) {
				if((event.getDeviceInfo().getProduct_id() == productId && event.getDeviceInfo().getVendor_id() == vendorId)) {
					if(event.getEnventType() == ChangeEventType.DEVICE_REMOVED) {
						threadLoopControll = false;
						try {
							device.close();
						} catch (Exception e) {
							e.printStackTrace();
						}
						device = null;
						Logger.getLogger(BridgeUSB.class.getName())
							.log(Level.INFO, String.format("BridgeUSB associada [p_id: %d / v_id: %d] foi removida do barramento.", productId, vendorId));
						notifyListeners(DeviceChangeEventType.DEVICE_REMOVED, BridgeUSB.this);
					}
					else if(event.getEnventType() == ChangeEventType.DEVICE_ADDED) {
						Logger.getLogger(BridgeUSB.class.getName())
							.log(Level.INFO, String.format("BridgeUSB associada [p_id: %d / v_id: %d] foi reconectada ao barramento.", productId, vendorId));
						try {
							HIDDeviceInfo deviceInfo = event.getDeviceInfo();
							device = deviceInfo.open();
							device.enableBlocking();
							openUSBDaemon();
							notifyListeners(DeviceChangeEventType.DEVICE_ADDED, BridgeUSB.this);
						} catch (Exception e) {
							Logger.getLogger(BridgeUSB.class.getName()).log(Level.SEVERE, "Impossivel abrir comunicacao com dispositivo apos reconexao.");
						}
					}
				}
			}
		});
	}
	
	@Override
	public BridgeBusType getBusType() {
		return BridgeBusType.USB;
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void requestRefresh() {
		// TODO Verificar como funcionara este recurso na bridgeUSB
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public Map<Integer, Integer> getValue(Integer index, Integer... posicoes) {
		synchronized (bufferCache) {
			if(bufferCache.get(index) != null) {
				HashMap<Integer, Integer> mapa = new HashMap<Integer, Integer>();
				
				for(Integer posicao : posicoes) {
					mapa.put(posicao, bufferCache.get(index)[posicao]);
				}
				
				return mapa;
				
			}
			return null;
		}
	}

	@Override
	/**
	 * {@inheritDoc}
	 */
	public void setValue(Integer index, Map<Integer, Integer> posicoesValores) throws IOException {
		synchronized (bufferCache) {
			if(device == null) {
				throw new IOException("O dispositivo USB ainda nao esta pronto.");
			}
			
			byte[] buffer  = new byte[64];
			
			buffer[0] = (byte) (int) index;
			
			Iterator<Integer> iter = posicoesValores.keySet().iterator();
			
			while(iter.hasNext()) {
				int posicao = iter.next();
				if(posicao == 0) {
					throw new IllegalArgumentException("Nao e permitido associar valores a posicao [0], pois ela define o tipo do buffer");
				}
				int valor = posicoesValores.get(posicao);
				buffer[posicao] = (byte) valor;
			}
			
			device.writeTimeout(buffer, 5000);
		}
	}
	
	@Override
	/**
	 * {@inheritDoc}
	 */
	public synchronized void release() {
		threadLoopControll = false;
		removeAllListeners();
		try {
			if(device != null) {
				try {
					device.disableBlocking();
				}
				finally {
					device.close();
					AutmixHidManager.getInstance().removeListener(localAnonymousHidListener);
					AutmixHidManager.releaseInstance();
				}
			}
		} catch (Exception e) {
			Logger.getLogger(BridgeUSB.class.getName()).log(Level.SEVERE, "Erro ao tentar liberar recursos da bridge.", e);
		}
	}
	
	/**
	 * Recebe um buffer vindo do dispositivo USB, e notifica os interessados sobre valores alterados.
	 * @param index Indice de leitura do buffer. Determina a classe de dispositivos
	 * @param buffer Buffer com valores de leitura
	 */
	private void bufferReceived(Integer index, byte[] buffer) {
		Map<Integer, Integer> mapa  = new HashMap<Integer, Integer>();
		if(bufferCache.get(index) != null) {
			int[] cacheBuffer = bufferCache.get(index);
			for(int i = 1; i < buffer.length; i++) {
				int valorCache = (int) cacheBuffer[i];
				int valor = (int) buffer[i];
				if(valor<0) {valor+=256;}
				if( valor != valorCache ) {
					mapa.put(i, valor);
				}
				// Atualizando buffer
				cacheBuffer[i] = buffer[i];
			}
		}
		else {
			int[] newBuffer = new int[64];
			for(int i = 1; i<buffer.length; i++) {
				int valor = (int) buffer[i];
				if(valor<0) {
					valor += 256;
				}
				mapa.put(i, valor);
				// Atualizando buffer
				newBuffer[i] = (int) buffer[i];
			}
			bufferCache.put(index, newBuffer);
		}
		if(!mapa.isEmpty()) {
			notifyValueChangeListeners(index, mapa);
		}
	}
	
	/**
	 * Abre a thread de leitura do dispositivo.<br />
	 * O Controle da thread e extremamente simples.<br />
	 * Note que a leitura do dispotivio realiza lock na thread.<br />
	 * E necessario fechar o dispositivo, e entao anular o controle da thread para encerra-la
	 */
	private void openUSBDaemon() {
		threadLoopControll = true;
		Thread readThread = new Thread(new Runnable() {
			@Override
			public void run() {
				while(threadLoopControll) {
					if(device != null) {
						try {
							byte[] buffer = new byte[64];
							device.readTimeout(buffer, 5000);
							if(!Arrays.equals(buffer, new byte[64])) {
								synchronized (bufferCache) {
									bufferReceived((int) buffer[0], buffer);
								}
							}
						} catch (Exception e) {
							Logger.getLogger(BridgeUSB.class.getName()).log(Level.SEVERE, "Erro ao ler dados do dispositivo.", e);
							try {
								Thread.sleep(1000L);
							} catch (InterruptedException e1) {
								e1.printStackTrace();
							}
						}
					}
				}
				Logger.getLogger(BridgeUSB.class.getName()).log(Level.INFO, "Encerrando thread de leitura de dispositivo.");
			}
		});
		readThread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
		Logger.getLogger(BridgeUSB.class.getName()).log(Level.INFO, "Startando thread de leitura de dispositivo.");
		readThread.start();
	}

}


And this is the error:

[2012-05-13 16:39:54.322] ERROR Thread-32                    System.err                                                        Exception in thread "Thread-32" java.lang.NoClassDefFoundError: com/codeminders/hidapi/HIDDeviceInfo 
[2012-05-13 16:39:54.322] ERROR Thread-32                    System.err                                                        Caused by: java.lang.ClassNotFoundException: com.codeminders.hidapi.HIDDeviceInfo 
[2012-05-13 16:39:54.323] ERROR Thread-32                    System.err                                                         at java.net.URLClassLoader$1.run(URLClassLoader.java:202) 
[2012-05-13 16:39:54.323] ERROR Thread-32                    System.err                                                         at java.security.AccessController.doPrivileged(Native Method) 
[2012-05-13 16:39:54.323] ERROR Thread-32                    System.err                                                         at java.net.URLClassLoader.findClass(URLClassLoader.java:190) 
[2012-05-13 16:39:54.323] ERROR Thread-32                    System.err                                                         at java.lang.ClassLoader.loadClass(ClassLoader.java:306) 
[2012-05-13 16:39:54.323] ERROR Thread-32                    System.err                                                         at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) 
[2012-05-13 16:39:54.323] ERROR Thread-32                    System.err                                                         at java.lang.ClassLoader.loadClass(ClassLoader.java:247) 


How can I debug that: It is the Full stack trace.

Thanks all!
Re: Weird ClassNotFoundException [message #871455 is a reply to message #871448] Sun, 13 May 2012 16:38 Go to previous messageGo to next message
Eduardo Frazão is currently offline Eduardo Frazão
Messages: 118
Registered: January 2012
Senior Member
A new information.

I added the classes of this library in my own bundle.

When I remove the USB Device, I got the same error.

Class not found exception of: com.codeminders.hidapi.HIDDeviceInfo

Detail: If I not remove the USB Device, I can load this class normally. This problem only occours when I remove the usb device, and put it again.

How can this happen?

Maybe it is because it is a native library? Things that occour inside this class is outside the scope of the equinox?
Re: Weird ClassNotFoundException [message #871683 is a reply to message #871448] Mon, 14 May 2012 13:15 Go to previous message
Eduardo Frazão is currently offline Eduardo Frazão
Messages: 118
Registered: January 2012
Senior Member
Problem solved.

Unfortunatelly, I have to add this bundle on the System Packages.

A native code was trying to create instances of the com.codeminders.hidapi.HIDDeviceInfo, and this class was not on the System ClassLoader.

Now, everything is work, but I need to put my bundle on the System ClassPath. Sad. Not as mudular as I want, but, for now, its working. I found an opened bug on the library. I will comment on!

Thanks!
Previous Topic:Greenpages 2.5.0.RELEASE
Next Topic:Greenpages 2.4 not working
Goto Forum:
  


Current Time: Tue Jul 29 04:49:39 EDT 2014

Powered by FUDForum. Page generated in 0.02295 seconds