I am using the apache commons configuration library to read a configuration xml and it works nicely. However, I am not able to modify the value of the elements or add new ones.
To read the xml I use the following code:
XMLConfiguration config = new XMLConfiguration(dnsXmlPath);
boolean enabled = config.getBoolean("enabled", true));
int size = config.getInt("size");
To write I am trying to use:
config.setProperty("newProperty", "valueNewProperty");
config.save();
If I call config.getString("newProperty"), I obtain "valueNewProperty", but the xml has not been changed.
Obviously it is not the right way or I am missing something, because it does not work.
Could anybody tell me how to do this?
Thanks in advance.
You're modifying xml structure in memory
The parsed document will be stored keeping its structure. The class also tries to preserve as much information from the loaded XML document as possible, including comments and processing instructions. These will be contained in documents created by the save() methods, too.
Like other file based configuration classes this class maintains the name and path to the loaded configuration file. These properties can be altered using several setter methods, but they are not modified by save() and load() methods. If XML documents contain relative paths to other documents (e.g. to a DTD), these references are resolved based on the path set for this configuration.
You need to use XMLConfiguration.html#save(java.io.Writer) method
For example, after you've done all your modifications save it:
config.save(new PrintWriter(new File(dnsXmlPath)));
EDIT
As mentioned in comment, calling config.load() before calling setProperty() method fixes the issue.
I solved it with the following lines. I was missing the config.load().
XMLConfiguration config = new XMLConfiguration(dnsXmlPath);
config.load();
config.setProperty("newProperty", "valueNewProperty");
config.save();
It is true though that you can used the next line instead of config.save() and works the same.
config.save(new PrintWriter(new File(dnsXmlPath)));
Related
I'm looking for a way to access the name of the file being processed during the data transformation within a DoFn.
My pipeline is as shown below:
Pipeline p = Pipeline.create(options);
p.apply(FileIO.match()
.filepattern(options.getInput())
.continuously(Duration.standardSeconds(5),
Watch.Growth.<String>never()))
.apply(FileIO.readMatches()
.withCompression(Compression.GZIP))
.apply(XmlIO.<MyString>readFiles()
.withRootElement("root")
.withRecordElement("record")
.withRecordClass(MyString.class))//<-- This only returns the contents of the file
.apply(ParDo.of(new ProcessRecord()))//<-- I need to access file name here
.apply(ParDo.of(new FormatRecord()))
.apply(Window.<String>into(FixedWindows.of(Duration.standardSeconds(5))))
.apply(new CustomWrite(options));
Each file that is processed is an XML document. While processing the content, I need access to the name of the file being processed too to include in the transformed record.
Is there a way to achieve this?
This post has a similar question, but since i'm trying to use XmlIO I havent found a way to access the file metadata.
Below is the approach I found online, but not sure if there is a way to use it in the pipeline described above.
p.apply(FileIO.match()
.filepattern(options.getInput())
.continuously(Duration.standardSeconds(5),
Watch.Growth.<String>never()))//File Metadata
.apply(FileIO.readMatches()
.withCompression(Compression.GZIP))//Readable Files
.apply(MapElements
.into(TypeDescriptors.kvs(TypeDescriptors.strings(),new TypeDescriptor<ReadableFile>() {} ))
.via((ReadableFile file) -> {
return KV.of(file.getMetadata().resourceId().getFilename(),file);
})
);
Any suggestions are highly appreciated.
Thank you for your time reviewing this.
EDIT:
I took Alexey's advice and implemented a custom XmlIO. It would be nice if we could just extend the class we need and override the appropriate method. However, in this specific case, there was a reference to one method which was protected within the sdk because of which I couldn't easily override what i needed and instead ended up copying a whole bunch of files. While this works for now, I hope in future there is a more straighforward way to access the file metadata in these IO implementations.
I don't think it's possible to do "out-of-box" with a current implementation of of XmlIO since it returns a PCollection<T> where T is a type of your xml record and, if I'm not mistaken, there is no way to add a file name there. Though, you still can try to "reimplement" a ReadFiles and XmlSource in a way that it will return parsed payload and input file metadata.
EDIT: I changed my mind. I would find a way to generate the Java class and load the JSON as an object of that class.
I just discovered that exists a variant of JSON called JSON-LD.
It seems to me a more structured way of defining JSON, that reminds me XML with an associated schema, like XSD.
Can I create a Java class from JSON-LD, load it at runtime and use it to convert JSON-LD to an instantiation of that class?
I read the documentation of both the implementations but I found nothing about it. Maybe I read them bad?
Doing a Google search brought me to a library that will decode the JSON-LD into an "undefined" Object.
// Open a valid json(-ld) input file
InputStream inputStream = new FileInputStream("input.json");
// Read the file into an Object (The type of this object will be a List, Map, String, Boolean,
// Number or null depending on the root object in the file).
Object jsonObject = JsonUtils.fromInputStream(inputStream);
// Create a context JSON map containing prefixes and definitions
Map context = new HashMap();
// Customise context...
// Create an instance of JsonLdOptions with the standard JSON-LD options
JsonLdOptions options = new JsonLdOptions();
// Customise options...
// Call whichever JSONLD function you want! (e.g. compact)
Object compact = JsonLdProcessor.compact(jsonObject, context, options);
// Print out the result (or don't, it's your call!)
System.out.println(JsonUtils.toPrettyString(compact));
https://github.com/jsonld-java/jsonld-java
Apparently, it can take it from just a string as well, as if reading it from a file or some other source. How you access the contents of the object, I can't tell. The documentation seems to be moderately decent, though.
It seems to be an active project, as the last commit was only 4 days ago and has 30 contributors. The license is BSD 3-Clause, if that makes any difference to you.
I'm not in any way associate with this project. I'm not an author nor have I made any pull requests. It's just something I found.
Good luck and I hope this helped!
see this page: JSON-LD Module for Jackson
Since I do not know of a better solution, I am currently writing small Java classes to process .properties file to merge them, remove duplicate properties, override properties, etc. (I need to process many files and a huge number of properties).
org.apache.commons.configuration.PropertiesConfiguration works great for reading a properties file (using org.apache.commons.configuration.AbstractFileConfiguration.load(InputStream, String), however if I rewrite the file using org.apache.commons.configuration.AbstractFileConfiguration.save(File), I have two problems:
the original layout and comments are lost. I am going to try the PropertiesConfigurationLayout, which is supposed to help here (see How to overwrite one property in .properties without overwriting the whole file?) and post the results
the properties are slightly modified. Accents é and è are rewritten as unicode characters (\u00E9), which I do not want. Afaik .properties files are generally ISO-8859-1 (and I think mine are), so escaping shouldn't be necessary.
Specifying the encoding when calling org.apache.commons.configuration.AbstractFileConfiguration.load(InputStream, String) does not make a difference, because when it is not specified, the same encoding is used by default anyway (private static final String DEFAULT_ENCODING = "ISO-8859-1";). What could I do about that ?
Doing some tests I think you can do what you want, using CombinedConfiguration plus a OverrideCombiner. Basically the properties will be merged automatically and the trick for the layout is to get the layout from one of the loaded files:
CombinedConfiguration props = new CombinedConfiguration();
final PropertiesConfiguration defaultsProps = new PropertiesConfiguration(new File("/tmp/default.properties"));
final PropertiesConfiguration customProps = new PropertiesConfiguration(new File("/tmp/custom.properties"));
props.setNodeCombiner(new OverrideCombiner());
props.addConfiguration(customProps); //first should be loaded the override values
props.addConfiguration(defaultsProps); // last your 'default' values
PropertiesConfiguration finalFile = new PropertiesConfiguration();
finalFile.append(props);
PropertiesConfigurationLayout layout = new PropertiesConfigurationLayout(finalFile, defaultsProps.getLayout()); //here we copy the layout from the 'base file'
layout.save(new FileWriter(new File("/tmp/app.properties")));
The issue with the encoding I don't know if its possible to find a solution.
How do you merge two .odt files? Doing that by hand, opening each file and copying the content would work, but is unfeasable.
I have tried odttoolkit Simple API (simple-odf-0.8.1-incubating) to achieve that task, creating an empty TextDocument and merging everything into it:
private File masterFile = new File(...);
...
TextDocument t = TextDocument.newTextDocument();
t.save(masterFile);
...
for(File f : filesToMerge){
joinOdt(f);
}
...
void joinOdt(File joinee){
TextDocument master = (TextDocument) TextDocument.loadDocument(masterFile);
TextDocument slave = (TextDocument) TextDocument.loadDocument(joinee);
master.insertContentFromDocumentAfter(slave, master.getParagraphByReverseIndex(0, false), true);
master.save(masterFile);
}
And that works reasonably well, however it looses information about fonts - original files are a combination of Arial Narrow and Windings (for check boxes), output masterFile is all in TimesNewRoman. At first I suspected last parameter of insertContentFromDocumentAfter, but changing it to false breaks (almost) all formatting. Am I doing something wrong? Is there any other way?
I think this is "works as designed".
I tried this once with a global document, which imports documents and display them as is... as long as paragraph styles have different names !
Using same named templates are overwritten with the values the "master" document have.
So I ended up cloning standard styles with unique (per document) names.
HTH
Ma case was a rather simple one, files I wanted to merge were generated the same way and used the same basic formatting. Therefore, starting off of one of my files, instead of an empty document fixed my problem.
However this question will remain open until someone comes up with a more general solution to formatting retention (possibly based on ngulams answer and comments?).
I'm trying to read the property values from a bar file created by message broker.
I want to do this via java. The api is here: http://publib.boulder.ibm.com/infocenter/wmbhelp/v7r0m0/index.jsp?topic=%2Fcom.ibm.etools.mft.doc%2Fbe43410_.htm
However, I can only figure out how to get the names of the properties NOT THEIR VALUES by using the deployment descriptor. I can see how to override the value that a property has, but once again, not how to retrieve the value. Another words I can see only how to write to the property not read from it. I want to do both! Call me greedy ;)
If I use the command line based utility: http://publib.boulder.ibm.com/infocenter/wmbhelp/v7r0m0/index.jsp?topic=%2Fcom.ibm.etools.mft.doc%2Faf03900_.htm
I can get the property values no problem.
But I want to get them via java if at all possible.
Thanks in advance for any help on this!
The problem was I was misunderstanding how the deployment descriptor worked. I thought that when the java API referred to overridden properties it meant ones that were over ridden in my java code. But it actually meant all the properties that had a value in the bar file.
That being said getting the values is not strait forward. You have to get all the identifiers and then pass them to getOverride();
BarFile b = BarFile.loadBarFile("C:\\BarParamTest\\myBar.bar");
DeploymentDescriptor d = b.getDeploymentDescriptor();
Enumeration<String> properties = d.getPropertyIdentifiers();
while(properties.hasMoreElements())
{
String p = properties.nextElement();
System.out.println(p + " = " + d.getOverride(p));
}
or use the following to only list properties that have values
Enumeration<String> properties = d.getOverriddenPropertyIdentifiers();
For some reason settings are not written to file, if they are not overriden or not changed.(the reason is the lack of necessity to keep the property's default value:) ) so the way to get the properties is to know their default values. But I would recommend you to use com.ibm.mq.jar library if you're able to connect to broker to read properties using method
java.util.Properties MessageFlowProxy.Node.getProperties()
from already deployed .bar.