Is there a way to use Spring SpEL inside a method to get a .properties value? - spring-el

I have a scheduled task class with #Component annotation. I have this successfully pulling data from the .properties file for the delay time, but I'd like to use that same value later INSIDE the method.
#Scheduled(fixedDelayString = "${mypropvalue}")
public void doScheduledTask () throws IOException
{
// do some stuff
log.info("The doScheduledTask finished at {} ", dateFormat.format(new Date()));
log.info("The next task will run in {} ms", #Value("${mypropvalue}"));
}
The #Value on the last line has a compile error saying "Annotations are not allowed here". How can I get that value again from inside the method? And since I am using #Scheduled, I cannot pass in that #Value as a parameter.

Add it as a field
#Value("${mypropvalue}
private long fixedDelay
then
this.fixedDelay
within your method.

Related

How to set timeout for TestNG's #BeforeSuite method thru a Listener class

I would like to set some timeout for a BeforeSuite method through a Listener class. I could not find help for this. (Am using Selenium WebDriver)
I have so many test suites, we've set timeout for each of the tests & would like to restrict the time for the BeforeSuite method as well.
I would like to set it through a Listener instead of adding it in each suite.
#BeforeSuite(groups = {"aa-bb-cc"})
public void abcdef(ITestContext context) throws Exception {
....}
#AfterSuite(groups = {"aa-bb-cc"})
public void cleanup() {
quitDriver();
}
How can I set timeouts using a listener for the above 2methods (instead of hardcoding the timeout like #BeforeSuite(groups = {"aa-bb-cc"}, timeOut=600000))
You can use org.testng.IAnnotationTransformer2
Documentation,
Java Doc IAnnotationTransformer2
Use this interface instead of IAnnotationTransformer if you want to
modify any TestNGannotation besides #Test.
You will need to override method having parameter IConfigurationAnnotation
#Override
public void transform(IConfigurationAnnotation annotation, Class testClass,
Constructor testConstructor, Method testMethod) {
annotation.setTimeOut(10);
}

Non Serializable object in Apache Flink

I am using Apache Flink to perform analytics on streaming data.
I am using a dependency whose object takes more than 10 secs to create as it is reads several files present in hdfs before initialisation.
If I initialise the object in open method I get a timeout Exception and if in the constructor of a sink/flatmap, I get serialisation exception.
Currently I am using static block to initialise the object in some other class, using Preconditions.checkNotNull(MGenerator.mGenerator) in main file and then it's working if used in a flatmap of sink.
Is there a way to create a non serializable dependency's object which might take more than 10 secs to be initialised in Flink's flatmap or sink?
public class DependencyWrap {
static MGenerator mGenerator;
static {
final String configStr = "{}";
final Config config = new Gson().fromJson(config, Config.class);
mGenerator = new MGenerator(config);
}
}
public class MyStreaming {
public static void main(String[] args) throws Exception {
Preconditions.checkNotNull(MGenerator.mGenerator);
final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(parallelism);
...
input.flatMap(new RichFlatMapFunction<Map<String,Object>,List<String>>() {
#Override
public void open(Configuration parameters) {
}
#Override
public void flatMap(Map<String,Object> value, Collector<List<String>> out) throws Exception {
out.collect(MFVGenerator.mfvGenerator.generateMyResult(value.f0, value.f1));
}
});
}
}
Also, Please correct me if I am wrong about the question.
Doing it in the Open method is 100% the right way to do it. Is Flink giving you a timeout exception, or the object?
As a last ditch method, you could wrap your object in a class that contains both the object and it's JSON string or Config (is Config serializable?) with the object marked transient and then override the ReadObject/WriteObject methods to call the constructor. If the mGenerator object itself is stateless (and you'll have other problems if it's not), the serialization code should get called only once when jobs are distributed to taskmanagers.
Using open is usually the right place to load external lookup sources. The timeout is a bit odd, maybe there is a configuration around it.
However, if it's huge using a static loader (either static class as you did or singleton) has the benefit that you only need to load it once for all parallel instances of the task on the same task manager. Hence, you save memory and CPU time. This is especially true for you, as you use the same data structure in two separate tasks. Further, the static loader can be lazily initialized when it's used for the first time to avoid the timeout in open.
The clear downside of this approach is that the testability of your code suffers. There are some ways around that, which I could expand if there is interest.
I don't see a benefit of using the proxy serializer pattern. It's unnecessarily complex (custom serialization in Java) and offers little benefit.

How to pass parameters to a Camel route?

It is possible to pass parameters to a Camel route?, for instance, in the next code snippet:
public class MyRoute extends RouteBuilder {
public void configure() throws Exception {
from("direct:start")
.to("cxf:bean:inventoryEndpoint?dataFormat=PAYLOAD");
}
}
The value for dataFormat is in hard code, but, what if I want set it dynamically?, passing a value from the code where route is called. I know this is possible adding a constructor and passing parameters in it, like this:
public class MyRoute extends RouteBuilder {
private String type;
public MyRoute(String type){
this.type = type;
}
public void configure() throws Exception {
from("direct:start")
.to("cxf:bean:inventoryEndpoint?dataFormat=" + type);
}
}
There is another way?
Thanks so much!
As you mentioned, you can use a constructor (or setters or any other Java/Framework instruments) if the parameters are static from a Camel point of view.
The parameters are configurable in the application, but after the application is started they do no more change. So, every message processed by the Camel route uses the same value.
In contrast, when the parameters are dynamic - i.e. they can change for every processed message, you can use the dynamic endpoint toD() of Camel. These endpoint addresses can contain expressions that are computed on runtime. For example the route
from("direct:start")
.toD("${header.foo}");
sends messages to a dynamic endpoint and takes the value from the message header named foo.
Or to use your example
.toD("cxf:bean:inventoryEndpoint?dataFormat=${header.dataFormat}");
This way you can set the dataformat for every message individually through a header.
You can find more about dynamic endpoints on this Camel documentation page

Hystrix Javanica : Call always returning result from fallback method.(java web app without spring)

I am trying to integrate Hystrix javanica into my existing java EJB web application and facing 2 issues with running it.
When I try to invoke following service it always returns response from fallback method and I see that the Throwable object in fallback method has "com.netflix.hystrix.exception.HystrixTimeoutException" exception.
Each time this service is triggered, HystrixCommad and fallback methods are called multiple times around 50 times.
Can anyone suggest me with any inputs? Am I missing any configuration?
I am including following libraries in my project.
project libraries
I have setup my aspect file as follows:
<aspectj>
<weaver options="-verbose -showWeaveInfo"></weaver>
<aspects>
<aspect name="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"/>
</aspects>
</aspectj>
Here is my config.properties file in META-INF/config.properties
hystrix.command.default.execution.timeout.enabled=false
Here is my rest service file
#Path("/hystrix")
public class HystrixService {
#GET
#Path("clusterName")
#Produces({ MediaType.APPLICATION_JSON })
public Response getClusterName(#QueryParam("id") int id) {
ClusterCmdBean clusterCmdBean = new ClusterCmdBean();
String result = clusterCmdBean.getClusterNameForId(id);
return Response.ok(result).build();
}
}
Here is my bean class
public class ClusterCmdBean {
#HystrixCommand(groupKey = "ClusterCmdBeanGroup", commandKey = "getClusterNameForId", fallbackMethod = "defaultClusterName")
public String getClusterNameForId(int id) {
if (id > 0) {
return "cluster"+id;
} else {
throw new RuntimeException("command failed");
}
}
public String defaultClusterName(int id, Throwable e) {
return "No cluster - returned from fallback:" + e.getMessage();
}
}
Thanks for the help.
If you want to ensure you are setting the property, you can do that explicitly in the circuit annotation itself:
#HystrixCommand(commandProperties = {
#HystrixProperty(name = "execution.timeout.enabled", value = "false")
})
I would only recommend this for debugging purposes though.
Something that jumps out to me is that Javanica uses AspectJ AOP, which I have never seen work with new MyBean() before. I've always have to use #Autowired with Spring or similar to allow proxying. This could well just be something that is new to me though.
If you set a breakpoint inside the getClusterNameForId can you see in the stack trace that its being called via reflection (which it should be AFAIK)?
Note you can remove commandKey as this will default to the method name. Personally I would also remove groupKey and let it default to the class name.

Put modified xml back into the message?

I'm using CXF to send messages with SOAP over JMS.
I'm trying to write a CXF Interceptor in the POST_MARSHALL phase.
I want to change some attributes when the xml is generated.
I know i can get the content from the message via
message.getContent(java.io.Writer.class).
This happens to be in the form of JMSConduit$1. Which - I think - is a StringWriter (if I debug my code I can see a buf field).
I can get the xml in String format and make my changes, but the problems is putting it back in the message.
I can not change the JMSConduit$1 to something else, otherwise CXF won't send it to the JMS Endpoint. (it must be a JMSConduit).
I can't find a way to put the modified xml back in a JMSConduit, which i can get through
message.getExchange().getConduit();
So, how can I put my modified xml back into the message/JMSConduit?
Finally found an answer. I used a FilterWriter.
public void handleMessage(Message message) throws Fault {
final Writer writer = message.getContent(Writer.class);
message.setContent(Writer.class, new OutWriter(message, writer));
}
class OutWriter extends FilterWriter {
#Override
public void close() throws IOException {
// Modify String (in xml form).
message.setContent(Writer.class, out);
}
}

Resources