jar file not up updating values in file - debugging

I have a javafx project that I am preparing for distributions. The project works perfectly from the debugger inside NetBeans. I am working on Linux.
But when I run the project from the jar file, there is one function in all the others that does not work. This function is supposed to open the settings file on a button click and alter some values from true to false.
I have changed the settings file's location and tried around google, but all to no avail.
I am still quite a newbie to java, fx, netbeans and java (not so much programming) and making my first experiences.
Any idea why this happens?
#FXML
private void openSettingsFile(ActionEvent event) throws IOException {
// this test works ....
ProcessBuilder processBuilder = new ProcessBuilder("terminal");
processBuilder.start();
// this part only replaces the values when I use the debugger ..
Path path = Paths.get("src/desktop_launcher/Settings.java");
Charset charset = StandardCharsets.UTF_8;
String content = new String(Files.readAllBytes(path));
content = content.replaceAll(" \"true\"" , " \"false\"");
Files.write(path, content.getBytes(charset));

Your approach (which, as far as I understand it, is to try to programmatically change the source file that generates the properties file) will not work at deployment time for a number of reasons.
The first is that the source files are generally not available at runtime: your jar file contains the class files and other resources required to run the application, but typically not the source code (and it's not desirable to include it in the application, in general).
Secondly, you are trying to locate this file from a relative path passed to Paths.get(..). This will resolve relative to the working directory, which is essentially arbitrary (basically "where the application was run from"). So even if the source code were available at runtime, this would not be a reliable way to find it. (My guess is that your debugger runs with the working directory fortuitously set to the parent directory of src, but when you run the jar file the most likely location of the working directory is the directory in which the jar file is located. But that is just a guess: it really depends on the configuration of your IDE, debugger, etc etc.)
Thirdly, and probably most importantly, even if the code does find the source file and rewrite it, that's all it will do. Next time you execute the application from the jar file, it won't magically know there is a new version of the source code that has to be compiled and then the resulting class file(s) incorporated into the jar file. So you would have to also include code to compile the new version of your source code (where will you get a compiler? AFAIK not all Java runtimes will include a compiler) and then programmatically insert the new class file(s) into the jar file (how do you even figure out where the jar file is: that is certainly non-trivial and I don't think it can be done in a reliable manner). What if the current user doesn't have permissions to write the directory containing the jar (which is a pretty common scenario..)?
The usual way to load and save startup configuration values is to use the java.util.Properties API. You need an external location to store the properties file, that you can be certain exists on the user's computer: a convenient way to do this is to create an application-specific directory in the user's home directory. The user's home directory can be accessed via System.getProperty("user.home"); (The system property user.home is one of those that is guaranteed to exist.).
I would recommend using a separate class to manage the configuration properties. For example:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Properties;
public class PropertiesAccessor {
private static final Path USER_HOME = Paths.get(System.getProperty("user.home"));
private Properties props ;
private Path path ;
public PropertiesAccessor(String relativePath) {
path = USER_HOME.resolve(relativePath);
props = new Properties();
if (Files.exists(path)) {
try {
props.load(Files.newBufferedReader(path));
} catch (IOException exc) {
System.err.println("Warning: could not load properties file. Using defaults.");
exc.printStackTrace(System.err);
loadDefaults();
}
} else {
loadDefaults();
}
}
public Boolean getBooleanValue(String key) {
String value = props.getProperty(key);
return value == null ? null : Boolean.valueOf(value) ;
}
public void updateBooleanValue(String key, boolean value) {
props.setProperty(key, Boolean.toString(value));
}
public void writeProperties() throws IOException {
if (! Files.exists(path)) {
Files.createDirectories(path.getParent());
Files.createFile(path);
}
props.store(Files.newBufferedWriter(path), "Properties updated "+LocalDateTime.now());
}
private final void loadDefaults() {
// in real life, you might keep a default properties file bundled with
// the application and read that here, e.g.
// props.load(getClass().getResourceAsStream("/default-startup.properties"));
props.setProperty("config.value1", "true");
props.setProperty("config.value2", "false");
}
}
And now you can use this in your application. Just load the properties in the init() method and save them back in the stop() method. Note that executing this will create a directory called .myApp in your home directory, and a file called startup.properties inside it.
import java.io.IOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class StartupPropertiesExample extends Application {
private PropertiesAccessor config ;
private CheckBox value1 ;
private CheckBox value2 ;
#Override
public void init() {
config = new PropertiesAccessor(".myApp/startup.properties");
}
#Override
public void start(Stage primaryStage) {
value1 = new CheckBox("Value 1");
value2 = new CheckBox("Value 2");
value1.setSelected(config.getBooleanValue("config.value1"));
value2.setSelected(config.getBooleanValue("config.value2"));
Button exit = new Button("Exit");
exit.setOnAction(e -> Platform.exit());
VBox root = new VBox(10, value1, value2, exit);
root.setPadding(new Insets(10));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() {
config.updateBooleanValue("config.value1", value1.isSelected());
config.updateBooleanValue("config.value2", value2.isSelected());
try {
config.writeProperties();
} catch (IOException exc) {
System.err.println("Warning: could not save properties");
exc.printStackTrace(System.err);
}
}
public static void main(String[] args) {
launch(args);
}
}

Related

How to write adb commands inside a Android application?

I want to know how to execute adb commands from within my code. For e.g I want to push a file inside the adb shell and I write this:
package org.example.adbshell;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Process process;
try {
process = Runtime.getRuntime().exec("adb push C:/Users/Savio/Desktop/savio.xml /storage/sdcard0/");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
I should be able to see the savio.xml inside the /storage/sdcard0 folder. But for some reason I am unable to see the file. I am guessing that the command is not getting executed. What am I doing wrong here?
There are three type of command
System command // In this case below code is working. like mv/edit/cp/cd etc
Non routed command
Rooted command // You need to routed device.
Try this
Process process Runtime.getRuntime().exec("your command");
//or
Process process Runtime.getRuntime().exec("/path/your_command");
Its work for me of copying file :
Process process Runtime.getRuntime().exec("/system/bin/mv my_file_path");
You can read output data with the help of process object
// Use buffer reader for the same.
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
There is no ADB command on Android's side. ADB is a part of Android SDK only and is always run on computer not on Android.
Also, Android knows nothing about C:/Users/Savio/Desktop/savio.xml as it is not a file in its filesystem.
You should rather implement desktop application with HTTP (or similar) server and use it to download and upload files from Android to PC. You can start with NanoHTTP, a lightweight HTTP implementation.
Or you can use server for communication between Android and computer and run ADB command on that computer based upon request from Android.

How to override your Propertyfile for jUnit (maven)

I have a Propertyfile config.properties in which I store a Path which a class loads to read Files.
The properties are loaded like this:
public class PropertyConfig {
private static final Properties properties = new Properties();
static {
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
public static String getSetting(String key) {
return properties.getProperty(key);
}
}
and the call in the relevant class is like this:
private static File savedGamesFolder = new File(PropertyConfig.getSetting("folder_for_saved_games"));
For testing purposes I want to be able to change the path to a test directory, or change the whole Property-file in a jUnit-TestCase. How can achieve this?
I'm using Maven if that helps.
Assuming you have your config.properties in
src/main/resources/config.properties
Note: you should nevertheless have your properties files somewhere in src/main/resources
Place your test configuration in
src/main/test/config.properties
That's it. No need to change your code.

Images in runnable jar are not working - NullPointer is thrown

I've seen this question all over this website. And I've read almost every response. I feel like I'm doing exactly what is required, but I just can't get it to work! I'm trying to package some images into a Runnable Jar so that my program is self-contained. When I run the code in Eclipse, it works as intended. But when I use the executable Jar, the program will not launch. It gives me a NullPointerException on the line where I create the image. The files are in a folder called Resources in the source folder of the project. Here is the code. It is incomplete because this is just a test program that I've been trying to get working.
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class testgui extends JFrame{
private static JLabel label = new JLabel();
private static testgui gui = new testgui();
private static ArrayList<ImageIcon> sprites;
public static void main(String[] args) {
// TODO Auto-generated method stub
sprites = getImages();
BufferedImage backgroundImage;
try {
backgroundImage = ImageIO.read(new testgui().getClass().getClassLoader().getResource("resources/runescapemap.png"));
gui.setContentPane(gui.new ImagePanel(backgroundImage));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
gui.setLayout(new GridLayout(1,2));
label.setIcon(sprites.get(0));
gui.add(label);
gui.setSize(1000,900);
gui.setVisible(true);
}
private static ArrayList<ImageIcon> getImages(){
ImageIcon autoTalkerLogo = new ImageIcon(new testgui().getClass().getClassLoader().getResource("Resources/autotalker-logo.png"));
ImageIcon meterNormal = new ImageIcon(new testgui().getClass().getClassLoader().getResource("Resources/meter.png"));
ImageIcon meterSafe = new ImageIcon(new testgui().getClass().getClassLoader().getResource("Resources/meter-safe.png"));
ImageIcon meterNotSafe = new ImageIcon(new testgui().getClass().getClassLoader().getResource("Resources/meter-notsafe.png"));
ArrayList<ImageIcon> sprites = new ArrayList<ImageIcon>();
sprites.add(autoTalkerLogo);
sprites.add(meterNormal);
sprites.add(meterSafe);
sprites.add(meterNotSafe);
return sprites;
}
class ImagePanel extends JComponent {
private Image backgroundImage;
public ImagePanel(Image image) {
this.backgroundImage = image;
}
#Override
protected void paintComponent(Graphics g) {
g.drawImage(backgroundImage, 0, 0, null);
}
}
}
If the folder is genuinely called Resources rather than resources, that could be the problem. While the Windows file system is case-insensitive, jar files aren't.
Try
...getResource("Resources/runescapemap.png")
I note that your later calls to getResource do use Resources rather than resources.
Of course, it could be the other way round - maybe your folder is actually resources, and it's the first call that's okay and the other four should use resources. Either way, it's unlikely that both are correct...

MEF and AssemblyCatalog / AggregateCatalog

I have a simple console app as below (un-relevant code removed for simplicity)
[ImportMany(typeof(ILogger))]
public IEnumerable<ILogger> _loggers {get;set;}
public interface ILogger
{
void Write(string message);
}
[Export(typeof(ILogger))]
public class ConsoleLogger : ILogger
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
[Export(typeof(ILogger))]
public class DebugLogger : ILogger
{
public void Write(string message)
{
Debug.Print(message);
}
}
The code that initialize the catalog is below
(1) var catalog = new AggregateCatalog();
(2) catalog.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory));
(3) //var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);
If the catalog is initialized trough lines 1-2, nothing got loaded into _logger
If the catalog is initialized trough line 3, both logger got loaded into _logger
What's the issue with AggregateCatalog approach?
Thanks
It should work the way you are using it.
However, on line 2 you are creating a DirectoryCatalog, and on line 3 an AssemblyCatalog. Does it work as expected if you change line two into
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
I found the problem.
It seems DirectoryCatalog(path) search only in DLL by default, and my test program was a console application. And the exports were in EXE (not DLL) so they weren't loaded.
On the other hand, AssemblyCatalog(Assembly.GetExecutingAssembly()), obviously loaded exports from current assembly(which is the EXE).
The solution is to use the other constructor of DirectoryCatalog(path, searchPattern) , and use "*.*" for second param. And it works

How to edit a maven POM at runtime?

I need editing POM at runtime. I used Dom4j for read pom and after that set some data. But i need know if exist another form for to do this. Exist a maven utilities for this?
Use MavenXpp3Reader to read and MavenXpp3Writer to write Model objects. Simple example:
String baseDir = "/your/project/basedir/";
//Reading
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(new FileInputStream(new File(baseDir, "/pom.xml")));
//Editing
model.setUrl("http://stackoverflow.com");
//Writing
MavenXpp3Writer writer = new MavenXpp3Writer();
writer.write(new FileOutputStream(new File(baseDir, "/pom.xml")), model);
And notice that any comment, extra white spaces or lines will be removed from the file.
Depending on what you are changing, there may be maven plugins. For example the maven release plugin updates the version information in the pom.xml and checks the changes into version control.
Try searching for the specific task you are trying to accomplish (e.g. "maven plugin version number update") rather than the more generic "modify pom.xml".
This code works for me:
package or.jrichardsz;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Writer;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
public class TestMavenPomEdit {
public static void main(String[] args) throws Exception {
//read initial pom
Model model = parsePomXmlFileToMavenPomModel("C:\\Users\\User\\Desktop\\initial_pom.xml");
//add some pom modification
Plugin plugin = new Plugin();
plugin.setGroupId("com.jelastic");
model.getBuild().addPlugin(plugin);
//write new pom
parseMavenPomModelToXmlString("C:\\Users\\User\\Desktop\\final_pom.xml", model);
}
public static Model parsePomXmlFileToMavenPomModel(String path) throws Exception {
Model model = null;
FileReader reader = null;
MavenXpp3Reader mavenreader = new MavenXpp3Reader();
reader = new FileReader(path);
model = mavenreader.read(reader);
return model;
}
public static void parseMavenPomModelToXmlString(String path,Model model) throws Exception {
MavenXpp3Writer mavenWriter = new MavenXpp3Writer();
Writer writer = new FileWriter(path);
mavenWriter.write(writer, model);
}
}
TestMavenPomEdit.java
HTH

Resources