This (obviously) works:
#Every("10s")
public class Extinguisher extends Job {
...
}
...but this doesn't:
#Every(Play.configuration.getProperty("my.setting", "10s"))
public class Extinguisher extends Job {
...
}
When running auto-test, the app doesn't start and complains my controllers can't get enhanced because of a NullPointerException encountered by javassist.
Is there a way to configure a job scheduling from application.conf?
You can schedule your job manually from #OnApplicationStartup job:
#OnApplicationStartup
public class ExtinguisherBootstrap extends Job {
public void doJob() {
new Extinguisher()
.every(Play.configuration.getProperty("my.setting", "10s"));
}
}
I don't know whether Play or javassist extend what you can do with the Java language, but I can at least point out that the following line is not legal Java:
#Every(Play.configuration.getProperty("my.setting", "10s"))
For an annotation with a parameter with type T and value V, the Java Language Specification requires that:
If T is a primitive type or String, V is a constant expression
In this case, T, the type of the annotation parameter, is a String, but the value you're trying to set to it isn't a (compile-time) constant expression.
The issue is that "configuration" wont be available at that stage.
I don't think what you want to do is possible (as per my current knowledge of Play, maybe someone knows a trick to make it work)
You may be able to "hack it" by having a job run every few seconds and in that job launch the target job as per configuration. It's less efficient, but it may solve your issue
You can do something like this:
#On("cron.noon")
Which will look for a line like this in application.conf:
cron.noon = 1s
Related
Question is : how can I handle a chain of fallback values in Spring expression, allowing me to fallback on higher level configuration until I got a defined value ?
To explain a little, let's illustrate this with my own use case : I was intending to create a Spring application using the #Scheduled annotation to run some processes. Thing is I have many scheduled tasks and I would let the running frequency to be easily configurable for all of them, or only for a subset.
So I was looking for something like
#Component
public class SpecificTaskRunner {
#Scheduled(cron = "${ specific-task-cron ?: task-families-cron ?: default-cron }")
public void specificTask() {
doSomething();
}
}
Letting application configure either the frequency of all the Scheduled task at once by overriding the default-cron value, or only a subset of them by overriding the task family property, or finally, specifying on a task basis. Advantage of this approach is that it allows to play with multiple configuration levels as every scheduled task looks for the appropriate property starting from the most specific, and looking for a more generic until it got something defined, ultimately fall-backing on a default global value.
Unfortunately... this do not work. When evaluated, if the first element is not defined, then if fallback on the whole remaining. In this example, it would mean that if configuration misses a value for specific-task-cron, then the resolved value is : task-families-cron ?: default-cron which unfortunately is not what I'm looking for!
I found 2 way to handle it :
The first one, is purely based on Spring expression. Spring seems to re-evaluates the result of the Elvis operator if it also is a Spring expression. So my working configuration was :
#Component
public class SpecificTaskRunner {
#Scheduled(cron = "${ specific-task-cron ?: ${ task-families-cron ?: default-cron }}")
public void specificTask() {
doSomething();
}
}
Which in my real use case, with one more fallback, was not really convenient...
So I switched to a simpler solution that relies on configuration by defining a chain of values this way :
#application.yml
default-cron: '0 */5 0 0 0 0' #every 5 minutes
task-families-cron: ${default-cron}
specific-task-cron: ${task-families-cron}
Combined with
#Component
public class SpecificTaskRunner {
#Scheduled(cron = "${specific-task-cron}")
public void specificTask() {
doSomething();
}
}
This way any override of a property apply to hierarchical sub-levels, unless they got themselves overridden.
Both solutions seems to works, so at the end, yes Spring expression language handle multiple fallback. Whether it should be used, or is the configuration approach better readable... I let you decide.
Is there a specific way to accomplish this? I tried to find a solution on here but couldn't find what I need. I have a Spring Boot application that will be accepting multiple arguments from the command line. The argument in question is the queue name (i.e. the destination). It can be one of several of our many queues. The JmsListener is in the form
#JmsListener(destination="dest_goes_here")
public void processOrder(Message message){. . .}
I have a class that basically looks like this
public class Arguments {
private static queue
private static antoherArg
:
:
getters and setters
}
And what I would like to say is destination = Arguments.getQueue(), but it seems destination can only be a static final variable? I assume this because the error presents a little tooltip that alludes to that.
I also tested it, as I have yet another class called Constants, that obvioulsy contains constants, and if I hard code the queue name as public static final String QUEUE = "MyQ"; then say destination = Constants.QUEUE it is ok with that.
So then I assumed I could do something like this in my listener class private static final String QUEUE = Arguments.getQueue(); But it doesn't like that either. Alas, I am stumped.
So really two questions here if anyone is willing to knowledge share. Why is the #JmsListener ok with having destination set to my second solution, but not the first and the last?
And then the main question (that I'd prefer you answer over the first) is, what strategies can I make use of to set destination to a variable that originates from the command line (i.e. be dynamic)?
Edit: To clarify, I cannot keep the value in my Constants class, as the value will be coming from the command line and needs to be passed to the JmsListener class to be used as the destination.
That's how Java works, destination must be a compile-time constant expression and a function invocation isn't considered one. Take a look at the official language specification for more details. EDIT: you can also look at this answer.
As far as your second (and more important) question goes, I have several suggestions for you.
First, you can read the queue name from a configuration property, like so: destination="${jms.queue.name1}" where jms.queue.name1 is your configuration property. Then, since you are using Spring Boot, you can use command-line arguments to override your configuration properties (see externalized configuration documentation for more details). That way, you'll be able to specify the queue name at runtime by passing it as a command-line argument like so --jms.queue.name1=foo.
Second, you can use programmatic listener registration, like so:
#Configuration
#EnableJms
public class AppConfig implements JmsListenerConfigurer {
#Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
endpoint.setId("myJmsEndpoint");
endpoint.setDestination(Arguments.getQueue());
endpoint.setMessageListener(message -> {
// processing
});
registrar.registerEndpoint(endpoint);
}
}
I'm trying to use Picocontainer Web (picocontainer-web-core-2.5.1.jar).
I have configured everything and I checked out that everything works just fine, until trying to retrieve anything from container... :p
I though I should use static method getRequestComponentForThread(Class type) from PicoServletContainerFilter class, which looks like this:
public static Object getRequestComponentForThread(Class type) {
MutablePicoContainer requestContainer = ServletFilter.currentRequestContainer.get();
MutablePicoContainer container = new DefaultPicoContainer(requestContainer);
container.addComponent(type);
return container.getComponent(type);
}
But as you can see, in that method, new instance of DefaultPicoContainer is created and type which I'm trying to retrieve is being registered.
if type is a Class - new instance is created and returned, instead of cached one from parent container...
if type is a Interface - runtime exception ("'ExampleInterface' is not instantiable") is being thrown, at 3rd line (addComponent).
And my question is: How to use this library? I was pretty sure that I understand it, but implementation of this one method blows my mind...
Actually you should not use getComponent unless there's a special case.
App/Session/Request containers are created for you when you add pico context listener to the web.xml.
Just configure components for each scope and picocontainer will inject stuff automatically and instantiate components when needed. Also use Startable lifecycle interface.
I figured out one acceptable solution - writing own version of org.picocontainer.web.PicoServletContainerFilter.ServletFilter - and adding one method:
public class MyComponentContainer extends PicoServletContainerFilter {
/*
code from original class PicoServletContainerFilter.ServletFilter
[...]
*/
public static <T> T getComponent(Class<T> clazz) {
return (T) currentRequestContainer.get().getComponent(clazz);
}
}
I'm not sure if it's the best to do, but it work's fine for me. However, if you know better solution I'd be grateful for information :)
I want/need to pass along the rowkey to the Reducer, as the rowkey is calculated in advance, and the information is not available anymore at that stage. (The Reducer executes a Put)
First I tried to just use inner classes, e.g.
public class MRMine {
private byte[] rowkey;
public void start(Configuration c, Date d) {
// calc rowkey based on date
TableMapReduceUtil.initTableMapperJob(...);
TableMapReduceUtil.initTableReducerJob(...);
}
public class MyMapper extends TableMapper<Text, IntWritable> {...}
public class MyReducer extends TableReducer<Text, IntWritable, ImmutableBytesWritable> {...}
}
and both MyMapper and MyReducer have the default constructor defined. But this approach leads to the following exception(s):
java.lang.RuntimeException: java.lang.NoSuchMethodException: com.mycompany.MRMine$MyMapper.<init>()
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:115)
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:719)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:370)
at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:212)
Caused by: java.lang.NoSuchMethodException: com.company.MRMine$MyMapper.<init>()
at java.lang.Class.getConstructor0(Class.java:2730)
at java.lang.Class.getDeclaredConstructor(Class.java:2004)
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:109)
I got rid of the exception by declaring the inner classes static (Runtimeexception: java.lang.NoSuchMethodException: tfidf$Reduce.<init>()) . but then I'd have to make the rowkey static as well, and I'm running multiple jobs in parallel.
I found https://stackoverflow.com/a/6739905/1338732 where the configure method of the Reducer is overwritten, but it doesn't seem to be available anymore. Anyhow, I wouldn't be able to pass along a value.
I was thinking of (mis)using (?) the Configuration, by just adding a new key-value pair, would this be working, and the correct approach?
Is there a way to pass along any custom value to the reducer?
the versions I'm using are: hbase: 0.94.6.1, hadoop: 1.0.4
Your problem statement is a little unclear, however I think something like this is what you are looking for.
The way I currently use to pass information to the reducer is to pass it in the configuration.
in the job setup do the following
conf.set("someName","someValue");
This will create a tag in the configuration that has name someName with value someValue. This can later be retrieved in the Mapper/Reducer by doing the following:
Configuration conf = context.getConfiguration();
String someVariable = conf.get("someName");
The current code will set the value of someVariable to "someValue", allowing the information to be passed to the reducer.
To pass multiple values use setStrings(). I haven't tested this function yet, but according to the documentation is should work with one of the following two options (the documentation is a little unclear, so try both and use whichever works):
conf.setStrings("someName","value1,value2,value3");
conf.setStrings("someName","value1","value2","value3");
retrieve using:
Configuration conf = context.getConfiguration();
String someVariable = conf.getStrings("someName");
Hope this helps
The goal is a little unclear, but I have found that for many types of jobs involving HBase, you do not need a reducer to put data into HBase. The mapper reads a row, modifies it in some way, then writes it back.
Obviously there are jobs for which that is inappropriate (any type of aggregation for example), but the reduce stage can really slow down a job.
How can I change what a method is doing in Java ?
I mean, I am trying to use annotations to make the following code
#Anno1(Argument = "Option1")
public class TestClass
{
#Anno2
public void test()
{
}
}
Into
public class TestClass
{
private static StaticReference z;
public void test()
{
z.invokeToAll();
}
}
This is a very simplified example of what I am trying to do. Anno1 will have many possible combinations, but this is not my problem so far. My problem is how to add code to method test()
I am looking for a more generic solution if possible. Eg. A way to add every kind of code in the method (not just a way to .invokeToAll())
So far I am using import javax.annotation.processing.*; and I have the following code, but I don't know how to go on from there
private void processMethodAnnotations(RoundEnvironment env)
{
for (Element e : env.getElementsAnnotatedWith(Anno2.class))
{
//If it is a valid annotation over a method
if (e.getKind() == ElementKind.METHOD)
{
//What to do here :S
}else
{
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,"Not a method!", e);
}
}
}
I have found something about Java Reflection but I have not found any source to help me with what I am doing.
Obviously I extends AbstractProcessor in my code
I have found this tutorial (http://www.zdnetasia.com/writing-and-processing-custom-annotations-part-3-39362483.htm) But this concerns creating a new class, not just changing a method. and the javax.lang.model.elements do not provide any way of editing that element (which in my case represents a Method).
I hope my question is clear and inline with the rules. If not please comment and I will clarify. Thanks.
Annotation processing is the wrong way to go for you, from Wikipedia:
When Java source code is compiled,
annotations can be processed by
compiler plug-ins called annotation
processors. Processors can produce
informational messages or create
additional Java source files or
resources, which in turn may be
compiled and processed, but annotation
processors cannot modify the annotated
code itself.
People suggested to you the right way - AOP. Specifically, you can use AspectJ. "Quick result" way is (if you use Eclipse):
Install AJDT (AspectJ Development Tools)
Create an AspectJ project and add there your classes and annotations
Create Aspect:
public aspect Processor {
private StaticReference z;
pointcut generic()
// intercept execution of method named test, annotated with #Anno1
// from any class type, annotated with #Anno2
: execution(#Anno2 * (#Anno1 *).test())
// method takes no arguments
&& args ();
// here you have written what you want the method to actually do
void around () : generic() {
z.invokeToAll();
}
}
now you can execute a test and you will see that it works ;) AJDT compiles code for you automatically, so do not need any manual work to do, hope that's what you called "magic" ;)
UPDATE:
if your code in the test() method depends on the Anno1 annotation value, then inside aspect you can get class annotation for which it is executed this way:
void around () : generic() {
Annotation[] classAnnotations = thisJoinPoint.getThis().getClass().getAnnotations();
String ArgumentValue = null;
for ( Annotation annotation : classAnnotations ) {
if ( annotation instanceof Anno1 ) {
ArgumentValue = ((Anno1) annotation).Argument();
break;
}
}
if ( ArgumentValue != null && ArgumentValue.equals("Option1")) {
z.invokeToAll();
}
}
where thisJoinPoint is a special reference variable.
UPDATE2:
if you want to add System.out.println( this ) in your aspect, you need to write there System.out.println( thisJoinPoint.getThis() ), just tested and it works. thisJoinPoint.getThis() returns you "this" but not exactly; in fact this is Object variable and if you want to get any propery you need either to cast or to use reflection. And thisJoinPoint.getThis() does not provide access to private properties.
Well, now seems that your question is answered, but if I missed anything, or you get additional question/problems with this way - feel free to ask ;)
It's perfectly possible to do what you ask, although there is a caveat: relying on private compiler APIs. Sounds scary, but it isn't really (compiler implementations tend to be stable).
There's a paper that explains the procedure: The Hacker's Guide to Javac.
Notably, this is used by Project Lombok to provide automatic getter/setter generation (amongst other things). The following article explains how it does it, basically re-iterating what is said the aforementioned paper.
Well, you might see if the following boilerplate code will be useful:
public void magic(Object bean, String[] args) throws Exception {
for (Method method : bean.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(Anno2.class)) {
// Invoke the original method
method.invoke(bean, args);
// Invoke your 'z' method
StaticReference.invokeAll();
}
}
}
As an alternative your might employ aspect oriented programming, for instance you have the AspectJ project.
I'm not sure at all if it is even possible to change the source or byte code via annotations. From what your describing it looks as if aspect oriented programming could provide a solution to your problem.
Your annotations are pretty similiar to the pointcut concept (they mark a location where code needs to be inserted) and the inserted code is close the advice concept.
Another approach would be parsing the java source file into an abstract syntax tree, modify this AST and serialize to a java compiler input.
If your class extends a suitable interface, you could wrap it in a DynamicProxy, which delegates all calls to the original methods, except the call to test.