Hey I am trying to use Google Cloud Speech API into Android but I am getting this error and am unable to get around it.
java.lang.VerifyError: Verifier rejected class com.google.cloud.speech.v1
.StreamingRecognizeResponse due to bad method java.lang.Object com.google
.cloud.speech.v1.StreamingRecognizeResponse.dynamicMethod(com.google.protobuf
.GeneratedMessageLite$MethodToInvoke, java.lang.Object, java.lang.Object)
(declaration of 'com.google.cloud.speech.v1.StreamingRecognizeResponse'
appears in /data/app/com.curieo.podcast-1/base.apk:classes65.dex)
at com.google.cloud.speech.v1.StreamingRecognizeResponse.getDefaultInstance(StreamingRecognizeResponse.java:1095)
at com.google.cloud.speech.v1.SpeechGrpc.<clinit>(SpeechGrpc.java:67)
at com.curieo.podcast.ui.fragment.dates.googlecloud.StreamingRecognizeClient.<init>(StreamingRecognizeClient.java:57)
at com.curieo.podcast.ui.fragment.dates.googlecloud.MicrophoneStreamRecognizeClient.<init>(MicrophoneStreamRecognizeClient.java:54)
at com.curieo.podcast.ui.fragment.dates.RecordFragment$1.run(RecordFragment.java:112)
I searched for this but couldn't find a solution. here is the code where error occurs
private Thread runner = new Thread() {
public void run() {
try {
MicrophoneStreamRecognizeClient client;
synchronized (this) {
try {
client = new MicrophoneStreamRecognizeClient(getResources().openRawResource(R.raw.credential), Self); //crashes here
client.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
Here is the code snippet of MicrophoneStreamRecognizeClient class:
public class MicrophoneStreamRecognizeClient {
private String host = "speech.googleapis.com";
private Integer port = 443;
private ManagedChannel channel;
private StreamingRecognizeClient client;
private final List<String> OAUTH2_SCOPES = Arrays.asList("https://www.googleapis.com/auth/cloud-platform");
/**
*
* #param authorizationFile
* #param host
* #param port
* #return
* #throws IOException
*/
private ManagedChannel createChannel(InputStream authorizationFile, String host, int port) throws IOException {
GoogleCredentials creds = GoogleCredentials.fromStream(authorizationFile);
creds = creds.createScoped(OAUTH2_SCOPES);
return ManagedChannelBuilder.forAddress(host, port)
.intercept(new ClientAuthInterceptor(creds, Executors.newSingleThreadExecutor()))
.build();
}
/**
*
* #param autorizationFile
* #throws IOException
*/
public MicrophoneStreamRecognizeClient(InputStream autorizationFile, IResults screen) throws IOException {
channel = createChannel(autorizationFile, host, port);
client = new StreamingRecognizeClient(channel, screen);
}
/**
*
* #throws IOException
* #throws InterruptedException
*/
public void start() throws IOException, InterruptedException {
client.recognize();
}
/**
*
* #throws InterruptedException
*/
public void stop() throws InterruptedException {
client.shutdown();
}
}
Cleaning out the build folder resolved the problem. Not sure why ART had an issue but Dalvik did not.
Running a gradle clean task was not clearing out my build folder all the way. I had to do it manually, but clean may work for some people.
Reference
java.lang.VerifyError can happen for some reason:
A class tries to extend a class declared as final
A method tries to override a super method that is declared as final
A wrong argument is passed to a method
clint = new MicrophoneStreamRecognizeClient(getResources()
.openRawResource(R.raw.credential), Self); //crashes here
I don't know what is Self. Is that ok?
Try this.
synchronized (this) {
MicrophoneStreamRecognizeClient client;
try {
client = new MicrophoneStreamRecognizeClient(getResources().openRawResource(R.raw.credential), Self); //crashes here
client.start();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Because another issue can be !! Synchronized block inside try / catch block !! cause of java.lang.VerifyError reference
If the java.lang.VerifyError is triggered because library differences between runtime and compiling, as #Enamul also suggested, then you might wanna check differences between com.google.cloud.speech.v1.StreamingRecognizeResponse and com.google.cloud.speech.v1beta1.StreamingRecognizeResponse.
Even so, try with the beta, newer, version of the library. The example that inspired you uses the beta version.
Related
I have a main thread server which basically listen to whoever want to connect to the port
/**
* The main server thread receives request from and sends
* response to clients.
*/
public class Server {
/*
Port number for the client connection
*/
private static final int PORT = 3000;
/*
The number of client can be connected
*/
private static final int SIZE = 10;
/*
The executor
*/
private static ExecutorService executorService = Executors.newFixedThreadPool(SIZE);
/**
* Starts the main server.
*/
public static void main(String[] args) {
/*
All the information are stored into the queue
*/
BlockingQueue<Message> messageQueue = new LinkedBlockingQueue<>();
/*
All the clients are stored into the map
*/
ConcurrentMap<byte[], Boolean> clientManagement = new ConcurrentHashMap<>();
runMainServer(messageQueue, clientManagement);
}
private static void runMainServer(BlockingQueue<Message> messageQueue, ConcurrentMap<byte[], Boolean> clientManagement) {
try (
ServerSocket serverSocket = new ServerSocket(PORT);
) {
System.out.println("Starting server");
while (true) {
System.out.println("Waiting for request");
Socket socket = serverSocket.accept();
System.out.println("Processing request");
ClientThread newClient = new ClientThread(socket, messageQueue, clientManagement);
executorService.submit(newClient);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
And I have many multi-threading sub-server to handle each identical client. The client is first going to be accepted by the server, and checked if first message that the server received is a connect_message. If it is, then they are officially connected. There are many more message other than connect_message. But I am just not going to be too specific on them.
/**
* The client thread.
*/
public class ClientThread implements Runnable {
private Socket socket;
private BlockingQueue<Message> messageQueue;
private ConcurrentMap<byte[], Boolean> clientManagement;
private byte[] username;
/**
*
*
* #param socket
* #param messageQueue
* #param clientManagement
*/
public ClientThread(Socket socket, BlockingQueue<Message> messageQueue, ConcurrentMap<byte[], Boolean> clientManagement) {
this.socket = socket;
this.messageQueue = messageQueue;
this.clientManagement = clientManagement;
this.username = new byte[1];
}
/**
*
*/
#Override
public void run() {
try (
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
) {
Message m = (Message) in.readObject();
if (m.getIdentifier() == MessageIdentifier.CONNECT_MESSAGE) {
ConnectMessage cm = (ConnectMessage) m;
this.username = cm.getUsername();
clientManagement.put(cm.getUsername(), true);
byte[] cntMsg = "Successfully Connected!".getBytes();
ConnectResponse cr = new ConnectResponse(true, cntMsg.length, cntMsg);
out.writeObject(cr);
} else {
// Handle failing request
handleFailedMsg(out, "Client should connect first");
socket.close();
throw new IllegalArgumentException("Connect unsuccessfully");
}
handleClient(in, out);
socket.close();
} catch (IOException | ClassNotFoundException | InterruptedException e) {
e.printStackTrace();
}
}
/**
*
* #param in
* #param out
* #throws InterruptedException
* #throws IOException
* #throws ClassNotFoundException
*/
private void handleClient(ObjectInputStream in, ObjectOutputStream out)
throws InterruptedException, IOException, ClassNotFoundException {
while (true) {
// Handle message taken from the queue
Message msgFromQueue = messageQueue.take();
handleQueueRequest(msgFromQueue, out);
// Handle request obtained by user
Message request = (Message) in.readObject();
// Handle disconnect
if (request.getIdentifier() == MessageIdentifier.DISCONNECT_MESSAGE) {
DisconnectMessage dm = (DisconnectMessage) request;
// If the message is not for this thread, then put it back and ignore it.
if (!Arrays.equals(username, dm.getUsername())) {
messageQueue.add(request);
continue;
}
// Check if the username is inside the client map
if (!clientManagement.containsKey(dm.getUsername())) {
handleFailedMsg(out, "The client doesn't exist");
}
// Disconnect
clientManagement.remove(dm.getUsername());
// Create disconnect response
byte[] message = "See you again".getBytes();
DisconnectResponse dr = new DisconnectResponse(true, message.length, message);
// Write to the client
out.writeObject(dr);
break;
}
// Handle other
if (!handleRequest(request, out)) {
handleFailedMsg(out, "The request failed due to incorrect username.");
}
}
}
/**
*
* #param request
* #param out
* #return
* #throws IOException
*/
private boolean handleRequest(Message request, ObjectOutputStream out) throws IOException {
switch (request.getIdentifier()) {
// If broadcast, then every one should know
case BROADCAST_MESSAGE:
BroadcastMessage bm = (BroadcastMessage) request;
if (!Arrays.equals(username, bm.getUsername())) {
return false;
}
messageQueue.add(request);
break;
// If user want the list of connected users
case QUERY_CONNECTED_USERS:
QueryUsersMessage qu = (QueryUsersMessage) request;
if (!Arrays.equals(username, qu.getUsername())) {
return false;
}
List<Pair<Integer, byte[]>> userList = new ArrayList<>();
for (byte[] username : clientManagement.keySet()) {
Pair<Integer, byte[]> user = new Pair<>(username.length, username);
userList.add(user);
}
// Create a new query response containing all the users
QueryResponse qr = new QueryResponse(clientManagement.keySet().size(), userList);
out.writeObject(qr);
break;
// If user wants to send a direct message to the other user
case DIRECT_MESSAGE:
DirectMessage dm = (DirectMessage) request;
if (!Arrays.equals(username, dm.getUsername())) {
return false;
}
messageQueue.add(request);
break;
// If user wants to send an insult to the other user and broadcast to the chat room
case SEND_INSULT:
SendInsultMessage si = (SendInsultMessage) request;
if (!Arrays.equals(username, si.getUsername())) {
return false;
}
messageQueue.add(request);
break;
}
return true;
}
/**
*
* #param out
* #param description
* #throws IOException
*/
public void handleFailedMsg(ObjectOutputStream out, String description) throws IOException {
byte[] failedMsg = description.getBytes();
FailedMessage fm = new FailedMessage(failedMsg.length, failedMsg);
out.writeObject(fm);
}
/**
*
* #param request
* #param out
* #throws IOException
*/
public void handleQueueRequest(Message request, ObjectOutputStream out) throws IOException {
switch (request.getIdentifier()) {
case SEND_INSULT:
// Gets the message from queue
SendInsultMessage si = (SendInsultMessage) request;
// Check if the user already gotten the message
if (!si.getOtherUsers().contains(username)) {
out.writeObject(si);
si.addUsers(username);
}
// Check if all the users already gotten the message
if (si.getOtherUsers().size() < clientManagement.keySet().size()) {
messageQueue.add(si);
}
break;
case DIRECT_MESSAGE:
DirectMessage dm = (DirectMessage) request;
// Check if the message is for this user
if (Arrays.equals(username, dm.getRecipientUsername())) {
out.writeObject(dm);
} else { // If not for this user then put it back
messageQueue.add(dm);
}
break;
case BROADCAST_MESSAGE:
// Gets the message from queue
BroadcastMessage bm = (BroadcastMessage) request;
// Check if the user already gotten the message
if (!bm.getOtherUsers().contains(username)) {
out.writeObject(bm);
bm.addUsers(username);
}
// Check if all the users already gotten the message
if (bm.getOtherUsers().size() < clientManagement.keySet().size()) {
messageQueue.add(bm);
}
break;
}
}
I want to do JUnit test for my server. What is the best way to test a multi-threading server like this?
Here are the JUnit test code that I am trying. I first start a thread which is accepted by the server. Then I am going to start a client and pretend that the client is sending something to the server. I first want to try a connect_message to see how connection work. But so far, the test doesn't seem to responding on JUnit test. It just keeps running, nothing happen
public class ClientThreadTest {
private Thread foo;
private List<ClientThread> clientList;
private BlockingQueue<Message> messageQueue;
private ConcurrentMap<byte[], Boolean> clientManagement;
private static final int PORT = 3000;
#Before
public void setUp() throws Exception {
messageQueue = new LinkedBlockingQueue<>();
clientManagement = new ConcurrentHashMap<>();
}
#Test
public void run() throws IOException, ClassNotFoundException {
ServerSocket socket = new ServerSocket(PORT);
foo = new Thread(new ClientThread(socket.accept(), messageQueue, clientManagement));
foo.start();
Socket fooClient = new Socket("localhost", PORT);
ObjectOutputStream out = new ObjectOutputStream(fooClient.getOutputStream());
ObjectInputStream in = new ObjectInputStream(fooClient.getInputStream());
// First test Connection message
byte[] username = "foo".getBytes();
ConnectMessage cm = new ConnectMessage(username.length, username);
// The message need to get
byte[] cntMsg = "Successfully Connected!".getBytes();
ConnectResponse cr = new ConnectResponse(true, cntMsg.length, cntMsg);
out.writeObject(cm);
ConnectResponse m = (ConnectResponse) in.readObject();
System.out.println(Arrays.toString(m.getMessage()));
}
I have solved my own problem!
For anyone who is doing JUnit testing on a multi-threading server. Here is my suggestion:
You have to start you main server at the beginning, before anything else. Keep you main server listening to some port that you give it.
Then you have to start your client and you have to give it the same port number which you gave to the main server
Last but not least, you can start your thread to deal with a specific client. Somehow if I instantiated my thread as ClientThread foo, and I called foo.run(), it won't work. I have to instantiate Thread foo, and make my ClientThread() as an input to Thread(), and call foo.start() instead!
Now it is working!
I am trying to declare one global variable in a class, whenever I create simple variables like int i; , they are created easily, but when I try to create an object like Socket socket = new Socket("192.168.1.3",4917); it gives the error that I have mentioned. I know that its wants me to handle exception, but no syntex is working at this part of the program, try and catch says illegal type of start.
This might get solved by correct syntex required to be applied. Please help. Thanks.
Here is my code..
public class NumberAdditionUI extends javax.swing.JFrame {
Socket socket = new Socket("192.168.1.3",4917);
public static void main(String args[]) {
/* Set the Nimbus look and feel */
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NumberAdditionUI().setVisible(true);
}
});
}
The problem you are having is that the constructor of Socket can throw an exception, and you need to handle it somehow.
There are a couple easy ways to do this.
One is by creating a no-arg constructor, and initializing socket there. You can then either handle the exceptions there, or declare that you throw them and let the instantiating code deal with it:
Socket socket;
public NumberAdditionUI() {
try {
socket = new Socket("192.168.1.3", 4917);
} catch (UnknownHostException e) {
// ...
} catch (IOException e) {
// ...
}
}
// OR
public NumberAdditionUI() throws UnknownHostException, IOException {
socket = new Socket("192.168.1.3", 4917);
}
Another way to do this is to use an initialization block:
Socket socket;
{
try {
socket = new Socket("192.168.1.3", 4917);
} catch (UnknownHostException e) {
// ...
} catch (IOException e) {
// ...
}
}
The constructor for creating the Socket you are using throws exceptions
UnknownHostException and 'IOException'. These must always be inside a try catch or must be catched atleast some where in the flow of control.
But in your case you are declaring it in global context and you cannot handle this exceptions like this case.
the constructor looks like this
public Socket(String host,
int port)
throws UnknownHostException,
IOException
See the official docs
I Created a class JavaRunner that dynamically creates a file from string, compiles it in memory and runs it's main method (I also created a method that writes the file and compiles it on disk with similar results).
I created 2 other classes that call the runner.
The first is TerminalRunner which takes the class name and source as arguments and calls JavaRunner.compile, this works fine because it only runs once every time I call it.
The second class is RunnerServlet which starts a small java server that receives a post request compiles using JavaRunner and runs the code and returning a JSON object with the sys.out and sys.err streams.
if I post {name:"Main", code:"[Some Java code]"} I get the correct response; however if I call the same class Main with different source code I get the first result.
I traced the code and the source String is delivered correctly to the JavaCompiler.
The problem has to do with the compiled class, my guess it is somehow cached by the JVM.
This is The compile method in JavaRunner.java
public static void compile(String name, String code, int timeLimit){
/*Creating dynamic java source code file object*/
SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject (name, code) ;
JavaFileObject javaFileObjects[] = new JavaFileObject[]{fileObject} ;
/*Instantiating the java compiler*/
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
/**
* Retrieving the standard file manager from compiler object, which is used to provide
* basic building block for customizing how a compiler reads and writes to files.
*
* The same file manager can be reopened for another compiler task.
* Thus we reduce the overhead of scanning through file system and jar files each time
*/
StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null);
try {
stdFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File("./temp")));
} catch (IOException e) {
e.printStackTrace();
}
/* Prepare a list of compilation units (java source code file objects) to input to compilation task*/
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects);
/*Prepare any compilation options to be used during compilation*/
//In this example, we are asking the compiler to place the output files under bin folder.
List<String> compileOptions = new ArrayList<String>();
// compileOptions.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path")));
// Iterable<String> compilationOptionss = Arrays.asList(compileOptions);
/*Create a diagnostic controller, which holds the compilation problems*/
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
/*Create a compilation task from compiler by passing in the required input objects prepared above*/
CompilationTask compilerTask = compiler.getTask(null, stdFileManager, diagnostics, compileOptions, null, compilationUnits) ;
//Perform the compilation by calling the call method on compilerTask object.
boolean status = compilerTask.call();
if (!status){//If compilation error occurs
/*Iterate through each compilation problem and print it*/
for (Diagnostic diagnostic : diagnostics.getDiagnostics()){
System.err.format("Error on line %d in %s", diagnostic.getLineNumber(), diagnostic);
}
} else {
// ExecutorService service = Executors.newSingleThreadExecutor();
// try {
// Runnable r = new Runnable() {
// #Override
// public void run() {
try {
Class.forName(name).getDeclaredMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { null });
} catch (ClassNotFoundException e) {
System.err.println("Class not found: " + e);
} catch (NoSuchMethodException e) {
System.err.println("No such method: " + e);
} catch (IllegalAccessException e) {
System.err.println("Illegal access: " + e);
} catch (InvocationTargetException e) {
System.err.println("RuntimeError: "+e.getTargetException());
}
// }
// };
// Future<?> f = service.submit(r);
// f.get(timeLimit, TimeUnit.MILLISECONDS); // attempt the task for timelimit default 5 seconds
// }
// catch (final InterruptedException e) {
// System.err.println("Thread Interrupted: " + e);
// }
// catch (final TimeoutException e) {
// System.err.println("TimeoutException: Your program ran for more than "+timeLimit);
// }
// catch (final ExecutionException e) {
// e.printStackTrace();
// }
// finally {
// service.shutdown();
// }
}
try {
(new File("./temp/"+name+".class")).delete();
stdFileManager.close() ;//Close the file manager
} catch (IOException e) {
e.printStackTrace();
}
}
This is the DynaDynamicJavaSourceCodeObject
class DynamicJavaSourceCodeObject extends SimpleJavaFileObject{
private String sourceCode ;
/**
* Converts the name to an URI, as that is the format expected by JavaFileObject
*
*
* #param String name given to the class file
* #param String source the source code string
*/
protected DynamicJavaSourceCodeObject(String name, String source) {
super(URI.create("string:///" +name.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);
this.sourceCode = source ;
}
#Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException {
return sourceCode ;
}
public String getSourceCode() {
return sourceCode;
}
}
Any advice?
so far I set the CLASS_OUPUT to a /temp directory where I delete them
however once a class is defined even after I delete it it remains in memory somewhere
Is there a way to clear classes from java's memory?
I created a repo with my current progress here
My workaround, if all else fails,is to generate random file names then every 10000 compilation I would restart the server or something (but it's messy)
So thanks to the suggestions by #pm-77-1 and hot-licks in the comments
I used theSecureClassLoader class and made it so that the compiled bytecode is loaded there
here's the full class
public class JavaRunner {
public static void compile(String name, String code){
compile(name,code,5000);
}
/**
* compiles and runs main method from code
* #param name Class Name
* #param code String to compile
* #param timeLimit (otional) limit for code to run, default to 5 seconds
*/
public static void compile(String name, String code, int timeLimit){
/*Creating dynamic java source code file object*/
SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject (name, code) ;
JavaFileObject javaFileObjects[] = new JavaFileObject[]{fileObject} ;
/*Instantiating the java compiler*/
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
/**
* Retrieving the standard file manager from compiler object, which is used to provide
* basic building block for customizing how a compiler reads and writes to files.
*
* The same file manager can be reopened for another compiler task.
* Thus we reduce the overhead of scanning through file system and jar files each time
*/
StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, null, null);
//uses custom file manager with defined class loader inorder to unload the compiled class when this is done
ClassFileManager fileManager = new ClassFileManager(stdFileManager);
/* Prepare a list of compilation units (java source code file objects) to input to compilation task*/
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects);
/*Prepare any compilation options to be used during compilation*/
//In this example, we are asking the compiler to place the output files under bin folder.
List<String> compileOptions = new ArrayList<String>();
// compileOptions.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path")));
// Iterable<String> compilationOptionss = Arrays.asList(compileOptions);
/*Create a diagnostic controller, which holds the compilation problems*/
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
/*Create a compilation task from compiler by passing in the required input objects prepared above*/
CompilationTask compilerTask = compiler.getTask(null, fileManager, diagnostics, compileOptions, null, compilationUnits) ;
//Perform the compilation by calling the call method on compilerTask object.
boolean status = compilerTask.call();
if (!status){//If compilation error occurs
/*Iterate through each compilation problem and print it*/
for (Diagnostic diagnostic : diagnostics.getDiagnostics()){
System.err.format("Error on line %d in %s", diagnostic.getLineNumber(), diagnostic);
}
} else {
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Runnable r = new Runnable() {
#Override
public void run() {
try {
fileManager.getClassLoader(null).loadClass(name).getDeclaredMethod("main", new Class[] { String[].class }).invoke(null, new Object[] { null });
} catch (ClassNotFoundException e) {
System.err.println("Class not found: " + e);
} catch (NoSuchMethodException e) {
System.err.println("No such method: " + e);
} catch (IllegalAccessException e) {
System.err.println("Illegal access: " + e);
} catch (InvocationTargetException e) {
System.err.println("RuntimeError: "+e.getTargetException());
}
try {
fileObject.delete();
fileManager.close();
ResourceBundle.clearCache(ClassLoader.getSystemClassLoader()); // <--useless
} catch (IOException e) {
e.printStackTrace();
}
}
};
Future<?> f = service.submit(r);
f.get(timeLimit, TimeUnit.MILLISECONDS);
}
catch (final InterruptedException e) {
System.err.println("Thread Interrupted: " + e);
}
catch (final TimeoutException e) {
System.err.println("TimeoutException: Your program ran for more than "+timeLimit);
}
catch (final ExecutionException e) {
e.printStackTrace();
}
finally {
service.shutdown();
}
}
}
}
This prepares a dynamic java source code for compilation.
class DynamicJavaSourceCodeObject extends SimpleJavaFileObject{
private String sourceCode ;
/**
* Converts the name to an URI, as that is the format expected by JavaFileObject
*
*
* #param String name given to the class file
* #param String source the source code string
*/
protected DynamicJavaSourceCodeObject(String name, String source) {
super(URI.create("string:///" +name.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);
this.sourceCode = source ;
}
#Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException {
return sourceCode ;
}
public String getSourceCode() {
return sourceCode;
}
}
the idea is to create a Dynamic class instead of writing to file
class JavaClassObject extends SimpleJavaFileObject {
/**
* Byte code created by the compiler will be stored in this
* ByteArrayOutputStream so that we can later get the
* byte array out of it
* and put it in the memory as an instance of our class.
*/
protected ByteArrayOutputStream bos =
new ByteArrayOutputStream();
/**
* Registers the compiled class object under URI
* containing the class full name
*
* #param name
* Full name of the compiled class
* #param kind
* Kind of the data. It will be CLASS in our case
*/
public JavaClassObject(String name, Kind kind) {
super(URI.create("string:///" + name.replace('.', '/')
+ kind.extension), kind);
}
/**
* Will be used by our file manager to get the byte code that
* can be put into memory to instantiate our class
*
* #return compiled byte code
*/
public byte[] getBytes() {
return bos.toByteArray();
}
/**
* Will provide the compiler with an output stream that leads
* to our byte array. This way the compiler will write everything
* into the byte array that we will instantiate later
*/
#Override
public OutputStream openOutputStream() throws IOException {
return bos;
}
}
We use this file manager so that the compiled class from source can be unloaded also not having to write to file System
class ClassFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
/**
* Instance of JavaClassObject that will store the
* compiled bytecode of our class
*/
private JavaClassObject jclassObject;
/**
* Instance of ClassLoader
*/
private SecureClassLoader classLoader;
/**
* Will initialize the manager with the specified
* standard java file manager
*
* #param standardManger
*/
public ClassFileManager(StandardJavaFileManager standardManager) {
super(standardManager);
this.classLoader = new SecureClassLoader() {
#Override
protected Class<?> findClass(String name)
throws ClassNotFoundException {
byte[] b = jclassObject.getBytes();
return super.defineClass(name, jclassObject
.getBytes(), 0, b.length);
}
};
}
/**
* Will be used by us to get the class loader for our
* compiled class. It creates an anonymous class
* extending the SecureClassLoader which uses the
* byte code created by the compiler and stored in
* the JavaClassObject, and returns the Class for it
*/
#Override
public ClassLoader getClassLoader(Location location) {
return this.classLoader;
}
public void unloadClass(Location location) {
this.classLoader = null;
this.jclassObject = null;
System.gc();
}
/**
* Gives the compiler an instance of the JavaClassObject
* so that the compiler can write the byte code into it.
*/
#Override
public JavaFileObject getJavaFileForOutput(Location location,
String className, Kind kind, FileObject sibling)
throws IOException {
jclassObject = new JavaClassObject(className, kind);
return jclassObject;
}
}
I think the only way for a Class<?> object to be garbage collected, is for the associated ClassLoader to be garbage collected, and this only becomes eligible for collection if there are no more references to the ClassLoader and any of the classes loaded through this ClassLoader. Have a look at this question for more information.
I have implemented a Steaming API for twitter. I get the streams perfectly. However, My program never ends. I have tried many combinations but can't figure out why. I am suing Apache AsyncHttpClient in java. My goal is to start the stream for example for 10 seconds, get the streams, and gracefully close the stream and exit the application (I am expecting this to happen when my Main method ends naturally). This is the code below:
public static void main(String[] args) throws Exception
{
TwitterStreamingHttpClient client = new TwitterStreamingHttpClient();
Executor ex = Executors.newSingleThreadExecutor();
ex.execute(client);
Thread.sleep(5000);
client.ceaseStream();
LOG.debug("Keeps running");
}
and this:
public class TwitterStreamingHttpClient extends DefaultHttpAsyncClient implements Runnable
{
private final static Logger LOG = LoggerFactory.getLogger(TwitterStreamingHttpClient.class);
/**
* #throws IOReactorException
*/
public TwitterStreamingHttpClient() throws IOReactorException
{
super();
// TODO: parametrize it, load from config file, spring config file?
this.getCredentialsProvider().setCredentials(new AuthScope("stream.twitter.com", 80),
new UsernamePasswordCredentials("username", "password"));
this.start();
}
public void initiateStream() throws UnsupportedEncodingException, InterruptedException, ExecutionException
{
String requestContent = new String();
requestContent = "track=NothingFeelsBetterThan";
Future future = this.execute(HttpAsyncMethods.createPost(
"https://stream.twitter.com/1.1/statuses/filter.json", requestContent,
ContentType.APPLICATION_FORM_URLENCODED), new TwitConsumer(), null);
Boolean result = future.get();
if(result==null)
{
LOG.error("Requested to close stream!");
return;
}
}
public void ceaseStream()
{
try
{
this.shutdown();
LOG.info("Shutting down the stream");
}
catch (InterruptedException e)
{
LOG.debug("InterruptedException {}", e);
}
}
/*
* (non-Javadoc)
*
* #see java.lang.Runnable#run()
*/
public void run()
{
Thread.currentThread().setName("initiateSTream Thread");
try
{
initiateStream();
Thread.currentThread().interrupt();
}
catch (UnsupportedEncodingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (ExecutionException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I tried to add a return whereever I though it mightbe helpful. but no luck. Can someone help me with this?
Edit 1: When I use the debug mode, I can see that the "initiateSTream Thread" thread. is still running while the main thread is gone!
Edit 2 (Solution): In the main method, I replaced:
Executor ex = Executors.newSingleThreadExecutor();
ex.execute(client);
with:
Thread thread = new Thread(client);
thread.start();
Now my programs ends after the designated time of streaming. But why? What is the difference between the two approaches?!
I have a client that starts a long running process on the server. At regular intervals, I'd like to show the user what's happening in the background. The most simple approach is to poll the server but I'm wondering if there wasn't a way to implement the Observer pattern for this. Unfortunately, I'm using RMI to talk to the server and I fear that I have to turn my client into an RMI server for this.
Is there another way that I'm missing?
http://sites.google.com/site/jamespandavan/Home/java/sample-remote-observer-based-on-rmi
RMI can in general support two way communication. (And yeah, RMI is a PITA to set up, and do anything else with.)
However, the HTTP transport that works over a CGI script(!) does not support it.
Consolidating all the answers here, I implemented 2 way RMI between client and server with server exposing its stub using Registry
The client gets a stub of the server from rmi registry
Then the client puts its stub as Observer to the server's addObserver method
The server notifies the clients using this stub
The following code will gives a better idea
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.util.Observable;
import java.util.Observer;
import java.net.*;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
interface ReceiveMessageInterface extends Remote
{
/**
* #param x
* #throws RemoteException
*/
void receiveMessage(String x) throws RemoteException;
/**
* #param observer
* #throws RemoteException
*/
void addObserver(Remote observer) throws RemoteException;
}
/**
*
*/
class RmiClient extends UnicastRemoteObject
{
/**
* #param args
*/
static public void main(String args[])
{
ReceiveMessageInterface rmiServer;
Registry registry;
String serverAddress = args[0];
String serverPort = args[1];
String text = args[2];
System.out.println("sending " + text + " to " + serverAddress + ":" + serverPort);
try
{ // Get the server's stub
registry = LocateRegistry.getRegistry(serverAddress, (new Integer(serverPort)).intValue());
rmiServer = (ReceiveMessageInterface) (registry.lookup("rmiServer"));
// RMI client will give a stub of itself to the server
Remote aRemoteObj = (Remote) UnicastRemoteObject.exportObject(new RmiClient(), 0);
rmiServer.addObserver(aRemoteObj);
// call the remote method
rmiServer.receiveMessage(text);
// update method will be notified
}
catch (RemoteException e)
{
e.printStackTrace();
}
catch (NotBoundException e)
{
System.err.println(e);
}
}
public void update(String a) throws RemoteException
{
// update should take some serializable object as param NOT Observable
// and Object
// Server callsbacks here
}
}
/**
*
*/
class RmiServer extends Observable implements ReceiveMessageInterface
{
String address;
Registry registry;
/**
* {#inheritDoc}
*/
public void receiveMessage(String x) throws RemoteException
{
System.out.println(x);
setChanged();
notifyObservers(x + "invoked me");
}
/**
* {#inheritDoc}
*/
public void addObserver(final Remote observer) throws RemoteException
{
// This is where you plug in client's stub
super.addObserver(new Observer()
{
#Override
public void update(Observable o,
Object arg)
{
try
{
((RmiClient) observer).update((String) arg);
}
catch (RemoteException e)
{
}
}
});
}
/**
* #throws RemoteException
*/
public RmiServer() throws RemoteException
{
try
{
address = (InetAddress.getLocalHost()).toString();
}
catch (Exception e)
{
System.out.println("can't get inet address.");
}
int port = 3232;
System.out.println("this address=" + address + ",port=" + port);
try
{
registry = LocateRegistry.createRegistry(port);
registry.rebind("rmiServer", this);
}
catch (RemoteException e)
{
System.out.println("remote exception" + e);
}
}
/**
*
* #param args
*/
static public void main(String args[])
{
try
{
RmiServer server = new RmiServer();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
}
I don't think you're missing anything. The only two ways are to either periodically call the server and check the status (polling) or register a callback which the server periodically calls (your client must expose a method). IMO, polling is a perfectly reasonable way to handle this.