How to implement dynamic referenced configuration in Java? - java

I have a configuration (config.properties) something like
app.rootDir=
app.reportDir=${app.rootDir}/report
The app.rootDir is not a fixed parameter and it must be initialized by external module. I need keep the ${app.reportDir} keep dynamic reference to ${app.rootDir}.
Use pseudo code to illustrate the problem:
// Init the root dir as '/usr/app'
config.setValue('app.rootDir','/usr/app');
// I need the reportDir to be '/usr/app/report'
String reportDir = config.getValue('app.reportDir');
I can write some codes to get this feature but I'd like to know if there is any existing library do this?
I can use properties, yaml, or json as configuration file type, according to the library availability.

Related

Create custom gradle plugin to analyze java source code and generate codes

I am trying to create a plugin to generate some java code and write back to the main source module. I was able to create a some simple pojo class using JavaPoet and write to the src/main/java.
To make this useful, it should read the code from src/maim/java folder and analyze the classes using reflection. Look for some annotation then generate some codes. Do I use the SourceTask for this case. Looked like I can only access the classes by the files. Is that possible to read the java classes as the class and using reflection analyze the class?
Since you specified what you want to do:
You'll need to implement an annotation processor. This has absolutely nothing to do with gradle, and a gradle plugin is actually the wrong way to go about this. Please look into Java Annotation Processor and come back with more questions if any come up.
With JavaForger you can read input classes and generate sourcecode based on that. It also provides an API to insert it into existing classes or create new classes based on the input file. In contrast to JavaPoet, JavaForger has a clear separation between code to be generated and settings on where and how to insert it. An example of a template for a pojo can look like this:
public class ${class.name}Data {
<#list fields as field>
private ${field.type} ${field.name};
</#list>
<#list fields as field>
public ${field.type} ${field.getter}() {
return ${field.name};
}
public void ${field.setter}(${field.type} ${field.name}) {
this.${field.name} = ${field.name};
}
</#list>
}
The example below uses a template called "myTemplate.javat" and adds some extra settings like creating the file if it does not exist and changing the path where the file will be created from */path/* to */pathToDto/*. The the path to the input class is given to read the class name and fields and more.
JavaForgerConfiguration config = JavaForgerConfiguration.builder()
.withTemplate("myTemplate.javat")
.withCreateFileIfNotExists(true)
.withMergeClassProvider(ClassProvider.fromInputClass(s -> s.replace("path", "pathToPojo")))
.build();
JavaForger.execute(config, "MyProject/path/inputFile.java");
If you are looking for a framework that allows changing the code more programatticaly you can also look at JavaParser. With this framework you can construct an abstract syntax tree from a java class and make changes to it.

How can I create an auto-generated enum from a resource file?

I want to create an auto-generated resource file similar to R from android. I know how to do the parsing and creation of the file and essentially creating a new class file. What I don't know how to do is start this auto-generation process.
So, using eclipse (although if there is a way to make this happen in an agnostic fashion, I would prefer it), how can I trigger an auto-generation session to read a properties file and create a .java file holding static variables and the "keys" from this parsed file, that I can then reference from my code?
A few examples of how to generate java source files have already been provided. It should be relatively easy to read the properties file and invoke one of these APIs.
To trigger the code generation process, you need to add a custom build step. With Ant, just add a custom task. And then hook it up to an Eclipse Builder: project Properties -> Builders -> New.
Subsequently, Eclipse should find and refresh this file on its own. If it doesn't, then check your configs: Preferences -> General -> Workspace -> find "Refresh using native hooks or polling" and similar ones and check them. (Note that I'm not 100% sure that this last part will work.)
The path of least resistance is to run this build step separately. If your properties file is not changing that often, then it shouldn't be that big a deal. This is similar to what you'd do if you use Protocol Buffers, JAXB, wsdl2java, etc. If you want everything to work magically like R.java does, then you probably have to do something a little more complicated:
 - Try to use Eclipse Builder options to control when the Ant task is executed
- If you can't figure that out, then I'd check out how Eclipse hooks up to the above projects (that is, to Protocol Buffers, JAXB, wsdl2java, etc.)
- Look at the ADT custom PreCompilerBuilder class
- Check out the build-helper-plugin
It is common to use a ResourceBundle to create an object that allows you to lookup properties by key. You can learn about the ResourceBundle on the Java Trail.
The basic idea is that you have a text file with a .properties extension. You point the ResourceBundle object to that file. You can then use the getString() or getObject() method passing in the key to the property you want. That is all there is to it. You just need to load the ResourceBundle when you start your program (or sometime before you need it).
If you create you own class that has a ResourceBundle as a member value, you can use a simple bit of code like this to have a simple get() method to get the property value:
public String get(String aString)
{
String sVal = null;
try
{
sVal = (String)myProperties.getObject(aString);
}
catch (MissingResourceException e)
{
log.debug("Missing Property Value: "+aString);
}
return sVal;
}
I hope that is useful.

URIResolver, Docbook and XSL Transform

I am attempting to transform some Docbook XSL to HTML using Java / Xalan and a mixture of the official Docbook XSL files from https://sourceforge.net/projects/docbook/files/docbook-xsl/1.76.1/ with some local xsl files that provide some customizations and overrides.
I want to prevent my application from having to download external resources or access local files. So I have implemented a class that extends the URIResolver interface.
The problem is that the resolve(final String href, final String base) function is not providing enough information to identify the particular file that is being requested.
For example, one of the local override files is imported from the xsl file using <xsl:import href="../../../xsl/html.xsl"/>. In this case the href parameter for my resolver class is set to ../../../xsl/html.xsl, which is fine. The html.xsl file then imports a file called defaults.xsl. The href parameter is set to only defaults.xsl, and the base parameter is set to null.
This might be followed by an import of http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl, in which case the href parameter is set to http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl. However, if the docbook.xsl imports a file called defaults.xsl, the href parameter is also set to defaults.xsl and base is set to null.
The issue is that the href and base parameters don't uniquely identify the resource, and you can't guess which file is being requested by watching the order of the previous hrefs either. Is there some trick to finding out exactly what context a file is being requested in?
Does the Source you are creating the transform from have a system ID? If not, this might be a reason why your base is always null in your URI resolver.
If you are creating transforms from input streams, you can manually assign a system ID to a source. You can generate an artificial one if necessary and use that artificial URI in your URI resolver to map back to a base URI. Also make sure the sources you create in your URI resolver also have system IDs or the same problem will occur with resources imported from those files.

How do you tell the reference path when loading a class?

I'm trying to use JavaLoader to load a java (HttpAsyncClient) class into ColdFusion.
client = loader.create("org.apache.commons.HttpAsyncClient")
How do we know the reference that is org.apache.commons.HttpAsyncClient? I thought if you open the jar file and follow the directory structure, it will give you the reference path. But I don't think this is true.
I'm trying to use the HttpAsyncClient but I'm unable to load it:
client = loader.create("org.apache.commons.HttpAsyncClient") returns a class not found error.
Loader is a reference to JavaLoader, which loads Java classes into your CF server.
Rather than reinvent the wheel, why not try an existing tool like Mark Mandel's AsyncHTTP library?
Update: From the comments, that tool is ACF only. So you might try using the concrete class DefaultHttpAsyncClient as shown in the Asynchronous HTTP Exchange example.
I don't know ColdFusion. You probably have to specify the full path to the class, not just the package containing the class.
According to an example I found the full package and class name is this: org.apache.http.nio.client.HttpAsyncClient
You can also use the javadoc to find out the package and class names: http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/index.html
Getting something async going with an interface like this will probably be brutal. I would suggest trying the sync version first.
EDIT
I would try adapting this sync example to CF: http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientWithResponseHandler.java
When you instantiate HttpGet you have to pass extra parameters to init() as they do in this example: http://www.coldfusionjedi.com/index.cfm/2009/5/29/Generating-Speech-with-ColdFusion-and-Java

Log4j: Changing XML with DOMConfigurator?

I am using log4j with Java and wanted to configure my XML-Config-File (I need to use XML for the ErrorHandler), so that some Properties in the XML (like the Backup-Value for the RollingFileAppender) could be changed within the DOMConfigurator of the log4j-API. This class also got the subst()-method, which should substitute the chosen values, but I really don´t know how to handle it.
If their is no way changing the config with the DOMConfigurator, which else possibilities did I got to easily correct values in an ambiguous XML-File (So to say, because the XML-Tags are not unique or only their Tag-names, which are values itself)? My XML is kind of static or hand-written.
Why can't you fix the original XML file on the disk?
If for some reason that's not possible, I would rather try altering the configuration directly via Logger, after the config file has been loaded.

Categories

Resources