import static com.crawler.constants.CrawlerConstants;
import static com.crawler.constants.CrawlerConstants.CRAWLER4J;
import java.util.Properties;
public final class Configurations {
private static Properties prop = new Properties();
public static String getStringProperty(String key, String defaultValue) {
if (prop == null || prop.getProperty(key) == null) {
return defaultValue;
}
return prop.getProperty(key);
}
public static int getIntProperty(String key, int defaultValue) {
if (prop == null || prop.getProperty(key) == null) {
return defaultValue;
}
return Integer.parseInt(prop.getProperty(key));
}
public static short getShortProperty(String key, short defaultValue) {
if (prop == null || prop.getProperty(key) == null) {
return defaultValue;
}
return Short.parseShort(prop.getProperty(key));
}
public static long getLongProperty(String key, long defaultValue) {
if (prop == null || prop.getProperty(key) == null) {
return defaultValue;
}
return Long.parseLong(prop.getProperty(key));
}
public static boolean getBooleanProperty(String key, boolean defaultValue) {
if (prop == null || prop.getProperty(key) == null) {
return defaultValue;
}
return prop.getProperty(key).toLowerCase().trim().equals("true");
}
static {
try {
prop.load(Configurations.class.getClassLoader()
.getResourceAsStream(CONFIG_DIR + "/" + CRAWLER4J));
} catch (Exception e) {
prop = null;
System.err.println("WARNING: Could not find crawler4j.properties file in class path. I will use the default values.");
}
}
}
In my try loop above it is not loading crawler4j.properties file. As previously it was like this-
try {
prop.load(Configurations.class.getClassLoader()
.getResourceAsStream("crawler4j.properties"));
}
so it was able to load it directly from the src/main/resources folder. But I want to load this crawler4j.properties file kept outside the code in different directory. So I have stored crawler4j.properties file in /my/dir/crawler4j.properties and this is try loop that I want to modify-
try {
prop.load(Configurations.class.getClassLoader()
.getResourceAsStream(CONFIG_DIR + "/" + CRAWLER4J_PROP));
}
And CONFIG_DIR contains \my\dir and CRAWLER4J has crawler4j.properties but somehow it is not loading and it is going to catch exception block. Any suggestions why is it happening.
If you try to load something as a resource, it must be on the classpath--that's the definition of a resource (give or take).
To load it from a filesystem path, use load(InputStream) (or load(Reader)).
It's most likely a misconfigured path, in your catch try appending in your System.err statement:
e.getMessage();
I think you might find you need to escape the "/" so try using "//". I'm not sure if this is the issue but I had it awhile back and was pulling my hair out trying to figure out why it worked some places and not others.
So, what kind of exception do you get? FileNotFound? Is this a part of web app or regular java application?
Make sure you have read rights to read the properties file in the directory.
Edit:
getResourceAsStream returns null if it doesn't find the resource, so as suggested by others:
1. Make sure the properties file is on the classpath.
2. Escape the / -
prop.load(Configurations.class.getClassLoader()
.getResourceAsStream(CONFIG_DIR + "//" + CRAWLER4J_PROP));
Related
I have this snippet of code:
if (configURI == null) {
if (jfwConfigLocator != null) {
jfwConfigLocator.deduceLocationFromEnvironment();
LOG.info("Using configuration files at URI {}", jfwConfigLocator.getConfigURI());
LOG.info("Using configuration for suite {}", jfwConfigLocator.getSuite());
setSuite(jfwConfigLocator.getSuite());
setRole(jfwConfigLocator.getRole());
String configUri = jfwConfigLocator.getConfigURI();
String cleanUri = JfwPropertyLoader.sanitizeUri(configUri);
URL url = new URL(cleanUri); // <= Fortify complaint
setConfigURL(url);
String passwordsKeyUri = jfwConfigLocator.getPasswordsKeyURI();
if (passwordsKeyUri != null) {
cleanUri = JfwPropertyLoader.sanitizeUri(passwordsKeyUri);
setPasswordsKeyURL(new URL(cleanUri));
}
String passwordsUri = jfwConfigLocator.getPasswordsURI();
if (passwordsUri != null) {
setPasswordsURL(new URL(jfwConfigLocator.getPasswordsURI()));
}
}
}
Fortify is telling me that attackers are able to control the resource identifier argument to URL() at snippet.java right before setConfigURL(...) call, which could enable them to access or modify otherwise protected system resources.
as you can see I already added a call to sanitize the Uri, as a private method in the class, the methods was taken from www.java2s.com and it's this snippet of code:
private static String sanitizeUri(String uri) {
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() - 1);
}/*from ww w . j a v a 2 s. co m*/
return uri.replaceAll("//", "/");
}
I do not know what else to do in order for this issue to go away.
any help is greatly appreciated.
Following function is used to delete empty directories inside backup folder. But problem with this method is it deletes backup folder as well if it is empty.
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
if(folder.listFiles().length == 0){
folder.delete();
}else {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if(fileEntry.listFiles().length == 0){
fileEntry.delete();
}
}
}
}
}
Assuming my folder structure is as follows,
backup
-2019
-10
-15
-2020
If I call method as deleteEmptyDirectoriesOfFolder(backup) it deletes backup folder as well. Any suggestions to fix it without including a second parameter to the method?
Your so close, just break it in two methods:
deleteEmptySubDirectoriesOfFolder-Calls current method for all subdirectories
deleteEmptyDirectoriesOfFolder-Your current method.
Here is the new method:
public static void
deleteEmptySubDirectoriesOfFolder(final File folder)
{
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if(fileEntry.listFiles().length == 0){
fileEntry.delete();
}
}
}
}
Have a wrapper class around File as below
class FileWrapper {
private File folder;
private boolean isRoot;
}
when you call deleteEmptyDirectoriesOfFolder for the first time, initialize FileWrapper as
File folder = new File("<backup_dir_path>");
FileWrapper fileWrapper = new FileWrapper(folder, true);
deleteEmptyDirectoriesOfFolder(fileWrapper);
then slightly change deleteEmptyDirectoriesOfFolder method as
public static void deleteEmptyDirectoriesOfFolder(final FileWrapper fileWrapper) {
if(fileWrapper.getFolder().listFiles().length == 0 && !fileWrapper.getIsRoot()){
fileWrapper.getFolder().delete();
}else {
for (final File fileEntry : fileWrapper.getFolder().listFiles()) {
if (fileEntry.isDirectory()) {
FileWrapper fileWrapper = new FileWrapper(fileEntry, false);
deleteEmptyDirectoriesOfFolder(fileWrapper);
if(fileEntry.listFiles().length == 0){
fileEntry.delete();
}
}
}
}
}
Actually...I'm very surprised that you don't ever get a NullPointerException. I think you should. Based on the directory structure example you provided, I interpret the tree to be:
- backup
- 2019
- 10
- 15
- 2020
As your for loop within the deleteEmptyDirectoriesOfFolder() method iterates through the folders it does a recursive call against any sub-directory determined by
fileEntry.isDirectory(). A recursive call eventually gets to the sub-directory named 15 in which case a final recursive call is made. Upon that final recursive call the condition for the if statement above the for loop
if (folder.listFiles().length == 0) {
folder.delete();
}
becomes true and ultimately the sub-directory is deleted and the recursive call is returned to the previous recursive call except now, because the folder (15) is deleted fileEntry.listFiles() becomes null hence when checking for fileEntry.listFiles() again (within the for loop under the recursive call):
deleteEmptyDirectoriesOfFolder(fileEntry);
if (fileEntry.listFiles().length == 0) { // HERE
fileEntry.delete();
}
a NullPointerException should be thrown. You want to ignore the ones that are null so, you should perhaps check to see if fileEntry.listFiles() is null before attempting to play on it, like this:
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
if (folder.listFiles().length == 0) {
folder.delete();
}
else {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if (fileEntry.listFiles() != null && fileEntry.listFiles().length == 0) {
fileEntry.delete();
}
}
}
}
}
If you don't want to also delete the backup folder if it is empty then just use the for loop (the backup directory should remain):
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
deleteEmptyDirectoriesOfFolder(fileEntry);
if (fileEntry.listFiles() != null && fileEntry.listFiles().length == 0) {
fileEntry.delete();
}
}
}
}
Your method should now function properly.
Here is my solution after going through other answers,
public static void deleteEmptyDirectoriesOfFolder(final File folder) {
deleteEmptyDirectoriesOfFolder(folder, true);
}
private static void deleteEmptyDirectoriesOfFolder(final File folder, boolean isRoot) {
if(!isRoot && folder.listFiles().length == 0){
folder.delete();
}else {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
File parent = fileEntry.getParentFile();
deleteEmptyDirectoriesOfFolder(fileEntry,false);
if(!isRoot && parent != null && parent.listFiles().length == 0){
parent.delete();
}
}
}
}
}
How can I throw an Exception when a properties file contains a duplicate property?
Here is an example demonstrating this situation:
# Properties-file
directory=D:\\media\\D-Downloads\\Errorfile\\TEST_A
directory=D:\\media\\D-Downloads\\Errorfile\\TEST_B
#directory=D:\\media\\D-Downloads\\Errorfile\\TEST_C
I suppose you are reading the file with something like Properties.load(). It sets the parameter internally using put(key, value). You can override that method to get the desired behaviour like e.g.
new Properties() {
#Override
public synchronized Object put(Object key, Object value) {
if (get(key) != null) {
throw new IllegalArgumentException(key + " already present.");
}
return super.put(key, value);
}
}.load(...);
EDIT:
Integrating this into the OP's code:
File propertiesFile = new File("D:/media/myProperties.properties");
Properties properties = new Properties() {
#Override
public synchronized Object put(Object key, Object value) {
if (get(key) != null) {
// or some other RuntimeException you like better...
throw new IllegalArgumentException(key + " already present.");
}
return super.put(key, value);
}
}
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(propertiesFile))) {
properties.load(bis);
} catch (IllegalArgumentException ex) {
//
}
By the way, why would you want to catch the exception? I'd not continue a program if its configuration is corrupt (maybe catching at top-level to log the event). But exception-handling is a different topic...
(EDIT: my original code samles didn't compile, I corrected them)
As mentioned here Tool to find duplicate keys and value in properties file
"
There are two nice tools that I use
unival npm package: this is a command line tool to detect duplicate keys, values or lines.
npm command to install the package: npm i unival
Link: https://www.npmjs.com/package/unival
unival extension: if you use vscode, this is a extremely helpful extension to detect duplicates on the fly.
"
The best way is to have a test to run unival command, this will prevent duplicate values going to properties file
Here is how I am loading the properties:
File propertiesFile = new File("D:/media/myProperties.properties");
Properties properties = new Properties();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(propertiesFile))) {
properties.load(bis);
} catch (Exception ex) {
//
}
#Ralf How can I adapt your code?
The Ralf Kleberhoff answer is correct;
however, I would not use an anonymous class.
It seems likely that you want to use this functionality more than once,
so I would create a class that extends Properties and override the put as did Ralf
Note that the put method is from the Hashtable class which Properties extends.
Here is an example (I didn't try to compile it):
public class UniqueProperties extends Properties
{
#Override
public synchronized String put(Object key, Object value)
{
if (get(key) != null)
{
throw new IllegalArgumentException(key + " already present.");
}
super.put(key, value);
}
}
I've been working on a plugin that requires a fair amount of data being stored.
I have it being stored in a custom config file I found online that works basically the same as the default config.
The problem I'm having is that I am not sure how to actually close the file or if I even need to, as I know little about yaml configurations.
The code for the template I used is below.
I'm also curious as to advice on how I should store larger amounts of data in the future.
public class CustomConfig {
//store name of file to load/edit
private final String fileName;
//store plugin, to get file directory
private final JavaPlugin plugin;
//store actual hard disk file location
private File configFile;
//store ram file copy location
private FileConfiguration fileConfiguration;
//constructor taking a plugin and filename
public CustomConfig(JavaPlugin plugin, String fileName) {
//ensure plugin exists to get folder path
if (plugin == null)
throw new IllegalArgumentException("plugin cannot be null");
//set this classes plugin variable to the one passed to this method
this.plugin = plugin;
//get name of file to load/edit
this.fileName = fileName;
//get directory/folder of file to load/edit
File dataFolder = plugin.getDataFolder();
if (dataFolder == null)
throw new IllegalStateException();
//load config file from hard disk
this.configFile = new File(plugin.getDataFolder(), fileName);
reloadConfig();
}
public void reloadConfig() {
//load memory file from the hard copy
fileConfiguration = YamlConfiguration.loadConfiguration(configFile);
// Look for defaults in the jar
File configFile = new File(plugin.getDataFolder(), fileName);
if (configFile != null) {
YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(configFile);
fileConfiguration.setDefaults(defConfig);
}
}
public FileConfiguration getConfig() {
if (fileConfiguration == null) {
this.reloadConfig();
}
return fileConfiguration;
}
public void saveConfig() {
if (fileConfiguration == null || configFile == null) {
return;
} else {
try {
getConfig().save(configFile);
} catch (IOException ex) {
plugin.getLogger().log(Level.SEVERE, "Could not save config to " + configFile, ex);
}
}
}
public void saveDefaultConfig() {
if (!configFile.exists()) {
this.plugin.saveResource(fileName, false);
}
}
}
No. You do not have to close YamlConfiguration objects.
While the default config (JavaPlugin.getConfig()) is bound to the lifecycle of the plugin, custom ones are disposed when any other Java object is, i.e. when the garbage collector determines that there are no more references pointing to them in the code.
You don't need to close the config. It's not a BufferedWriter. The config keeps all of the data in the memory until the server shuts down. This means that if you change something in the config during the time your plugin is enabled, you will need to use your reloadConfig() method. The only clean up you need to do after using the FileConfiguration#set(String, Object) method is to use FileConfiguration#saveConfig() to tell Bukkit to take the current state of your config and copy it into your config file.
I got another JCo-related question and hopefully finding help.
With JCo you can easily build up a connection like it is explained in the example sheets which came with the JCo-library. Unfortunately, the only way building a connection is handled with a created property file. It wouldn´t be that bad, if there wasn´t any sensible data in it. But at least, the password for the SAP user stands in the file, so it is a lack of safety in this way of connection-handling. The manual of JCo says so, too :
"For this example the destination configuration is stored in a file that is called by the program. In practice you should avoid this for security reasons."
but couldn´t find a working solution after all. There are a palmful threads about this theme, like this
http://forums.sdn.sap.com/thread.jspa?messageID=7303957
but none of them are helpful. I really can´t figure out a solution and neither find one. Actually I solved the security-problem with deleting the file after building the connection, but this is not a satisfying solution. There have to be a better way getting the parameter for the connection, especially when it stands in the manual, but I have no glue how.
Anybody already worked with JCo 3.0 and knows this problem?
Yes, that's possible. You have to create your own implementation of DestinationDataProvider and register it using Environment.registerDestinationDataProvider(). However your DDP obtains the connection data and credentials is up to you. Take a look at net.sf.rcer.conn.connections.ConnectionManager, there's a working example in there.
You need to
copy the private class starting on line 66 and adapt it to your own needs (that is, fetch the connection data from wherever you want to)
perform the registration (line 204) somewhere during the startup of your application
get the connection using some string identifier that will be passed to your DestinationDataProvider.
It's a bit confusing, it was dificult to me how to figure this too.
All you need is an object of type java.util.Properties to fill the desired fields, but it's up to ou how to fill this object.
I dit it through a ValueObject, I can fill this VO from a file, database, web form...
JCOProvider jcoProvider = null;
SAPVO sap = new SAPVO(); // Value Object
Properties properties = new Properties();
if(jcoProvider == null) {
// Get SAP config from DB
try {
sap = SAPDAO.getSAPConfig(); // DAO object that gets conn data from DB
} catch (Exception ex) {
throw new ConexionSAPException(ex.getMessage());
}
// Create new conn
jcoProvider = new JCOProvider();
}
properties.setProperty(DestinationDataProvider.JCO_ASHOST, sap.getJCO_ASHOST());
properties.setProperty(DestinationDataProvider.JCO_SYSNR, sap.getJCO_SYSNR());
properties.setProperty(DestinationDataProvider.JCO_CLIENT, sap.getJCO_CLIENT());
properties.setProperty(DestinationDataProvider.JCO_USER, sap.getJCO_USER());
properties.setProperty(DestinationDataProvider.JCO_PASSWD, sap.getJCO_PASSWD());
properties.setProperty(DestinationDataProvider.JCO_LANG, sap.getJCO_LANG());
// properties.setProperty(DestinationDataProvider.JCO_TRACE, "10");
try {
jcoProvider.changePropertiesForABAP_AS(properties);
} catch (Exception e) {
throw new ConexionSAPException(e.getMessage());
}
The JCOProvider class:
import com.sap.conn.jco.ext.DestinationDataEventListener;
import com.sap.conn.jco.ext.DestinationDataProvider;
import com.sap.conn.jco.ext.Environment;
import es.grupotec.ejb.util.ConexionSAPException;
import java.util.Properties;
public class JCOProvider implements DestinationDataProvider {
private String SAP_SERVER = "SAPSERVER";
private DestinationDataEventListener eventListener;
private Properties ABAP_AS_properties;
public JCOProvider() {
}
#Override
public Properties getDestinationProperties(String name) {
if (name.equals(SAP_SERVER) && ABAP_AS_properties != null) {
return ABAP_AS_properties;
} else {
return null;
}
// if(ABAP_AS_properties!=null) return ABAP_AS_properties;
// else throw new RuntimeException("Destination " + name + " is not available");
}
#Override
public boolean supportsEvents() {
return true;
}
#Override
public void setDestinationDataEventListener(DestinationDataEventListener eventListener) {
this.eventListener = eventListener;
}
public void changePropertiesForABAP_AS(Properties properties) throws ConexionSAPException {
try {
if (!Environment.isDestinationDataProviderRegistered()) {
if (ABAP_AS_properties == null) {
ABAP_AS_properties = properties;
}
Environment.registerDestinationDataProvider(this);
}
if (properties == null) {
if (eventListener != null) {
eventListener.deleted(SAP_SERVER);
}
ABAP_AS_properties = null;
} else {
ABAP_AS_properties = properties;
if (eventListener != null) {
eventListener.updated(SAP_SERVER);
}
}
} catch (Exception ex) {
throw new ConexionSAPException(ex.getMessage());
}
}
}
Regards