Ok, I'm sure this should be pretty easy, but I'm fairly new to Java (I'm more a .NET boy :P) and after following every single recommendation I found here to no success, I think it's time to step back and ask.
I'm trying to start a simple rmi project with a client, a server and a common project where common interfaces are defined. I've just implemented my server code, and when I try to run it to check if everything is fine, I get struck on a java.lang.ClassNotFoundException.
After following several answers on similar issues, I'm fair sure that my problem comes from rmiregistry running on a different location than my project.
I use following code to set registry codebase:
public class Utils {
public static final String CODEBASE = "java.rmi.server.codebase";
public static void setCodeBase(Class<?> c) {
String ruta = c.getProtectionDomain().getCodeSource().getLocation().toString();
String path = System.getProperty(CODEBASE);
if (path != null && !path.isEmpty()) {
ruta = path + " " + ruta;
}
System.setProperty(CODEBASE, ruta);
}
}
Then, I try to start my server code with this main class:
public class MainRegulador {
public static void main(String[] args) throws AccessException, RemoteException, NotBoundException {
Utils.setCodeBase(IRegulador.class);
Registry registro = null;
Remote proxy = null;
try {
Regulador myReg = new Regulador();
proxy = UnicastRemoteObject.exportObject(myReg, 36510);
registro = LocateRegistry.getRegistry();
registro.rebind("Distribuidor", proxy); //this is the line where exception is thrown
System.out.println("El Regulador está corriendo. Pulse ENTER para finalizar el proceso.");
System.in.read();
} catch(Exception ex) {
System.out.println("No se ha logrado inicializar el Registrador");
System.out.println(ex.getMessage());
} finally {
if (registro != null && proxy != null) {
registro.unbind("Distribuidor");
UnicastRemoteObject.unexportObject(proxy, true);
}
}
}
}
But when I run it, always get a java.lang.ClassNotFoundException at IRegulador interface.
Now the fun part:
I've printed to console java.rmi.server.codebase value, and it's pointing to bin folder of project where IRegulador interface is defined. (file:/F:/Practicas%20y%20dem%c3%a1s/Sistemas%20Distribuidos/common/bin/)
Obviously, that project is also set in the classpath of server project
(Regulador)
Workspace and rmiregistry are on different disks
Despite all, it doesn't seem a global classpath problem, as Utils class is on the same project as IRegulador interface, and it runs before the exception is thrown (as java.rmi.server.codebase is correctly set).
I've tried to set the classpath of rmiregistry before calling it (although it is directly discouraged on some answers), but nothing changed.
I've also tried to start rmiregistry.exe from Regulador project bin folder, but also seemed to don't change anything.
Coming from a .NET background, I've always found these classpath issues confusing, and this one is starting to consume much more time than I suspect it deserves. I'm in desperate need of help.
UPDATE: I'm starting to think that the problem is within the url it's passed to the codebase from IRegulador.class. If I paste it into windows explorer, the SO is unable to locate it, so I supose that it's being built with some structure problem that prevents the registry to reach the route:
file:/F:/Practicas%20y%20dem%c3%a1s/Sistemas%20Distribuidos/common/bin/
UPDATE2: I thought path route could be too complex, so I decided to simplify it and strip it from any non-straight character. Now codebase value is
file:/F:/Practicas/SD/common/bin/
However the problem persists, I don't know why rmiregistry is unable to reach that folder.
Then I decided to move the whole project to the same disk where rmiregistry is executed, and see if it changes anything. But nothing changed, same problem.
Ok, finally I got it working...
I've just copied rmiregistry.exe into the common/bin folder and launch it directly from there (previously just had called from there).
This seems to fix the problem with the routes (actually it makes the route available to the registry as it's on the same folder, probably all my codebase writting code is superflous now).
Related
I need the functionality like that of the rsync linux tool in my Java program. For that, I chose the rsync4j library.
Using their documentation, I wrote the following program:
import com.github.fracpete.processoutput4j.output.ConsoleOutputProcessOutput;
import com.github.fracpete.rsync4j.RSync;
public class MainClass {
public static void main(String [] args) {
System.out.println("Started");//check
RSync rsync = new RSync()
.source("/home/arth/DataSourceFolder/a.txt")
.destination("/home/arth/DataDestinationFolder/")
.recursive(true);
// or if you prefer using commandline options:
// rsync.setOptions(new String[]{"-r", "/one/place/", "/other/place/"});
CollectingProcessOutput output = null;
try {
System.out.println("Inside try");
output = rsync.execute();
System.out.println("End of try");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(output.getStdOut());
System.out.println("Exit code: " + output.getExitCode());
if (output.getExitCode() > 0)
System.err.println(output.getStdErr());
}
}
In the snippet, in out local machine, a file a.txt is copied from one location to another. This works perfectly. The file is successfully copied when I run it and here is the output:
Started
Inside try
End of try
Exit code: 0
But my need is to sync a local directory with a directory lying at a remote host/machine. When I tried to do it using a simple rsync command from a terminal using the following command
rsync remoteUserName#23.24.25.244:/home/beth/remoteFolder/a.png /home/arth/DataSourceFolder
it works like a charm. a.png IS copied to local machine at path specified, although a password of remote machine is asked first.
But the problem when I use the above Java program to do the same operation, by replacing line # 11 and 12 by:
.source("remoteUserName#23.24.25.244:/home/beth/remoteFolder/a.png")
.destination("/home/arth/DataDestinationFolder/")
the program gets stuck after printing Started in the console. Neither an exception is thrown nor does the program proceed.
The question is that how do I fix this problem?
(old post, I know, but here it goes...) The rsync4j library does not allow interaction. In your case, the underlying rysnc binary prompts for a password in the process that the Java library created, but never receives one.
Starting with release 3.2.3-7, you can supply an instance of the sshpass wrapper to feed in the password (see this comment for an example).
I'm trying to use Azure Application Insight in Cuba Platform: https://learn.microsoft.com/en-us/azure/application-insights/app-insights-java-get-started
I managed to add the library to Cuba Platform, in particular to the Web module, but I couldn't set the "Instrumentation key" in any way.
There are three ways to do so:
1- Putting ApplicationInsights.xml in the "resource" folder
I couldn't find a place to put the file to be read by TelemetryConfigurationFactory class. Internally, I see it's using getResource() to scan in various "sensible" places.
I tried WEB-INF, META-INF, conf directory in Tomcat, conf/app, root of java package, work/app in Tomcat and probably something more with no results.
2- System property: -DAPPLICATION_INSIGHTS_IKEY=your_ikey
3- Environment variable: APPLICATION_INSIGHTS_IKEY
Tried both in a docker container, tried the last one locally: no results. In particular, System.getEnv is returning null even after exporting manually the variable locally, so this could be some error on my side
Any insight :D is welcome
I tried to search for the configuration of Instrumentation key from Application Insights source code.
I can see the snippet of code as below in the TelemetryConfigurationFactory Class.
/**
* Setting an instrumentation key:
* First we try the system property '-DAPPLICATION_INSIGHTS_IKEY=i_key' or '-DAPPINSIGHTS_INSTRUMENTATIONKEY=i_key'
* Next we will try the environment variable 'APPLICATION_INSIGHTS_IKEY' or 'APPINSIGHTS_INSTRUMENTATIONKEY'
* Next we will try to fetch the i-key from the ApplicationInsights.xml
* #param userConfiguration The configuration that was represents the user's configuration in ApplicationInsights.xml.
* #param configuration The configuration class.
*/
private void setInstrumentationKey(ApplicationInsightsXmlConfiguration userConfiguration, TelemetryConfiguration configuration) {
try {
String ikey;
// First, check whether an i-key was provided as a java system property i.e. '-DAPPLICATION_INSIGHTS_IKEY=i_key', or '-DAPPINSIGHTS_INSTRUMENTATIONKEY=i_key'
ikey = System.getProperty(EXTERNAL_PROPERTY_IKEY_NAME);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
ikey = System.getProperty(EXTERNAL_PROPERTY_IKEY_NAME_SECONDARY);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
// Second, try to find the i-key as an environment variable 'APPLICATION_INSIGHTS_IKEY' or 'APPINSIGHTS_INSTRUMENTATIONKEY'
ikey = System.getenv(EXTERNAL_PROPERTY_IKEY_NAME);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
ikey = System.getenv(EXTERNAL_PROPERTY_IKEY_NAME_SECONDARY);
if (!Strings.isNullOrEmpty(ikey)) {
configuration.setInstrumentationKey(ikey);
return;
}
// Else, try to find the i-key in ApplicationInsights.xml
if (userConfiguration != null) {
ikey = userConfiguration.getInstrumentationKey();
if (ikey == null) {
return;
}
ikey = ikey.trim();
if (ikey.length() == 0) {
return;
}
configuration.setInstrumentationKey(ikey);
}
} catch (Exception e) {
InternalLogger.INSTANCE.error("Failed to set instrumentation key: '%s'", e.getMessage());
}
}
It seems that Instrumentation key can be configured as a java system property or as an environment variable or in ApplicationInsights.xml.
According to your description , System.getEnv("XXX") in your code return null.
You could check the possible reasons below :
Use My Computer > Advanced > Environment Variables to make a variable visible to all new processes.
2.The process which tries to read the variable is already running. Restart it.
3.The start script of Tomcat unsets the variable before it invokes java.exe
4.Tomcat unsets the variable in it's Java code.
In addition , you could refer to this thread : System.getenv() returns null when the environment variable exists.
Hope it helps you.
I am trying to use JIntellitype to listen to global hotkeys but I get this error:
Exception in thread "main"
com.melloware.jintellitype.JIntellitypeException: Could not load
JIntellitype.dll from local file system or from inside JAR at
com.melloware.jintellitype.JIntellitype.(JIntellitype.java:114)
at
com.melloware.jintellitype.JIntellitype.getInstance(JIntellitype.java:177)
at utils.HotKey.(HotKey.java:19) at
ui.Main.Catch_Hotkeys(Main.java:78) at ui.Main.(Main.java:20)
at ui.Main.main(Main.java:15) Caused by: java.io.IOException:
FromJarToFileSystem could not load DLL:
com/melloware/jintellitype/JIntellitype.dll at
com.melloware.jintellitype.JIntellitype.fromJarToFs(JIntellitype.java:150)
at
com.melloware.jintellitype.JIntellitype.(JIntellitype.java:105)
... 5 more Caused by: java.lang.NullPointerException at
com.melloware.jintellitype.JIntellitype.fromJarToFs(JIntellitype.java:146)
... 6 more
I have loaded the jar file and I also pointed to the folder where the dlls are located through Referenced Libraries.
Here is the code I am trying to run:
import com.melloware.jintellitype.HotkeyListener;
import com.melloware.jintellitype.IntellitypeListener;
import com.melloware.jintellitype.JIntellitype;
public class HotKey extends Thread implements HotkeyListener, IntellitypeListener {
private final int CTRL_C_SHIFT = 10;
public HotKey()
{
JIntellitype.getInstance().unregisterHotKey(CTRL_C_SHIFT);
JIntellitype.getInstance().registerHotKey(CTRL_C_SHIFT, JIntellitype.MOD_CONTROL + (int)'C', JIntellitype.MOD_SHIFT);
if (!JIntellitype.isJIntellitypeSupported())
{
System.exit(1);
}
}
#Override
public void onIntellitype(int arg0)
{
}
#Override
public void onHotKey(int key)
{
if (key == CTRL_C_SHIFT)
{
System.out.println("smg");
}
}
}
Any idea how to fix this?
Your problem will occur because of a version problem between that OS version and the JRE version.
You should check:
Whether an appropriate dll file is installed in your OS system folder.
JIntellitype package has two dll files, one is for 32bit OSs and the other is for 64bit OSs, they have different names.
Check your Java Platform version in the properties of the projects.
You can try to change the Java Platform, if there are more than one types of JDKs.
Make sure about which one is for 64bit or 32bit version.
Have good luck!
I recommend you do something like this:
try
{
JIntellitype.getInstance().unregisterHotKey(CTRL_C_SHIFT);
MyHotKeyListener hotKeyListener = new MyHotKeyListener();
hotKeyListener.addObserver(new MyEventListener());
JIntellitype.getInstance().addHotKeyListener(hotKeyListener);
JIntellitype.getInstance().registerHotKey(CTRL_C_SHIFT, JIntellitype.MOD_CONTROL + (int)'C', JIntellitype.MOD_SHIFT);
}
catch (JIntellitypeException je)
{
logger.warn("JIntellitype initialization failed.");
// DO WHATEVER (NOTIFY USERS?)
}
I can point to other threads, including one where the creator of this library himself denies problems with the library. However, many users such as myself encounter these sort of problems from time to time where JIntellitype fails to initialize and the only solution is to reboot the computer. Because of this, you should catch the JIntellitype exception (the only exception thrown by the library) and warn users (via dialog window) that the hotkey failed to register. You should give them the option to continue without them, or to reboot the computer and trying again.
Trust me.... unless this is a constant problem (which means you configured it incorrectly), it is your best alternative. This WILL happen from time to time at random.
I'm maintaining a Java Swing application that requires a connection to an instance of Microsoft SQL Server. For various reasons, I opted to replace the native SQL Server driver being used with jTDS (the aforementioned Microsoft drivers were not working at the time and have apparently failed in the field as well). When I try to run the executable .jar outside of the IDE, I run into issues because I'm missing the appropriate ntlmauth.dll dependency.
Before proceeding, it's important to note that this application is being developed and used in an extremely restrictive (Windows-only) environment:
I cannot install any software that requires Windows UAC authentication
My users cannot install or run any software that requires UAC authentication
This currently means I cannot write files to System32 or JAVA_HOME, and cannot use any sort of ProcessBuilder tomfoolery to start another JVM with whatever command line arguments I need
I cannot use executable wrappers/installers that would only require the UAC permission for the first time installation/setup
The solution I'm trying is a combination of this one and this one to check it--essentially packaging the .dll inside of the .jar, then extracting it and loading it if necessary--as most of the other solutions I've found have been incompatible with the above restrictions; however, I'm running into an issue where even after the native library is ostensibly "loaded," I get an exception saying it isn't.
My pre-startup code:
private static final String LIB_BIN = "/lib-bin/";
private static final String JTDS_AUTH = "ntlmauth";
// load required JTDS binaries
static {
logger.info("Attempting to load library {}.dll", JTDS_AUTH);
try {
System.loadLibrary(JTDS_AUTH);
} catch (UnsatisfiedLinkError e) {
loadFromJar();
}
try {
// do some quick checks to make sure that went ok
NativeLibraries nl = new NativeLibraries();
logger.debug("Loaded libraries: {}", nl.getLoadedLibraries().toString());
} catch (NoSuchFieldException ex) {
logger.info("Native library checker load failed", ex);
}
}
/**
* When packaged into JAR extracts DLLs, places these into
*/
private static void loadFromJar() {
// we need to put DLL in temp dir
String path = ***;
loadLib(path, JTDS_AUTH);
}
/**
* Puts library to temp dir and loads to memory
*/
private static void loadLib(String path, String name) {
name = name + ".dll";
try {
// have to use a stream
InputStream in = net.sourceforge.jtds.jdbc.JtdsConnection.class.getResourceAsStream(LIB_BIN + name);
// always write to different location
File fileOut = new File(System.getProperty("java.io.tmpdir") + "/" + path + LIB_BIN + name);
logger.info("Writing dll to: " + fileOut.getAbsolutePath());
OutputStream out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
System.load(fileOut.toString());
} catch (Exception e) {
logger.error("Exception with native library loader", e);
JOptionPane.showMessageDialog(null, "Exception loading native libraries: " + e.getLocalizedMessage(), "Exception", JOptionPane.ERROR_MESSAGE);
}
}
As you can see, I basically copied the solution from the first link verbatim, with a few minor modifications just to try and get the application running. I also copied the class from the second link and named it NativeLibraries, the invocation of that method is fairly irrelevant but it shows up in the logs.
Anyway here are the relevant bits of the log output on starting up the application:
2015-07-20 12:32:33 INFO - Attempting to load library ntlmauth.dll
2015-07-20 12:32:33 INFO - Writing dll to: C:\Users\***\lib-bin\ntlmauth.dll
2015-07-20 12:32:33 DEBUG - Loaded libraries: [C:\Program Files\Java\jre1.8.0_45\bin\zip.dll, C:\Program Files\Java\jre1.8.0_45\bin\prism_d3d.dll, C:\Program Files\Java\jre1.8.0_45\bin\prism_sw.dll, C:\Program Files\Java\jre1.8.0_45\bin\msvcr100.dll, C:\Program Files\Java\jre1.8.0_45\bin\glass.dll, C:\Program Files\Java\jre1.8.0_45\bin\net.dll, C:\Users\***\lib-bin\ntlmauth.dll]
2015-07-20 12:32:33 INFO - Application startup
***
2015-07-20 12:32:36 ERROR - Database exception
java.sql.SQLException: I/O Error: SSO Failed: Native SSPI library not loaded. Check the java.library.path system property.
at net.sourceforge.jtds.jdbc.TdsCore.login(TdsCore.java:654) ~[jtds-1.3.1.jar:1.3.1]
at net.sourceforge.jtds.jdbc.JtdsConnection.<init>(JtdsConnection.java:371) ~[jtds-1.3.1.jar:1.3.1]
at net.sourceforge.jtds.jdbc.Driver.connect(Driver.java:184) ~[jtds-1.3.1.jar:1.3.1]
at java.sql.DriverManager.getConnection(Unknown Source) ~[na:1.8.0_45]
at java.sql.DriverManager.getConnection(Unknown Source) ~[na:1.8.0_45]
One can see that the library was, indeed, "loaded," from the third line in the log (it's the last entry, if you don't feel like scrolling). However, I simply used the class that I felt like was probably using the native libraries (I also tried the TdsCore class to no avail), as the example that showed how to do this was just using a random class from the package the library was needed in.
Is there something I'm missing here? I'm not very experienced with the JNI or the inner workings of ClassLoaders, so I might just be loading it wrong. Any advice or suggestions would be greatly appreciated!
Welp I figured out a workaround: I ended up using JarClassLoader. This basically entailed copying all my dependencies, both Java and native, into a "libraries" folder within my main .jar, and disabling .jar signing in the IDE. The application is then run by a new class that simply creates a new JarClassLoader object and running the "invokeMain" method--an example is on the website. The whole thing took about three minutes, after several days of banging my head against a wall.
Hope this helps someone someday!
My current java project is using methods and variables from another project (same package). Right now the other project's jar has to be in the classpath to work correctly. My problem here is that the name of the jar can and will change because of increasing versions, and because you cannot use wildcards in the manifest classpath, it's impossible to add it to the classpath. So currently the only option of starting my application is using the -cp argument from the command line, manually adding the other jar my project depends on.
To improve this, I wanted to load the jar dynamically and read about using the ClassLoader. I read a lot of examples for it, however I still don't understand how to use it in my case.
What I want is it to load a jar file, lets say, myDependency-2.4.1-SNAPSHOT.jar, but it should be able to just search for a jar file starting with myDependency- because as I already said the version number can change at anytime. Then I should just be able to use it's methods and variables in my Code just like I do now (like ClassInMyDependency.exampleMethod()).
Can anyone help me with this, as I've been searching the web for a few hours now and still don't get how to use the ClassLoader to do what I just explained.
Many thanks in advance
(Applies to Java version 8 and earlier).
Indeed this is occasionally necessary. This is how I do this in production. It uses reflection to circumvent the encapsulation of addURL in the system class loader.
/*
* Adds the supplied Java Archive library to java.class.path. This is benign
* if the library is already loaded.
*/
public static synchronized void loadLibrary(java.io.File jar) throws MyException
{
try {
/*We are using reflection here to circumvent encapsulation; addURL is not public*/
java.net.URLClassLoader loader = (java.net.URLClassLoader)ClassLoader.getSystemClassLoader();
java.net.URL url = jar.toURI().toURL();
/*Disallow if already loaded*/
for (java.net.URL it : java.util.Arrays.asList(loader.getURLs())){
if (it.equals(url)){
return;
}
}
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(loader, new Object[]{url});
} catch (final java.lang.NoSuchMethodException |
java.lang.IllegalAccessException |
java.net.MalformedURLException |
java.lang.reflect.InvocationTargetException e){
throw new MyException(e);
}
}
I needed to load a jar file at runtime for both java 8 and java 9+. Here is the method to do it (using Spring Boot 1.5.2 if it may relate).
public static synchronized void loadLibrary(java.io.File jar) {
try {
java.net.URL url = jar.toURI().toURL();
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(Thread.currentThread().getContextClassLoader(), new Object[]{url});
} catch (Exception ex) {
throw new RuntimeException("Cannot load library from jar file '" + jar.getAbsolutePath() + "'. Reason: " + ex.getMessage());
}
}