Common configuration 2 - commented properties - java

i'm developing a java desktop application to use as a tool to manipulate properties files.
So my application need to to load a TXT file containing several keys (or properties), and be able to changes there values.
I use Apache commons configurations 2 project to do this work.
Everything was going well until a face this situation..
there is a txt file contating several properties but, one properties (or key) has a # before his name (look at config.txt file below), so apache commons do not recognize this propertie.
When i set a value to this propertie (look at last two lines on main method), apache commons configurator creates a new line on config.txt
This is not good to me, because i need to preserve the original config.txt format, so if i need to set a value to fileDb propertie, my expected behavior is to remove the # from fileDb name and do not create a new fileDb propertie on config.txt.
the program that uses this configuration file (config.txt) understands that if the property is commented (if it has "#" in its name), it means that it should not be used, but if it is uncommented (without "#" in the name) means that it should be used and that its value should be read.
So what can i do to add or remove "#" from the propertie name using common configuration? if is not possible to do it with commons configurator, how to do it?
On the ConfigTest class i show how the problem ocours.
Before run the code, the file config.txt has a commented propertie named fileDB
#fileDb = C:/test/test.db
the maind method try to change the filedb value to "C://aa//bb//cc"
but after the executions end wil appears a new propetie with the same name "fileDb" but uncomented (without "#"). At the end, config.txt wil have two fileDb propertie, one with "#" and other without "#"
#fileDb = C:/test/test.db
fileDb = C://aa//bb//cc
My expectd behavior after the code execution is to has only one fileDb propetie
fileDb = C://aa//bb//cc
After be able to uncoment this propertie i expect to be able to comment again if necessery (if user wish to do it on my app).
ConfigTest class
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.FileBasedConfiguration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.FileBasedBuilderParameters;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.ex.ConfigurationException;
import java.io.File;
public class ConfigTest {
private Configuration localConfiguration;
private FileBasedConfigurationBuilder<FileBasedConfiguration> fileBuilder;
private ConfigTest() throws ConfigurationException {
this.loadPropertiesFile();
}
private void loadPropertiesFile() throws ConfigurationException {
File file = new File("config.txt");
FileBasedBuilderParameters fb = new Parameters().fileBased();
fb.setFile(file);
fileBuilder = new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class);
fileBuilder.configure(fb);
localConfiguration = fileBuilder.getConfiguration();
}
public boolean saveModifications(){
try {
fileBuilder.save();
return true;
} catch (ConfigurationException e) {
e.printStackTrace();
return false;
}
}
public void setProperty(String key, String value){
localConfiguration.setProperty(key,value);
}
public static void main(String[] args) throws ConfigurationException {
ConfigTest test = new ConfigTest();
//change outputOnSSD propertie value to false
test.setProperty("outputOnSSD", "false");
//here when i set a new value to fileDb propertie, a new line on config.txt with a new fileDb propertie name is created
//the question is: how to remove # from fileDb propetie name on config.txt to commons config recognize it as a existent propertie?
test.setProperty("fileDb", "C://aa//bb//cc");
test.saveModifications();
}
}
File "config.txt" used by ConfigTest class to change his value
########################################################################
# Local environment configuration
########################################################################
# Defines program localization/language
locale = pt-BR
# Temporary directory for processing: "default" uses the system temporary folder.
indexTemp = /home/downloads
# Enable if is on a SSD disk.
indexTempOnSSD = true
# Enable if output/case folder is on SSD. If enabled, index is created directly in case folder,
outputOnSSD = false
# Number of processing threads/workers: "default" uses the number of CPU logical cores.
numThreads = 14
# Full path for hash index database.
#fileDb = C:/test/test.db

Related

Modifying of the Mwe2 workflow generated by Xtext programmatically

I'm running Mwe2 workflow programmatically and I need to add referencedResource for the Terminals.xtext to the GenerateYourDsl.mwe2 file in order to run this workflow successfully. Mentioned GenerateYourDsl.mwe2 file is generated by Xtext when I create new project - I didn't modify it.
Is it somehow possible to get object out of this workflow, access it in Java and add this one attribute to the language attribute of the component attribute of the workflow ?
Here's the workflow:
Workflow {
component = XtextGenerator {
configuration = {
project = StandardProjectConfig {
baseName = "org.example.yourdsl"
rootPath = rootPath
eclipsePlugin = {
enabled = true
}
createEclipseMetaData = true
}
code = {
encoding = "UTF-8"
lineDelimiter = "\n"
fileHeader = "/*\n * generated by Xtext \${version}\n */"
}
}
language = StandardLanguage {
name = "org.example.yourdsl.YourDsl"
fileExtensions = "yourdsl"
//following line needs to be added - in original generated workflow it is not
referencedResource = "platform:/resource/org.eclipse.xtext/org/eclipse/xtext/common/Terminals.xtext"
serializer = {
generateStub = false
}
validator = {
// composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
// Generates checks for #Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage
generateDeprecationValidation = true
}
}
}
}
I'm generating projects programmatically (using CliProjectsCreator and WizardConfiguration) and need to run the workflow when the projects are generated in order to generate src, src-gen files etc. But as I'm trying to run it programmatically (not in Eclipse) and Terminals are used in my grammar, I'm getting this error:
XtextLinkingDiagnostic: null:1 Couldn't resolve reference to Grammar 'org.eclipse.xtext.common.Terminals'.
TransformationDiagnostic: null:36 Cannot create datatype WS. If this is supposed to return EString, make sure you have imported 'http://www.eclipse.org/emf/2002/Ecore' (ErrorCode: NoSuchTypeAvailable)
TransformationDiagnostic: null:39 Cannot create datatype NAME_TERMINAL. If this is supposed to return EString, make sure you have imported 'http://www.eclipse.org/emf/2002/Ecore' (ErrorCode: NoSuchTypeAvailable)
TransformationDiagnostic: null:42 Cannot create datatype VALUE_TERMINAL. If this is supposed to return EString, make sure you have imported 'http://www.eclipse.org/emf/2002/Ecore' (ErrorCode: NoSuchTypeAvailable)
there should be no need to add the terminals grammar explicitely. It should be found on the classpath via org.eclipse.xtext.resource.ClassloaderClasspathUriResolver.resolve(Object, URI) if the workflow is called with a proper classpath.
have a look what the wizard creates when selecting maven: a call to the maven exec plugin calling into Mwe2Launcher main with the proper classpath

compile and execute java program with external jar file

I understand this has been asked for multiple times, but I am really stuck here and if it is fairly easy, please help me.
I have a sample java program and a jar file.
Here is what is inside of the java program (WriterSample.java).
// (c) Copyright 2014. TIBCO Software Inc. All rights reserved.
package com.spotfire.samples;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Random;
import com.spotfire.sbdf.BinaryWriter;
import com.spotfire.sbdf.ColumnMetadata;
import com.spotfire.sbdf.FileHeader;
import com.spotfire.sbdf.TableMetadata;
import com.spotfire.sbdf.TableMetadataBuilder;
import com.spotfire.sbdf.TableWriter;
import com.spotfire.sbdf.ValueType;
/**
* This example is a simple command line tool that writes a simple SBDF file
* with random data.
*/
public class WriterSample {
public static void main(String[] args) throws IOException {
// The command line application requires one argument which is supposed to be
// the name of the SBDF file to write.
if (args.length != 1)
{
System.out.println("Syntax: WriterSample output.sbdf");
return;
}
String outputFile = args[0];
// First we just open the file as usual and then we need to wrap the stream
// in a binary writer.
OutputStream outputStream = new FileOutputStream(outputFile);
BinaryWriter writer = new BinaryWriter(outputStream);
// When writing an SBDF file you first need to write the file header.
FileHeader.writeCurrentVersion(writer);
// The second part of the SBDF file is the metadata, in order to create
// the table metadata we need to use the builder class.
TableMetadataBuilder tableMetadataBuilder = new TableMetadataBuilder();
// The table can have metadata properties defined. Here we add a custom
// property indicating the producer of the file. This will be imported as
// a table property in Spotfire.
tableMetadataBuilder.addProperty("GeneratedBy", "WriterSample.exe");
// All columns in the table needs to be defined and added to the metadata builder,
// the required information is the name of the column and the data type.
ColumnMetadata col1 = new ColumnMetadata("Category", ValueType.STRING);
tableMetadataBuilder.addColumn(col1);
// Similar to tables, columns can also have metadata properties defined. Here
// we add another custom property. This will be imported as a column property
// in Spotfire.
col1.addProperty("SampleProperty", "col1");
ColumnMetadata col2 = new ColumnMetadata("Value", ValueType.DOUBLE);
tableMetadataBuilder.addColumn(col2);
col2.addProperty("SampleProperty", "col2");
ColumnMetadata col3 = new ColumnMetadata("TimeStamp", ValueType.DATETIME);
tableMetadataBuilder.addColumn(col3);
col3.addProperty("SampleProperty", "col3");
// We need to call the build function in order to get an object that we can
// write to the file.
TableMetadata tableMetadata = tableMetadataBuilder.build();
tableMetadata.write(writer);
int rowCount = 10000;
Random random = new Random();
// Now that we have written all the metadata we can start writing the actual data.
// Here we use a TableWriter to write the data, remember to close the table writer
// otherwise you will not generate a correct SBDF file.
TableWriter tableWriter = new TableWriter(writer, tableMetadata);
for (int i = 0; i < rowCount; ++i) {
// You need to perform one addValue call for each column, for each row in the
// same order as you added the columns to the table metadata object.
// In this example we just generate some random values of the appropriate types.
// Here we write the first string column.
String[] col1Values = new String[] {"A", "B", "C", "D", "E"};
tableWriter.addValue(col1Values[random.nextInt(5)]);
// Next we write the second double column.
double doubleValue = random.nextDouble();
if (doubleValue < 0.5) {
// Note that if you want to write a null value you shouldn't send null to
// addValue, instead you should use theInvalidValue property of the columns
// ValueType.
tableWriter.addValue(ValueType.DOUBLE.getInvalidValue());
} else {
tableWriter.addValue(random.nextDouble());
}
// And finally the third date time column.
tableWriter.addValue(new Date());
}
// Finally we need to close the file and write the end of table marker.
tableWriter.writeEndOfTable();
writer.close();
outputStream.close();
System.out.print("Wrote file: ");
System.out.println(outputFile);
}
}
The jar file is sbdf.jar, which is in the same directory as the java file.
I can now compile with:
javac -cp "sbdf.jar" WriterSample.java
This will generate a WriterSample.class file.
The problem is that when I try to execute the program by
java -cp .:./sbdf.jar WriterSample
I got an error message:
Error: Could not find or load main class WriterSample
What should I do? Thanks!
You should use the fully qualified name of the WriterSample, which is com.spotfire.samples.WriterSample and the correct java command is:
java -cp .:././sbdf.jar com.spotfire.samples.WriterSample

Add Timestamp Variable to Folder Path Value in Application Properties

So I need to set a folder path name value in the app.properties file. I also want to name it after the current timestamp so that when it's used to create a file it'll also create the folder. What I current have doesn't work.
screenshot.events = STARTED,SUCCEEDED,FAILED,STEP
screenshot.path = C:/Automation/${timestamp}
webdriver.type=CHROME
Here's 3 options:
1. At startup
You can define the required SystemProperty when launching your Spring Boot Application:
public static void main(String[] args) {
System.setProperty("timestamp",String.valueOf(System.currentTimeMillis()));
new SpringApplicationBuilder() //
.sources(Launcher.class)//
.run(args);
}
Then, define your property in application.properties just the way you did:
screenshot.path = C:/Automation/${timestamp}
2. At Injection
#Value("${screenshot.path}")
public void setScreenshotPath(String screenshotPath) {
this.screenshotPath =
screenshotPath.replace("${timestamp}", System.currentTimeMillis());
}
3. At usage - dynamic timestamps at execution
#Value("${screenshot.path}")
private String screenshotPath;
...
new File(screenshotPath.replace("${timestamp}", System.currentTimeMillis());
//or the following without the need for ${timestamp} in screenshot.path
//new File(screenshotPath + System.currentTimeMillis());
I would simplify it. Just define only root path in application.properties:
screenshot.root.path = C:/Automation/
And append timestamp path part programmatically when you are saving Selenium screenshot.

How to pass a file as parameter in mapreduce

I want to search for particular words in a file and display its count. When the word to be searched is a single word, I am able to do it by setting the configuration in the driver like below :
Driver class :
Configuration conf = new Configuration();
conf.set("wordtosearch", "fun");
Mapper class :
public static class SearchMapper extends
Mapper<LongWritable, Text, Text, IntWritable> {
// Map code goes here.
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map (LongWritable Key, Text value,Context context )throws IOException,InterruptedException{
Configuration conf = context.getConfiguration();
//retrieve the wordToSearch variable
String wordToSearch = conf.get("wordtosearch");
String txt= value.toString();
if(txt.compareTo(wordToSearch)==0){
word = context.getCurrentValue();
context.getCurrentKey();
word.set(txt);
context.write(word, one);
}
But when there is a list of words in a file, I dont know how to pass it. Some posts refers to use distributed cache but while doing that I am getting "distributed cache is deprecated" error. Are there any similar methods in the new api to pass the file ?
Yes, there is also a way in the new API.
First, store the file in HDFS. Then, in the Driver class (in the main method), do the following:
Configuration conf = getConf();
...
Job job = Job.getInstance(conf); ...
job.addCacheFile(new Path(filename).toUri());
Finally, in the mapper class (for instance in the setup() method), do the following:
URI[] localPaths = context.getCacheFiles();
If you have a single file, it should be stored in localPaths[0].
You can try this:judge the parameter wether is a file, then according to the type of parameter execute the operation respectively
If the list of words has a reasonable size, you can still pass it to the configuration:
Driver class: read the file
Driver class: add the list of words in the configuration, doing for instance conf.set("wordListToSearch", "fun:foo:bar"
Mapper class: read the configuration and retrieve your list of words

How do you escape colon (:) in Properties file?

I am using a properties file to store my application's configuration values.
In one of the instances, I have to store a value as
xxx:yyy:zzz. When I do that, the colon is escaped with a back slash\ resulting in the value showing as xxx\:yyy\:zzz in the properties file.
I am aware that the colon : is a standard delimiter of the Properties Java class. However I still need to save the value without the back slash \.
Any suggestions on how to handle this?
Put the properties into the Properties object and save it using a store(...) method. The method will perform any escaping required. The Java documentation says:
"... For the key, all space characters are written with a preceding \ character. For the element, leading space characters, but not embedded or trailing space characters, are written with a preceding \ character. The key and element characters #, !, =, and : are written with a preceding backslash to ensure that they are properly loaded."
You only need to manually escape characters if you are creating / writing the file by hand.
Conversely, if you want the file to contain unescaped colon characters, you are out of luck. Such a file is malformed and probably won't load properly using the Properties.load(...) methods. If you go down this route, you'll need to implement your own custom load and/or store methods.
I came across the same issue. Forward slashes / also get escaped by the store() method in Properties.
I solved this issue by creating my own CustomProperties class (extending java.util.Properties) and commenting out the call to saveConvert() in the customStore0() method.
Here is my CustomProperties class:
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
public class CustomProperties extends Properties {
private static final long serialVersionUID = 1L;
#Override
public void store(OutputStream out, String comments) throws IOException {
customStore0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
comments, true);
}
//Override to stop '/' or ':' chars from being replaced by not called
//saveConvert(key, true, escUnicode)
private void customStore0(BufferedWriter bw, String comments, boolean escUnicode)
throws IOException {
bw.write("#" + new Date().toString());
bw.newLine();
synchronized (this) {
for (Enumeration e = keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
String val = (String) get(key);
// Commented out to stop '/' or ':' chars being replaced
//key = saveConvert(key, true, escUnicode);
//val = saveConvert(val, false, escUnicode);
bw.write(key + "=" + val);
bw.newLine();
}
}
bw.flush();
}
}
We hit this question a couple of days ago. We were manipulating existing properties files with URLs as values.
It's risky but if your property values are less than 40 characters then you can use the "list" method instead of "store":
http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#list(java.io.PrintWriter)
We had a quick look at the JDK code and hacked out a custom implementation of store that works for our purposes:
public void store(Properties props, String propertyFilePath) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(propertyFilePath);
for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
String key = (String) e.nextElement();
pw.println(key + "=" + props.getProperty(key));
}
pw.close();
}
If you use the xml variant of the properties file (using loadFromXML and storeToXML) this shouldn't be a problem.
Try using unicode.
The unicode for a colon is\u003A
Additionally the unicode for a space is: \u0020
For a list of basic Latin characters see: https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)
For example:
ProperName\u003A\NameContinues=Some property value
Will expect a property with a key:
ProperName:NameContinues
And will have a value of:
Some property value
For me it worked by using \ before special character,
e.g,
Before: VCS\u003aIC\u0020Server\u003a=Migration
After: VCS\:IC\ Server\:=Migration
: is escaped with \: and (space) with \ (\ followed by <Space>).
For more info : https://en.wikipedia.org/wiki/.properties
For people like me that get here for this when using Spring Boot configuration properties files: You need to enclose in [..]:
E.g.:
my.test\:key=value
is not enough, you need this in your application.properties for example:
my.[test\:key]=value
See also SpringBoot2 ConfigurationProperties removes colon from yaml keys
Its simple,
just use Apostrophe ' ' over there
E.g.:
Instead of this(case 1)
File file= new File("f:\\properties\\gog\\esave\\apple");
prop.setProperty("basedir",file.toString());
Use this(case 2)
File file= new File("f':'\\properties\\gog\\esave\\apple");
prop.setProperty("basedir",file.toString());
Output will be
Case 1: basedir = f\:\\properties\\gog\\esave\\apple
Case 2: basedir = f:\\properties\\gog\\esave\\apple
I hope this will help you

Categories