Merge properties into a ResourceBundle from System.getProperties() - java

I'm building a ResourceBundle from a file, this bundle holds < String, String> values.
InputStream in = getClass().getResourceAsStream("SQL.properties");
properties = new PropertyResourceBundle(in);
in.close();
I would like to add/replace on this bundle some properties that I'm passing from the command line using -Dsome.option.val.NAME1=HiEarth
I don't care dumping the old bundle and creating a new one instead.
Could you please tip?
I think that what I need to do is :
Create from the bundle a HashMap< String, String>
Replace values.
Transform the HashMap into a InputStream. //This is the complicated part...
Build the new bundle from that.

This does some of what you want (converts the System.properties to a ResourceBundle). Better error handling is left up to you :-)
public static ResourceBundle createBundle()
{
final ResourceBundle bundle;
final Properties properties;
final CharArrayWriter charWriter;
final PrintWriter printWriter;
final CharArrayReader charReader;
charWriter = new CharArrayWriter();
printWriter = new PrintWriter(charWriter);
properties = System.getProperties();
properties.list(printWriter);
charReader = new CharArrayReader(charWriter.toCharArray());
try
{
bundle = new PropertyResourceBundle(charReader);
return (bundle);
}
catch(final IOException ex)
{
// cannot happen
ex.printStackTrace();
}
throw new Error();
}

This might not be the best way to do it but it's the best I can think of: implement a subclass of ResourceBundle that stores the properties you want to add/replace, then set the parent of that bundle to be the PropertyResourceBundle you load from the input stream.
InputStream in = getClass().getResourceAsStream("SQL.properties");
properties = new PropertyResourceBundle(in);
in.close();
MyCLIResourceBundle b = new MyCLIResourceBundle(properties);
// use b as your bundle
where the implementation would be something like
public class MyCLIResourceBundle extends ResourceBundle {
public MyCLIResourceBundle(ResourceBundle parent) {
super();
this.setParent(parent);
// go on and load your chosen properties from System.getProperties() or wherever
}
}

Related

Config-file for JavaFX-Project

I would like to add a file or class to my JavaFX project that only contains the configuration data of the project, e.g. the access data for the database, system paths etc. How would you do this?
Just write everything in a normal class? There is definitely a better way, right?
You're right, of course I'll be happy to do that.
First I created a property file in the project folder and call it app.properties:
db_url=jdbc:mysql://localhost:3306/db name
db_user=user name
db_pwd=secret password
instructions_folder=/home/username/documents/
Then I created a class that loads the properties and makes them available throughout the project.
public class AppProperties {
// FILENAME = Path to properties-file
// Store and protect it where ever you want
private final String FILENAME = "app.properties";
private static final AppProperties config_file = new AppProperties();
private Properties prop = new Properties();
private String msg = "";
private AppProperties(){
InputStream input = null;
try{
input = new FileInputStream(FILENAME);
// Load a properties
prop.load(input);
}catch(IOException ex){
msg = "Can't find/open property file";
ex.printStackTrace();
}finally{
if (input != null){
try{
input.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
public String getProperty (String key){
return prop.getProperty(key);
}
public String getMsg () {
return msg;
}
// == Singleton design pattern == //
// Where ever you call this methode in application
// you always get the same and only instance (config_file)
public static AppProperties getInstance(){
return config_file;
}
}
In the DBUtilitis class, where I do my database queries, I now load the properties into final variables and use them in the query methods.
private static final String db_url = AppProperties.getInstance().getProperty("db_url");
private static final String db_user = AppProperties.getInstance().getProperty("db_user");
private static final String db_pwd = AppProperties.getInstance().getProperty("db_pwd");
If I have not completely misunderstood this, the advantage of property files is that they can be stored and protected somewhere on the server. I hope the solution is not completely wrong - it works well anyway. I am always happy to receive suggestions and / or improvements.

Read two lines of a file at once in a flink streaming process

I want to process files with a flink stream in which two lines belong together. In the first line there is a header and in the second line a corresponding text.
The files are located on my local file system. I am using the readFile(fileInputFormat, path, watchType, interval, pathFilter, typeInfo) method with a custom FileInputFormat.
My streaming job class looks like this:
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<Read> inputStream = env.readFile(new ReadInputFormatTest("path/to/monitored/folder"), "path/to/monitored/folder", FileProcessingMode.PROCESS_CONTINUOUSLY, 100);
inputStream.print();
env.execute("Flink Streaming Java API Skeleton");
and my ReadInputFormatTest like this:
public class ReadInputFormatTest extends FileInputFormat<Read> {
private transient FileSystem fileSystem;
private transient BufferedReader reader;
private final String inputPath;
private String headerLine;
private String readLine;
public ReadInputFormatTest(String inputPath) {
this.inputPath = inputPath;
}
#Override
public void open(FileInputSplit inputSplit) throws IOException {
FileSystem fileSystem = getFileSystem();
this.reader = new BufferedReader(new InputStreamReader(fileSystem.open(inputSplit.getPath())));
this.headerLine = reader.readLine();
this.readLine = reader.readLine();
}
private FileSystem getFileSystem() {
if (fileSystem == null) {
try {
fileSystem = FileSystem.get(new URI(inputPath));
} catch (URISyntaxException | IOException e) {
throw new RuntimeException(e);
}
}
return fileSystem;
}
#Override
public boolean reachedEnd() throws IOException {
return headerLine == null;
}
#Override
public Read nextRecord(Read r) throws IOException {
r.setHeader(headerLine);
r.setSequence(readLine);
headerLine = reader.readLine();
readLine = reader.readLine();
return r;
}
}
As expected, the headers and the text are stored together in one object. However, the file is read eight times. So the problem is the parallelization. Where and how can I specify that a file is processed only once, but several files in parallel?
Or do I have to change my custom FileInputFormat even further?
I would modify your source to emit the available filenames (instead of the actual file contents) and then add a new processor to read a name from the input stream and then emit pairs of lines. In other words, split the current source into a source followed by a processor. The processor can be made to run at any degree of parallelism and the source would be a single instance.

Load resource bundle at runtime

Here is what I would like to achieve. We have an application that is running as a servlet on an IBM Domino server.
The application uses resource bundle to get translated messages and labels according to the browser language.
We want to enable customers to override some of the values.
We cannot modify the bundle_lang.properties files in the .jar at runtime.
So the idea was to provide additional bundleCustom_lang.properties files along with the .jar
This bundle could be loaded at runtime using
private static void addToClassPath(String s) throws Exception {
File file = new File(s);
URLClassLoader cl = (URLClassLoader) ClassLoader.getSystemClassLoader();
java.lang.reflect.Method m = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
m.setAccessible(true);
m.invoke(cl, new Object[] { file.toURI().toURL() });
}
So far, so good, this works in Eclipse. Here I had the bundleCustom files in a directory outside the workspace ( /volumes/DATA/Temp/ )
Once the addition ResourceBundle is available, We check this bundle for the key first. If it returns a value than this value is being used for the translation. If no value is returned, or the file does not exist, the value from the bundle inside the .jar is used.
My full code is here
public class BundleTest2 {
static final String CUSTOM_BUNDLE_PATH = "/volumes/DATA/Temp/";
static final String CUSTOM_BUNDLE_MODIFIER = "Custom";
public static void main(String[] args) {
try {
addToClassPath(CUSTOM_BUNDLE_PATH);
System.out.println(_getTranslation("LabelBundle", "OutlineUsersAllVIP"));
} catch (Exception e) {
}
}
private static String _getTranslation(String bundle, String translation) {
return _getTranslation0(bundle, new Locale("de"), translation);
}
private static String _getTranslation0(String bundle, Locale locale, String key) {
String s = null;
try {
try {
ResourceBundle custom = ResourceBundle.getBundle(bundle + CUSTOM_BUNDLE_MODIFIER, locale);
if (custom.containsKey(key)) {
s = custom.getString(key);
}
} catch (MissingResourceException re) {
System.out.println("CANNOT FIND CUSTOM RESOURCE BUNDLE: " + bundle + CUSTOM_BUNDLE_MODIFIER);
}
if (null == s || "".equals(s)) {
s = ResourceBundle.getBundle(bundle, locale).getString(key);
}
} catch (Exception e) {
}
return s;
}
private static void addToClassPath(String s) throws Exception {
File file = new File(s);
URLClassLoader cl = (URLClassLoader) ClassLoader.getSystemClassLoader();
java.lang.reflect.Method m = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
m.setAccessible(true);
m.invoke(cl, new Object[] { file.toURI().toURL() });
}
}
When I try the same from inside the servlet, I get a MissingResourceException.
I also tried to put the .properties files into a customization.jar and provide the full path ( incl. the .jar ) when invoking addToClassPath().
Apparently, the customization.jar is loaded ( it is locked in the file system ), but I still get the MissingResourceException.
We already use the same code in addToClassPath to load a Db2 driver and this is working as expected.
What am I missing?
Why don't you use Database to store the overriden translations? Persisting something crated by client in the local deployment of application is generally not a good idea, what will happen if you redeploy the app, will these resources be deleted? What if you have to run another node of your app, how will you replicate the custom properties file?

Creating synonym filter programmatically

I am struggling with the creation of a SynonymFilter that I try to create programmatically. How are you supposed to tell the filter where the synonym list is?
I am using Hibernate Search, but I don't want to use the #AnalyzerDef annotation.
All I can do is pass a synonym map?
private class AllAnalyzer extends Analyzer {
private SynonymFilterFactory synonymFilterFactory = new SynonymFilterFactory();
public AllAnalyzer() {
ClassLoader classLoader = getClass().getClassLoader();
String filePath = classLoader.getResource("synonyms.txt").getFile();
HashMap<String, String> stringStringHashMap = new HashMap<String, String>();
stringStringHashMap.put("synonyms", filePath);
stringStringHashMap.put("format", "solr");
stringStringHashMap.put("ignoreCase", "false");
stringStringHashMap.put("expand", "true");
stringStringHashMap.put("luceneMatchVersion", Version.LUCENE_36.name());
synonymFilterFactory.init(stringStringHashMap);
}
#Override
public TokenStream tokenStream(String fieldName, Reader reader) {
TokenStream result = null;
result = new StandardTokenizer(Version.LUCENE_36, reader);
result = new StandardFilter(Version.LUCENE_36, result);
result = synonymFilterFactory.create(result);
return result;
}
}
Unable to get it to work. When I debug it says that the map is null and I get a NPE. What is wrong?
Yes, you need to pass a SynonymMap to the SynonymFilter.
Sounds like you want to populate it from a file, so you'll likely want to use SolrSynonymParser to generate it. Along the lines of:
SolrSynonymParser parser = new SolrSynonymParser(true, false, analyzer);
Reader synonymFileReader = new FileRader(new File(path));
parser.add(synonymFileReader);
SynonymMap map = parser.build(); // SolrSynonymParser extends SynonymMap.Builder

Class usage inside class static initialization block

Probably it is discussed somewhere but I failed to find it.
I need to load class properties (java.util.Properties) inside class static initialization block. This is to make possible to access some class general options even without its objects creation. To do so I need appropriate Class object. But of course access to such Class object fails on null object. Something like this.
Class Name {
private static Properties properties;
static {
Name.properties = new Properties();
Name.properties.load(Name.class.getResourceAsStream("Name.properties"));
}
}
Any idea how to handle this situation?
UPDATE:
It was resource name (should be "/Name.properties" for my case). Everything else was OK.
+1 for all meaningful answers from me and ... don't forget to check operations one by one :-).
properties field must be static. And before load you need to initialize static variable with proeprties = new Properties() after that you can invoke load
Declare properties as static and initialize
static Properties properties;
or
static Properties properties = new Properties();
and static block should be
static {
try {
properties = new Properties(); //if you have not initialize it already
Name.properties.load(Name.class.getResourceAsStream("Name.properties"));
} catch (IOException e) {
throw new ExceptionInInitializerError(e); //or some message in constructor
}
}
You need to catch IOException while loading properties file
Final code based on all suggestions is like this:
Class Name {
private static final Properties properties = new Properties();
static {
try {
InputStream stream = Name.class.getResourceAsStream("/Name.properties");
if (stream == null) {
throw new ExceptionInInitializerError("Failed to open properties stream.");
}
Name.properties.load(stream);
} catch (IOException e) {
throw new ExceptionInInitializerError("Failed to load properties.");
}
}
}

Categories

Resources