Best practices for file system of application data JavaFX - file

I am trying to build an inventory management system and have recently asked a question about how to be able to store images in a package within my src file. I was told that you should not store images where class files are stored but have not been told what the best practices are for file systems. I have created a new page that allows the user to input all the data about a new part that they are adding to the system and upload an image associated with the part. When they save, everything worked fine until you try to reload the parts database. If you 'refresh' eclipse and then update the database, everything was fine because you could see the image pop into the package when refreshed. (All database info was updated properly as well.
I was told not to store these types of 'new' images with the program files but to create a separate file system to store these types of images. Is there a best practice for these types of file systems? My confusion is when the program gets saved where ever it is going to be saved, I can't have it point to an absolute path because it might not be saved on a C drive or K drive and I wouldn't want an images folder just sitting on the C drive that has all of the parts images for anyone to mess with. Please give me some good resources on how to build these file systems. I would like the images folder 'packaged' with the program when I compile it and package all the files together, I have not been able to find any good information on this, thanks!

To answer this question, probably not in the best way, but works pretty well.
I ended up making another menuItem and menu that you can see at the top 'Image Management', where it lets the user set the location that they would like to save all the images as well as a location to back up the images. it creates the directory if it is not there or it will save over the images if the directory is already there. This menu will only appear if the user has admin privileges. I would think that this could be set up with an install wizard, but I have no idea how to make one, where it only runs on installation. I am also going to add an autosave feature to save to both locations if a backup location has been set. This is the best way I can think of managing all the parts images, if anyone has some good input, please let me know. I considered a server, but think that is too much for this application and retrieving images every time the tableView populates would take a lot of time. If interested the code I used is:
public class ImageDirectoryController implements Initializable{
#FXML private AnchorPane imageDirectory;
#FXML private Label imageDirLbl, backupLbl;
#FXML private Button setLocationButton, backupButton;
#FXML private TextField imageDirPathTxtField;
Stage window;
String image_directory;
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
public void setImageDirectory(String image_address, String backup_address) {
imageDirLbl.setText(image_address);
backupLbl.setText(backup_address);
}
#FXML
public void setLocationButtonClicked () {
String imagesPath = imageDirPathTxtField.getText() + "tolmarImages\\";
File files = new File(imagesPath + "asepticImages");
File generalFiles = new File(imagesPath + "generalImages");
File facilitiesFiles = new File(imagesPath + "facilitiesImages");
boolean answer = ConfirmBox.display("Set Image", "Are you sure you want to set this location?");
if(answer) {
if (!files.exists()) {
if (files.mkdirs() && generalFiles.mkdirs() && facilitiesFiles.mkdirs()) {
JOptionPane.showMessageDialog (null, "New Image directories have been created!", "Image directory created", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog (null, "Failed to create multiple directories!", "Image directory not created", JOptionPane.INFORMATION_MESSAGE);
}
}
DBConnection dBC = new DBConnection();
Connection con = dBC.getDBConnection();
String updateStmt = "UPDATE image_address SET image_address = ? WHERE rowid = ?";
try {
PreparedStatement myStmt = con.prepareStatement(updateStmt);
myStmt.setString(1, imageDirPathTxtField.getText());
myStmt.setInt(2, 1);
myStmt.executeUpdate();
myStmt.close();
imageDirPathTxtField.clear();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#FXML
public void backupButtonClicked () {
String backupStatus = null;
if (backupLbl.getText().equals("")&& !imageDirPathTxtField.getText().equals("")) {
backupStatus = imageDirPathTxtField.getText();
} else if (!imageDirPathTxtField.getText().equals("")) {
backupStatus = imageDirPathTxtField.getText();
} else if (!backupLbl.getText().equals("")){
backupStatus = backupLbl.getText();
} else {
JOptionPane.showMessageDialog(null, "You must create a directory.", "No directory created", JOptionPane.INFORMATION_MESSAGE);
return;
}
boolean answer = ConfirmBox.display("Set Image", "Are you sure you want to backup the images?");
if(answer) {
DBConnection dBC = new DBConnection();
Connection con = dBC.getDBConnection();
String updateStmt = "UPDATE image_address SET image_address = ? WHERE rowid = 2";
try {
PreparedStatement myStmt = con.prepareStatement(updateStmt);
myStmt.setString(1, backupStatus);
myStmt.executeUpdate();
myStmt.close();
String source = imageDirLbl.getText() + "tolmarImages";
File srcDir = new File(source);
String destination = backupStatus + "tolmarImages";
File destDir = new File(destination);
try {
FileUtils.copyDirectory(srcDir, destDir);
JOptionPane.showMessageDialog(null, "Images copied successfully.", "Images copied", JOptionPane.INFORMATION_MESSAGE);
} catch (IOException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

Related

In VS Installer Project, Commit() is not working properly

Using the Visual Studio Installer Project, I included the initial setup project in Install and Commit in Custom Actions that will perform the downloading of the cabinet file under the Windows\Temp\Target Folder folder. Consequently, the zip file will be unzipped.
I used async/await for the first time in DownloadCatalog(), but the zip file wasn't properly downloaded, even though the directory was created. I assumed the installing process stopped the downloading process. I then changed it.
I created the installation file without async. Then I ran it, but the result was the same. This code works fine when running it in an independent project. Do you have any suggestions?
namespace IntialSetupApp
{
[RunInstaller(true)]
public partial class IntialInstallApp : System.Configuration.Install.Installer
{
private readonly string temp = #"C:\Windows\Temp\Target Folder\";
private readonly string zipUrl = #"https://thank.you/so.much";
private readonly string catalog = #"C:\Windows\Temp\Target Folder\whateverXML.xml";
public IntialInstallApp()
{
InitializeComponent();
}
public override void Commit(IDictionary savedState)
{
base.Commit(savedState);
Directory.CreateDirectory(temp);
DownloadCatalog();
}
private Task DownloadCatalog()
{
try
{
string fileName = Path.Combine(temp, "ZippedCab.cab");
Uri uri = new Uri(url);
using (WebClient client = new WebClient())
{
client.DownloadFile(uri, fileName);
}
UnzipFile(fileName);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return Task.FromResult(true);
}
private Task UnzipFile(string filePath)
{
try
{
CabInfo cab = new CabInfo(filePath);
cab.Unpack(temp);
return Task.FromResult(true);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return Task.FromResult(false);
}
}
}
+Update
With the above code, I created the console project independently, and it created the folder and completed downloading the file. Therefore, it seems that installer prevents modifying other folders. Is there any workaround way?
The reason was The request was aborted: Could not create SSL/TLS secure channel., so I updated the code with this. Then it works fine.

codename one image chooser gives wrong path

I want to upload an image with codename one the issue is when i upload it i get the wrong image name and path , let me explain more so this is the code :
imaged.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
Display.getInstance().openImageGallery(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
if (ev != null && ev.getSource() != null) {
String filePath = (String) ev.getSource();
int fileNameIndex = filePath.lastIndexOf("/") +1;
String fileName = filePath.substring(fileNameIndex);
System.out.println("image : "+ fileName);
}
}
});
}
});
c3.add(imaged);
i want to get the image name to insert it into my data base the lint that i gott is :
C:/Users/Emel/AppData/Local/Temp/temp8005230168902905005..png
the image which i'm selecting is hosted on my wamp server under the www folder:
http://localhost/PiWeb1/TeamFlags/es.png
which is wrong even the file name is wrong how can i get the real path and file name!
This is a bit problematic on devices. They are very inconsistent when it comes file system/media so we try to replicate some of those problems in the simulator by copying the selection to the side.
The reason is simple, say you had access to the image directory of the phone you could read and upload all the images without the users consent. So they OS copies an image and gives you access only to that data.
You might have better luck with this on devices, if not you might have better luck with: https://www.codenameone.com/blog/native-file-open-dialogs.html
As a side note your URL won't be an http URL it will be a file URL.

Fetching all Microsoft Active Directory users in Domino Xpages NamePicker via java Agent

I'm working with LDAP Microsoft Active Directory and Domino server and quite new with this.
we've successfully fetched all Microsoft Active Directory users in Domino via java Agent and have printed all the user names in java debug console. For that referred this http://lotus-blogs.blogspot.in/2009/08/ldap-programming-using-domino-java-step.html link.
Now, i want to get all users in Domino Xpages NamePicker, so is this possible to get all users in Xpages NamePicker via java Agent?
As per we see that in Xpages NamePicker, we are able to fetch the Domino Users with the help of java beans.
Any kind of suggestion will be really Appreciated.
My java Agent is like following-
import lotus.domino.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
LDAPQuery.ldapconnect();
} catch(Exception e) {
e.printStackTrace();
}
}
}
AND
import javax.naming.*;
import javax.naming.directory.*;
import java.util.*;
public class LDAPQuery {
public static void ldapconnect(){
String isFound="0";
try {
System.out.println("inside try 1");
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "PROVIDER_URL");
env.put(Context.SECURITY_PRINCIPAL, "UserName");
env.put(Context.SECURITY_CREDENTIALS, "password");
// Create initial context
DirContext ctx = new InitialDirContext(env);
// Specify the ids of the attributes to return
String[] attrIDs = {"cn","mail"};
SearchControls ctls = new SearchControls();
ctls.setReturningAttributes(attrIDs);
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(&(objectCategory=person)(mail=*abc.com))";
System.out.println("filter defined");
// Search for objects that have those matching attributes
NamingEnumeration answer = ctx.search("", filter,ctls);
System.out.println("get the answer!");
try {
System.out.println("inside try2");
while (answer.hasMore())
{
SearchResult sr = (SearchResult)answer.next();
System.out.println("<<" + sr.getName()+">>");
Attributes attrs = sr.getAttributes();
//System.out.println(sr.getName().matches("/^[0-9]/"));
System.out.println(attrs.get("cn").get());
System.out.println(attrs.get("mail").get());
isFound="1";
}
if ( isFound=="1") {
System.out.println("User found in Active Directory!");
} else {
System.out.println("Opps ! User not found in Active Directory!");
}
answer.close();
}catch(PartialResultException e) {
System.out.println("catch 2");
e.printStackTrace();
}
// Close the context when we're done
ctx.close();
} catch (Exception e) {
System.out.println("catch 1");
e.printStackTrace();
}
}
public LDAPQuery() {
// Don't think I'm doing anything here
}
}
OK, got it.
Any particular reason why you are utilizing an Agent as opposed to using a true bean? Calling an agent everytime someone opens the name picker in my opinion is far from being effective.
Apart from that I don't see a way how the results from your agent could directly be passed into the name picker.
Third: looking at your ldap filter I'm sure that your code will return hundreds or even thousands of names. Using a standard ExtLib NamePicker is no fun for your users, believe me: the list of names displayed per dialog page is way too limited. But that may be a different story.
Sticking to the namePicker approach there are several ways how you could achieve what you appear to accomplish:
refactor your java agent into a javaBean then feed the result to the control
consider going for a directory syncing tool like IBM TDI; thus your AD data can be pushed into a Domino directory of your choice, and then from within your application you can utilize standard name lookup features

Can I grab the project output app.config file in the XML file Changes area of InstallShield 2012?

I need to change a couple paths from the debug/testing App.config files to their final home on the end user's machine. I see the XML File Changes option when editing the Installer project through Visual studio, and the help indicates I should Import the xml file to be changed.
BUT...
Is there any way to import the output of the project for the XML file? If I browse directly to the file itself I have to use the Debug or Release config file, which seems like it would be annoying. Otherwise I could use the base App.config but if any transformations are applied when building they'd be lost.
So am I stuck with just browsing to a file, or can I grab the "Project Output" somehow like I can for the .exe file?
XML File Changes is pretty weak tea.
To do what you are looking for your going to have to create a custom action that loads the .config file and updates it outside of InstallShield.
If you are using 2012 C# Wizard project type an option should be to create a .rul that catches the OnEnd() event in After Move Data. From the .rul call into a dll via UseDLL and invoke a method that accepts the target path to the config and the value to update the value to.
The following is code I'm testing so...
Using a C# Wizard project type I added the following InstallScript rule to call into a C# dll:
function OnEnd()
string basePath;
BOOL bResult;
string dllPath;
OBJECT oAppConfig;
begin
dllPath = TARGETDIR ^ APPCONFIG_DLL;
try
set oAppConfig = DotNetCoCreateObject(dllPath, "AppConfig.ConfigMgr", "");
catch
MessageBox("Error Loading" + dllPath + ": " + Err.Description, INFORMATION);
abort;
endcatch;
try
basePath = "C:\\Program Files (x86)\\MyCompany\\Config Test\\";
bResult = oAppConfig.ConfigureSettings(basePath + "appsettings.xml", basePath + "app.config", "someAppSection");
catch
MessageBox("Error calling ConfigureSettings " + dllPath + " " + Err.Number + " " + Err.Description, INFORMATION);
endcatch;
end;
C# test code:
public bool ConfigureSettings(string configFilePath, string targetAppConfigPath, string targetAppName)
{
bool completed = true;
try
{
XmlDocument configFileDoc = new XmlDocument();
configFileDoc.Load(configFilePath);
string installerTargetFileDoc = targetAppConfigPath; // InstallShield's build process for Visual Studio solutions does not rename the app.config file - Awesome!
System.IO.FileInfo fi = new System.IO.FileInfo(installerTargetFileDoc);
if (fi.Exists == false) installerTargetFileDoc = "app.config";
XmlDocument targetAppConfigDoc = new XmlDocument();
targetAppConfigDoc.Load(installerTargetFileDoc);
// ensure all required keys exist in the target .config file
AddRequiredKeys(configFileDoc.SelectSingleNode("configuration/" + targetAppName + "/requiredKeys"), ref targetAppConfigDoc);
// loop through each key in the common section of the configuration file
AddKeyValues(configFileDoc.SelectSingleNode("configuration/common/appSettings"), ref targetAppConfigDoc);
// loop through each key in the app specific section of the configuration file - it will override the standard configuration
AddKeyValues(configFileDoc.SelectSingleNode("configuration/" + targetAppName + "/appSettings"), ref targetAppConfigDoc);
// save it off
targetAppConfigDoc.Save(targetAppConfigPath);
}
catch (Exception ex)
{
completed = false;
throw ex;
}
return completed;
}
private void AddKeyValues(XmlNode configAppNodeSet, ref XmlDocument targetAppConfigDoc)
{
foreach (XmlNode configNode in configAppNodeSet.SelectNodes("add"))
{
XmlNode targetNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings/add[#key='" + configNode.Attributes["key"].Value + "']");
if (targetNode != null)
{
targetNode.Attributes["value"].Value = configNode.Attributes["value"].Value;
}
}
}
private void AddRequiredKeys(XmlNode targetAppNodeSet, ref XmlDocument targetAppConfigDoc)
{
foreach (XmlNode targetNode in targetAppNodeSet.SelectNodes("key"))
{
// add the key if it doesn't already exist
XmlNode appNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings/add[#key='" + targetNode.Attributes["value"].Value + "']");
if (appNode == null)
{
appNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings");
XmlNode newAddNode = targetAppConfigDoc.CreateNode(XmlNodeType.Element, "add", null);
XmlAttribute newAddNodeKey = targetAppConfigDoc.CreateAttribute("key");
newAddNodeKey.Value = targetNode.Attributes["value"].Value;
XmlAttribute newAddNodeValue = targetAppConfigDoc.CreateAttribute("value");
newAddNodeValue.Value = "NotSet";
newAddNode.Attributes.Append(newAddNodeKey);
newAddNode.Attributes.Append(newAddNodeValue);
appNode.AppendChild(newAddNode);
}
}
}
While it seems like it should work, Installshield is unable to grok project output correctly (dependencies are missed often, merge modules are duplicated even when they dont apply), or give you a way to deal with individual files in project output.
I have no less than 5 bugs open with them about problems using project output and their workaround is always "Add the files manually".
If you are just getting started with install shield, I suggest you try another alternative. If you have to use it, either complain about this not working to their support team and use the suggested workaround until they get it together.
This may not be the "answer" to your question, but hopefully helps your sanity when dealing with the broken feature set in this product.
You can import any file you want (by browsing), and make changes to it in any run-time location you like. I suggest just putting the minimal amount you need to make your changes; after all it's the XML File Changes view. That way most updates to the file won't cause or require any changes to your XML File Changes settings, no matter how it's included.

How to use my own sqlite database?

I put my database field in "assets" folder. And use the code from this blog to copy the database to "/data/data/my_packname/databases/", (This copy code i run it in the onCreate() method when i run this app) then use select * from ... to get data. But it gives me the exception: no such table.
Someone told me that if i am attempting to copy the file in SQLiteOpenHelper's onCreate(), it's too late. So the copy file code can not copy the complete file.
So i need to use adb or ddms to pull the database first?
So, Anyone can teach me how to use my own databse?
Can you tell me the setup?
I've used the instructions in that blog post and found them, while on the right track, to severely complicate the issue by unnecessarily extending SQLiteOpenHelper. I've had much better luck doing the following:
Create a utility class that creates the static db by copying it into the correct directory from assets, but doesn't get itself so hung up on following the SQLiteOpenHelper format.
Using the same utility class to open the db by using SQLiteDatabase.openDatabase()
Edit: Here is a version of this utility class I've created; it's not quite complete, but you'll get the drift.
public class DbUtils {
private static final String DB_PATH = "/data/data/com.mypackage.myapp/databases/";
private static final String DB_NAME = "my.db";
public static void createDatabaseIfNotExists(Context context) throws IOException {
boolean createDb = false;
File dbDir = new File(DB_PATH);
File dbFile = new File(DB_PATH + DB_NAME);
if (!dbDir.exists()) {
dbDir.mkdir();
createDb = true;
}
else if (!dbFile.exists()) {
createDb = true;
}
else {
// Check that we have the latest version of the db
boolean doUpgrade = false;
// Insert your own logic here on whether to upgrade the db; I personally
// just store the db version # in a text file, but you can do whatever
// you want. I've tried MD5 hashing the db before, but that takes a while.
// If we are doing an upgrade, basically we just delete the db then
// flip the switch to create a new one
if (doUpgrade) {
dbFile.delete();
createDb = true;
}
}
if (createDb) {
// Open your local db as the input stream
InputStream myInput = context.getAssets().open(DB_NAME);
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(dbFile);
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
}
public static SQLiteDatabase getStaticDb() {
return SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
}
}
After you've copied the database, you should try closing and reopening the SQLiteDatabase object before executing any query on it. I had a similar problem with copying a db from an input stream and that's what solved it for me.
here is my Version from "Silvio Donnini" Code :),
now you can update the Database easily.
private static final String DB_PATH = "/data/data/pakagename/databases/";
private static final String DB_NAME = "databaseName";
private static SQLiteDatabase db;
public static void createDatabaseIfNotExists(Context context,int version) throws IOException {
boolean createDb = false;
File dbDir = new File(DB_PATH);
File dbFile = new File(DB_PATH + DB_NAME);
if (!dbDir.exists()) {
dbDir.mkdir();
createDb = true;
}
else if (!dbFile.exists()) {
createDb = true;
}
else {
// Check that we have the latest version of the db
db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
if (db.getVersion() != version) {
dbFile.delete();
createDb = true;
}
}
if (createDb) {
// Open your local db as the input stream
InputStream myInput = context.getResources().openRawResource(R.raw.database);
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(dbFile);
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
SQLiteDatabase dbwrite = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READWRITE);
dbwrite.setVersion(version);
dbwrite.close();
if (db != null)
db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
}
}
public static SQLiteDatabase getStaticDb() {
if (db != null)
return db;
return SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, null, SQLiteDatabase.OPEN_READONLY);
}
I know this is an old question, but I lost a lot of time figuring it out, with the help of all the replies.
The issue is that a device stores a database in his data/data/.../databases folder. So, when you change sth about the database (name, add android metadata table, size..) it wont make any difference because of the stored database and the method that checked for existing database.
To get the newest database, after changing it, you must run the program without checking for existing databses (e.g. instead of dbExist = checkDataBase(); make it just false).
dbExist = checkDataBase();
Change to:
dbExists = false;
After you picked up the "new" databse you can return to checking the existing ones.
Hope it helps someone,
dina
I know this is an old post, but for those who still get here after a Google or a Bing search, this is the solution to the stated problem:
in createDataBase() there is the following check;
this.getReadableDatabase();
This checks if there is already a database with the provided name and if not creates an empty database such that it can be overwritten with the one in the assets folder. On newer devices this works flawlessly but there are some devices on which this doesn't work. Mainly older devices. I do not know exactly why, but it seems like the getReadableDatabase() function not only gets the database but also opens it. If you then copy the database from the assets folder over it, it still has the pointer to an empty database and you will get table does not exist errors.
So in order to make it work on all devices you should modify it to the following lines:
SQLiteDatabase db = this.getReadableDatabase();
if (db.isOpen()){
db.close();
}
Even if the database is opened in the check, it is closed thereafter and it will not give you any more trouble.
Calm down guys,After long research finally found silly mistake for "no such table" error
Check name of database in Assets folder if it's like "DATABASE_NAME.EXTENSION" then put full name in Helper class with extension its solved my problem.
like say in Assets name of database is login.sqlite or login.db anything. put DB_NAME=login.sqlite fully with extention.
this tutorial now works perfectly.
The way of creating database from article you've posted is slightly diffrent from that how it's done in android examples (I don't want to say if it's good or bad).
I've learned how to use databases from SDKs NotePad sample
It's good example to start from, becouse it covers both database creation topic and database access through ContentProvider (it's really the only good way to get data from db, otherwise you will have problems when trying to get data simultaneusly from many places of your code).
You should note that SQLiteOpenHelper is really powerful and "it will help you" if you will use it properly. For example it stores current database version (not sqlite version but number you assingn with database schema version) and when you create new application version with new database structure you can update current schema to the new version in onUpdate.

Resources