I'm writing a MyTask that extends org.apache.tools.ant.Task
In the execute() method of MyTask i need to include a file.
I mean i would call the <include> task in the execute() method of MyTask.
I looked at the Apache Ant API but i didn't found the class IncludeTask that implements the <include> task
Where can i find the Include java class?
It seems that <include> isn't implemented as Task class in the normal way. The logic seems baked into org.apache.tools.ant.ProjectHelper, as though <include> is handled in a special way.
You may not have much luck trying to leverage that functionality.
Taken from: http://ant.apache.org/manual/develop.html
For example suppose one wanted to handle objects object of type org.apache.tools.ant.taskdefs.condition.Condition, one may have a class:
public class MyTask extends Task {
private List conditions = new ArrayList();
public void add(Condition c) {
conditions.add(c);
}
public void execute() {
// iterator over the conditions
}
}
One may define and use this class like this:
<taskdef name="mytask" classname="MyTask" classpath="classes"/>
<typedef name="condition.equals"
classname="org.apache.tools.ant.taskdefs.conditions.Equals"/>
<mytask>
<condition.equals arg1="${debug}" arg2="true"/>
</mytask>
Related
For performance reasons, I have a class that stores a Map whose key is a Class<?> and its value is function of that class's fields. The map is populated during code execution according to the type of the calling object. The above is a generalization/simplification
public class Cache {
private static final Map<Class<?>, String> fieldsList = ...;
//Synchronization omitted for brevity
public String getHqlFor(Class<?> entity){
if (!fieldsList.containsKey(entity))
fieldsList.put(entity,createHql(entity));
return fieldsList.get(entity);
}
}
During development, thanks to the help of Jrebel, I often make modifications to classes by changing entire properties or just their names. I can continue development just fine. However, if I already put a value into the cache it will be stale forever.
What I am asking here is if it is possible to intercept the event that a class in the classpath has changed. Very broad... But my specific problem is very simple: since I have such a need only during development, I just want to wipe that cache in case any class in my classpath changes.
How can I accomplish this? I don't need to do anything special than intercepting the event and simply wiping the cache
JRebel has a plugin API that you can use to trigger code on class reloads. The tutorial complete with example application and plugin available here: https://manuals.zeroturnaround.com/jrebel/advanced/custom.html
The JRebel plugin is a self-contained jar built against the JRebel SDK, which is attached to the running application via the JVM argument -Drebel.plugins=/path/to/my-plugin.jar. The JRebel agent attached to the application will load and start plugins from this argument.
If the application is not started with the JRebel agent, the plugin is simply not loaded.
In your example you want to register a ClassEventListener that will clear the Cache.fieldsList map. As it is a private field, you need to access it via reflection or add a get/clear method via a ClassBytecodeProcessor
public class MyPlugin implements Plugin {
void preinit() {
ReloaderFactory.getInstance().addClassReloadListener(new ClassEventListenerAdapter(0) {
#Override
public void onClassEvent(int eventType, Class<?> klass) throws Exception {
Cache.clear();
}
});
}
// ... other methods ...
}
And to clear the map
public class CacheCBP extends JavassistClassBytecodeProcessor {
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass) {
ctClass.addMethod(CtMethod.make("public static void clear() { fieldsList.clear(); }", ctClass));
}
}
However a better option is to only clear/recalculate the single class entry on class reload if possible. The example didn't display whether the info computed from one class depended on superclass infos, but if this is true, the JRebel SDK has methods to register a reload listener on the class hierarchy as well.
There is an existing class ClassValue which already does the job for you:
public class Cache {
private final ClassValue<String> backend = new ClassValue<String>() {
#Override
protected String computeValue(Class<?> entity) {
return createHql(entity);
}
};
public String getHqlFor(Class<?> entity){
return backend.get(entity);
}
}
When you call get, it will call computeValue if this is the first call for this specific Class argument or return the already existing value otherwise. It does already care thread safety and for allowing classes to get garbage collected. You don’t need to know when class unloading actually happens.
I'm writing a gerrit plugin and want to close network connections on plugin restart/shutdown. This can be done using a LifecycleListener.
As far as I know, there are two modes of operation for a gerrit plugin concerning Guice. One is to not declare anything in the Manifest and use auto-registration for everything, using annotations like #Listen and #Export. The other is to create a Guice module and do all wiring manually in that module.
I'd like to use auto-registration, but I can't make it work with a LifecycleListener. Adding a #Listen annotation has no effect, the Listener is getting ignored.
My code looks like this (minimized):
#Listen
#Singleton
public class CommitValidationTest implements CommitValidationListener {
#Listen
public static class Lifecycle implements LifecycleListener {
#Override
public void start() {
// write to log
}
#Override
public void stop() {
// write to log
}
}
}
I gathered that LifecycleListeners can't be used in combination with AutoRegistration.
Here's why: In order for the #Listen annotation to work, the #ExtensionPoint interface which is implemented by the class (in this case LifecycleListener) must have a DynamicItem, DynamicSet or DynamicMap definition in a Guice module, which isn't the case for LifecycleListener.
I've an interface implemented by classes that perform a file processing, say searching or whatever.
public interface FileProcessorInterface {
public void processFile(String fileName);
}
Then i have a different implementation for each file type:
public class TxtProcessor implements FileProcessorInterface {
#Override public void processFile(String fileName) { //do the work }
}
Thus i have the Utilizer of the processor, that has a method that allows for registering each class, something like this:
class Utilizer {
Map <String, Class> registered = new HashMap<>();
public void registerClass(String fileExt, Class clazz) {
registered.put(fileExt, clazz);
}
public void processFile(String fileName) {
//1) get the registered class from registered map (omitted because easy and not relevant)
//2) create an instance of the class using reflection (omitted because easy and not relevant)
FileProcessorInterface p = ....
p.processFile(fileName);
}
So far it's ok.
Now, i'm providing many implementations of my interface.
And i am tempted to provide each implementation class with a static initializer that register itself in the Utilizer, in the case of my previous TxtProcessor it would be:
class TxtProcessor implements FileProcessorInterface {
//previous code
static {
Utilizer.registerClass("txt", TxtProcessor.class);
}
}
The problem is that this static method will never be called because in the "statically reachable" code of the application there is no reference to my TxtProcessor class, since it is instantiated via reflection. So the jvm does not call the static initializer.
Say that i have two parts: the "generic code" that is the Utilizer and on the other side the implementations; it has to be thought as something provided dinamically and so it is not known by the Utilizer part.
Infact the idea was exactly that each class would register itself leaving the Utilizer untouched.
It is hard for me conceiving a solution that does not put some form of 'knowledge' of the implementations on the Utilizer side (and that stays simple), just because of the problem of the static initializer not called. How to overcome this?
Using reflections seems to be the best fit here. It's like geared to do this.
All you need is a small static block in Utilizer as
static {
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("path.to.all.processors.pkg"))
.setScanners(new SubTypesScanner())
);
reflections.getSubTypesOf(path.to.all.processors.pkg.FileProcessor.class);
}
If you don't want a third-part dependency, just add a FileProcessors.properties file to your classpath
txt=path.to.all.processors.pkg.TxtProcessor
doc=path.to.all.processors.pkg.DocProcessor
pdf=path.to.all.processors.pkg.PdfProcessor
and then register all the listed classes from Utilizer as
static {
Properties processors = new Properties();
try {
processors.load(Utilizer.class
.getResourceAsStream("FileProcessors.properties"));
} catch (IOException e) {
e.printStackTrace();
}
for (String ext : processors.stringPropertyNames()) {
Utilizer.registerClass(ext, Class.forName(processors.getProperty(ext));
}
}
This no longer requires a static block in every FileProcessor now.
You can look at Reflections library. It allow you to find all the classes which implement an interface, have an annotation or extend a class.
You Could...
Use the same concept as JDBC does for loading it's drivers. This would require you to use Class#forName to initialize the class when the program is first loaded. While this does mean that the implementation is still dynamic from the point of view of your utility class, it is specified at run time by your application...
This gives you control over which implementation you might want to use
You Could...
Use the same concept as something like java.awt.Toolkit uses when it initializes it's instance.
It basically looks up the resource (in this case a System property) and then loads the class dynamically using Class.
Personally, I normally look for a named resource (usually a properties file) and load a key from it.
Something like getClass().getResource("/some/gloabl/configFile");, which every implementation would need to provide.
Then, if available, read the properties file and find the key I'm after.
If more then one implementation is linked in though, there is no guarantee which one will be loaded.
Quick and dirty: You can statically initialize your Utilizer in main() with correct association.
Better solution: externalize in a resource file association like
txt=path.to.package.TxProcessor
load it in Utilizer and load FileProcessorInterface implementors with Class.forName()
you can force the static init by Class.forName(fqn, true, classLoader) or the short form Class.forName(fqn)
You could have a registry file (for example, some XML file), that would contain the list of all classes you support :
<item type="txt">somepackage.TxtProcessor</item>
<item type="gif">somepackage.GIFProcessor</item>
...
Your Utilizer would load this file into its registry.
I am using Apache Ant as a tool for tedious data collection and calculation tasks I have to do over and over again. I have defined some custom Ant Tasks and they work really well.
However, now I want to create new data-types using the <typedef> tag. I want to define some data in the beginning of my build.xml which I can reference to later, much like the following example from a regular build file from one of my Java projects:
<path id="classpath.build">
<fileset dir="${dir.lib}">
<include name="**/*.jar" />
<exclude name="**/junit*" />
</fileset>
</path>
So I created a simple HelloWorld example like follows:
<sampledata data="LOL" id="someid" />
and in a custom ant task I would like to refer to this data type:
<customtask dataref="someid" />
This seems reasonable simple, so after digging in the API docs I found out that my class has to extend org.apache.tools.ant.types.DataType and has to have the method setRefid(org.apache.tools.ant.types.Reference r).
My custom Ant Task customtask uses the following code for the dataref attribute:
public class CustomTask extends Task {
private SampleData data;
public void setDataref(Reference r) {
data = new SampleData(getProject());
data.setRefid(r);
}
public void execute() {
System.out.println(data.getData());
}
}
And my SampleData implementation is like follows:
public class SampleData extends DataType {
private String data;
public SampleData(Project project) {
setProject(project);
}
public void setData(String data) {
this.data = data;
}
public String getData() {
return this.data;
}
public void setRefid(Reference r) {
super.setRefid(r);
}
}
Mind you, this is all based on the sources from org.apache.tools.ant.types.Path which shows the behavior I want.
However, after creating a target with the customtask as defined above, the output is null. So SampleData is instantiated but the reference is not set correctly. When I debug I find out that SampleData is correctly instantiated in my ant file with the data LOL and even the refence is set to someid. Also, the CustomTask class setDataref method indeed is passed a Reference named someid, so it all goes wrong in the setDataref method, but I have no clue what I have to do and the manual is lacking (or I am missing an important part).
I have the feeling I don't completely grasp the lifecycle of custom datatypes with id's.
EDIT 23-11-2012 9:24 :
After some more fiddling and looking in the source of org.apache.tools.ant.types.Path I followed some of the methods there and changed my SampleData.getData to the following:
public String getData() {
if(isReference()) {
return ((SampleData)getCheckedRef()).getData();
}
return this.data;
}
I am a little bit further, however now I get the following Ant error in my build.xml :
/home/arjan/dev/so-demo/build.xml:9: someid doesn't denote a SampleData
However when I check the class encapsulated by the Reference object it is the correct type.
I am getting pretty fed up by this now. Any more tips?
EDIT 23-11-2012 11:46 :
I created a Gist with a clear testcase. My Ant version is 1.8.4.
Hopefully someone will come with a solution, because I've looked in other libraries like Sonatype Aether Antlib and followed their way of reasoning.
It all goes wrong at the getCheckedRef method, specifically in the Ant sourcefile src\main\org\apache\tools\ant\types\DataType.java:250:
if (!(requiredClass.isAssignableFrom(o.getClass()))) {
log("Class " + o.getClass() + " is not a subclass of " + requiredClass,
Project.MSG_VERBOSE);
String msg = ref.getRefId() + " doesn\'t denote a " + dataTypeName;
throw new BuildException(msg);
}
What is going on? This is the simples testcase I could come up with.
I believe that this might fix your issue, I was running into similar errors:
You are missing the loaderRef directive for your custom task and type. See here: If you are defining tasks or types that share the same classpath with multiple taskdef or typedef tasks, the corresponding classes will be loaded by different Java ClassLoaders. Two classes with the same name loaded via different ClassLoaders are not the same class from the point of view of the Java VM, they don't share static variables and instances of these classes can't access private methods or attributes of instances defined by "the other class" of the same name. They don't even belong to the same Java package and can't access package private code, either.
So when you define your custom task and custom type via typedef and taskdef use the loaderRef attribute - this can be anything (like customTaskLoader) as long as it is the same between your task and type definition.
From there you can simplify your code even further:
public class CustomTask extends Task {
private SampleData data;
public void execute() {
System.out.println(data.getData());
}
}
and
public class SampleData extends DataType {
private String data;
public SampleData(Project project) {
setProject(project);
}
public void setData(String data) {
this.data = data;
}
public String getData() {
if(isReference()) {
return ((SampleData)getCheckedRef()).getData();
}
return this.data;
}
}
I think the issue is you have not provided setter for Data in your class... Which is mandatory for CustomTask...
public class CustomTask extends Task {
private SampleData data;
public void setDataref(Reference r) {
data = new SampleData(getProject());
data.setRefid(r);
}
public void setData(SampleData data){
this.data = data;
}
public void execute() {
System.out.println(data.getData());
}
}
Hope this helps..
I solved it using the Gist above! The problem is two-fold, however I don't know how to solve the second one.
Problem 1
Somehow the classpathref argument for the typedef and taskdef tags is not the way to go. I am directing them to my compiled classes in the cls directory.
So I decided to jar all my files and place them in the {ant.home}/lib directory like follows:
<jar basedir="cls" destfile="${ant.home}/lib/demo.jar" />
<delete dir="cls" />
This way I could remove the classpathref arguments.
I thought that would solve it maybe... but I was wrong, however it is the actual solution (if you might call it that) that works.
Problem 2
Eclipse... this program is using its own Ant distribution and somehow my own generated jar is not added to the classpath when running Eclipse. This results in the following error:
typedef class types.DemoType cannot be found
Running from the command-line proved to be no problem.
Bottomline
The problem is solved by rarring my types and tasks and running it from the commandline. Using classpathref with typedef or taskdef resulted in the someid doesn't denote a SampleData error. Using Eclipse resulted in the class not found error.
Odd behavior I must say and I want to know how to make Eclipse properly work with custom tasks, because that must possible.
Well... that has cost me a few hours.
I have a JAR file that I'm using and I want to modify one of the files inside it. In a nutshell I have
public class ClassB {
public void printMethod(){
ClassA A = new ClassA();
A.printout();
}
}
public class ClassA {
public void printout(){
System.out.println("1234");
}
}
and I want to change ClassA's printout method to
public class ClassA {
public void printout(){
System.out.println("abcd");
}
}
I know you cannot modify a JAR without unpacking/rebuilding it and for this, let's say I can't do that. Is there a way to make modifications to ClassA without actually touching the current ClassA? My approach is to have a new class inherit from ClassA with an overridden method and then have a new class inherit from ClassB that calls the Inherited ClassA
public class InheritedClassA extends ClassA{
#Override
public void printout(){
System.out.println("abcd");
}
}
public class InheritedClassB extends ClassB{
#Override
public void printMethod(){
InheritedClassA A = new InheritedClassA();
A.printout();
}
}
I don't like this approach though because in my actual JAR, so many classes are using ClassA that its a nightmare trying to correctly do this with all of them, which then all require the same process on them. I know you cannot overload/overwrite a whole class which is basically what I want to do. Is there another way to do this?
EDIT
To make it even harder, I cannot download any new frameworks or software or anything.
I can only provide pointers as I never felt the need for it.
What you are referring to is called "Bytecode enhancement", and yes there are several frameworks to achieve it.
BCEL - http://commons.apache.org/bcel/
ASM - http://asm.ow2.org/
Usually, java developers prefer to use the inversion of control pattern. This allows the code to configure itself at runtime via a configuration file - See Spring IoC for more details.
One option which may not be feasible would be to create a new version of ClassA, package it up in its own jar file, and put that ahead of the original version in your classpath.
However, this is a pretty odd scenario - why can you not update the existing jar file? Even if that means a bit of extra work, it's likely to be much cleaner in the long run than any other approach.