JPackage (incubator) and SQLite database problem - java

I could use some help again, out of ideas. :(
I am making JavaFX application that will use SQLite database. OpenJDK 14 with OpenJFX14 is used. In my Eclipse all is working perfectly. I tried for test to make installer with JPackage and that worked too. When I start installed application it starts ok, but for some reason refuse to connect with database.
Here is my project structure:
I have a button where when Stage is loaded I check connection. It is in file PocetnaController:
//testiranje konekcije nakon instalacije
#FXML
public void btnObracunClick(ActionEvent event) {
lblStatus.setText(model.povezanaBaza());
}
And this is code from PocetnaModel that is called:
public String povezanaBaza() {
this.konekcija = Konekcija.poveziBazu();
return (this.konekcija != null) ? "Веза са базом успостављена" : "Повезивање са базом није успело.";
}
When true it returns "Database connection established" in my language and when false "Connection with database failed".
I repeat, in Eclipse all works well. But, when start installed app I am getting "Connection with database failed". So connection returning null for some reason.
My db file is coppied by JPackage in /app folder. I tried to copy manualy Porez.db to root folder where *.exe is. Strange thing, status label doesn't change in that case. And it should, it must return true or false, don't understand that.
This is stage look when started:
Even if I rename database file in /app folder, so it can't be found my connection still returning false and update status accordingly which is ok.
Here is entire Konekcija file who has a role to take care of connection:
public static Connection poveziBazu() {
File baza = new File("Porez.db");
try {
if (baza.exists()) {
Connection con = DriverManager.getConnection("jdbc:sqlite:Porez.db");
return con;
} else {
return null;
}
} catch (Exception e) {
return null;
}
}
My first suspect is something is wrong with my created JAR, but can't be sure. Makes no sense to me to work in Eclipse and no after install.

There are several places you need to check and possibly fix if you ran jpackage with:
jpackage --name SQLiteTest --input C:\Users\Dalibor\Documents\NetBeansProjects\SQLiteTest\dist --main-jar SQLiteTest.jar --runtime-image hello\myjre
Turn on Windows console so that you can see the error messages it is providing - use jpackage --win-console.
After installing your jpackaged release, check the release directory structure.
Make sure it contains the sqllite-jdbc.jar file.
If NOT found fix your --input directories to add the jar.
Check the app\xxx.cfg file for your generated application.
It must contain all your jar dependencies including sqlite-jdbc.jar such as:
app.classpath=$ROOTDIR\app\jars\xxxx.jar;$ROOTDIR\app\jars\sqlite-jdbc.jar
Check that the jlink command you used to build the runtime image hello\myjre includes --add-modules java.sql to combine with the required SQL dependencies.
The app structure created by the installer that jpackage builds is different to the structure you have in Eclipse - files are under app directory, and most importantly the release is only editable with Administrator privileges. Use System property java.launcher.path to adjust the location of the SqlLite database to an editable location
and don't mask exceptions:
public static Connection poveziBazu() {
File baza = new File("Porez.db");
String jhome = System.getProperty("java.launcher.path");
if (jhome != null) {
baza = new File(System.getProperty("user.home"), "Porez.db");
}
System.out.println("Connecting to "+baza.getAbsolutePath()+" exists()="+baza.exists());
try {
return DriverManager.getConnection("jdbc:sqlite:"+baza.getAbsolutePath());
} catch (Exception e) {
System.out.println("Failed connecting to: "+baza);
throw new RuntimeException("Failed to open or create db: "+baza, e);
}
}

Related

Using rsync4j library, a Java implementation of Linux rsync tool, how to sync data from a remote directory with a local directory

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).

java rmi simple project classNotFoundException binding registry

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).

Manually loading native libraries to circumvent a restrictive environment

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!

Update java desktop app

I am trying to develop a module that can update my running Java Desktop App.
The problem is that I have to replace the actual running jar with another jar, all the while displaying an image and a progress bar with the remaining time of the update process.
One solution I thought about is that I can put a jar in my main jar, and when launching the update process, to extract that second jar which will display the image and the progess bar, and also which will replace the old main jar with a new main jar.
My question is if this is possible and how can I do it.
I do not have a lot of experience with java and java packaging so if you have any examples or links, it would be of great help for me.
Thank you very much.
R.
Run this code when press UPDATE button ..
if(Desktop.isDesktopSupported()){
try {
Desktop.getDesktop().open(new File("update.jar"));
System.exit(0);
} catch (IOException ex) {
}
}
This will open update.jar and close main.jar. Now run this code from main class of update.jar
//wait sometime for terminate main.jar
try{
Thread.sleep(5000);
} catch(Exception e){
e.printStackTrace();
}
if(isUpdateVersionAvailable()) { //first check update from database
if(copyMainJarFileFromServer()){ //copy newMain.jar from server and paste
new File("main.jar").delete(); //delete main.jar
rename(new File("newMain.jar")); //rename newMain.jar to main.jar
}
}
boolean isUpdateVersionAvailable() {
//todo
}
boolean copyMainJarFileFromServer() {
//todo
}
void rename(File file){
file.renameTo(new File("main.jar"));
}
You can have a starter jar that checks for updates and launches the app from the main jar.
It will show start logo, an image, that standard java can display at start-up.
The start0er could also be used to restart the app in another interface language.
package starter;
...
public class StarterApp {
public static void main(String[] args) {
String workDir = System.getProperty("user.dir");
Path mainJar = Paths.get(workDir + "...");
Path nextMainJar = Paths.get(workDir + "...");
if (Files.exists(nextMainJar)) {
Files.copy(nextMainJar, mainJar, StandardCopyAction.REPLACE_EXISTING);
}
URLClassLoader classLoader = new URLClassLoader(new URL[] {mainJar.toURL()});
Class<?> appClass = classLoader.find("mainjar.MainApp");
... instantiate the app
}
As you see the main jar must not be loaded from too early, maybe not be on the class path entirely, and hence the use of a separate ClassLoader. The same might probably be done with the main jar on the class path of the starter app, and using Class.forName("mainjar.MainApp"). The Class-Path can be specified in META-INF/MANIFEST.MF.
The secundary jars may reside in a lib/ directory.
For those readers wanting more modular, service oriented, updateable apps, one could make an OSGi application, a container for bundles (=jars), that provide exchangable services and life-time control.

Java connectivity with PostgreSQL

Can someone please tell me how to connect java file to postgresql database (if possible with code n explanation)
Google is a good start
http://jdbc.postgresql.org/
Here is an example test.java
import java.sql.*;
class test
{
public static void main(String[] args) {
String hostname="", dbname="", username="", password="";
try {
int argno = 0;
hostname = args[argno++];
dbname = args[argno++];
username = args[argno++];
password = args[argno++];
} catch (Exception ex) {
System.err.println("Usage: java -cp driver.jar:. test [hostname] [dbname] [username] [password]");
System.exit(1);
}
try {
Class.forName("org.postgresql.Driver");
Connection connection =
DriverManager.getConnection(
"jdbc:postgresql://"+hostname+"/"+dbname,
username,
password
);
ResultSet rs = connection.createStatement().executeQuery(
"select version() as version"
);
while ( rs.next() ) {
System.out.println(rs.getString("version"));
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Download a current driver from JDBC download page, compile this and run like this on Unices:
java -cp [driver_file_name].jar:. test [hostname] [dbname] [username] [password]
On Windows:
java -cp [driver_file_name].jar;. test [hostname] [dbname] [username] [password]
Just wanted to expound on Tometzky's answer for other beginners using the Netbeans IDE in UNIX like me.
I want the driver to be recognized as a library in the IDE. If you go to Tools->Libraries, you will see the current list. Hit "New Library" and type "PostgreSQL JDBC Driver" or whatever name you want to give it. Then in the Classpath tab, hit "Add JAR/Folder" and point to where you've saved your downloaded driver. I'm not sure if there is a "correct" place to store it, I think it rather depends on how you back up your system and if multiple users share it. Somewhere in your home directory is fine.
After that, make a new project of type "Java Application" and paste Tometzky's code into main. In your project tree, right click on Libraries and add the JDBC driver directly to the project. Now you don't have to worry about specifying the driver on the command line.
Build your project and head over to its "dist" folder. Now you can run it with the command
java -jar myprojectname.jar 127.0.0.1 [dbname] [user] [pw]
That of course assumes you are connect to the database server on your own machine. [user] and [pw] refer to your PostgreSQL username and pw.
Also, when you download the documentation it comes as a bunch of html files. Save them somewhere and point your browser to the index.html file (in Firefox it is File-->Open File).

Categories