No Result sent after onError() in the Play Framework - java

I am using Play 2.2.1.
In my Global class I have the onError()-method overridden like this:
public Promise<SimpleResult> onError(RequestHeader request, Throwable t) {
Logger.info("onError reached");
return Promise.<SimpleResult>pure(internalServerError(t.getMessage()));
}
Thus my code is only slightly modified compared to the documentation.
After an exception occurs, it appears in the logging and the "onError reached" is also logged. Nevertheless it seems that the Result is never sent to the client as it is still waiting for an answer.
How do I send the internalServerError-Result back to the client if an error occured?
As a workaround I do the following:
public static Result someAction() {
try{
...
} catch (Exception ex) {
Logger.error(ex.getMessage(), ex);
return internalServerError(ex.getMessage());
}
}
I would really like to avoid that, because I think it's ugly, but at least it seems to work. Are there any possible problems (except that it has to be repeated for every Action) with that approach?

Just rechecked and it worked for me.
One minor issue I noticed - your return statement in onError lacks a closing brace, but I suppose it is not the issue since your code compiles.
Here's my working code:
controller:
package controllers;
import play.mvc.*;
public class Application extends Controller {
public static Result index() {
throw new RuntimeException("boom!");
}
}
Global:
import play.GlobalSettings;
import play.Logger;
import play.libs.F.Promise;
import play.mvc.Http.RequestHeader;
import play.mvc.Results;
import play.mvc.SimpleResult;
public class Global extends GlobalSettings {
public Promise<SimpleResult> onError(RequestHeader request, Throwable t) {
Logger.info("onError reached");
return Promise.<SimpleResult> pure(Results.internalServerError(t.getMessage()));
}
}

Related

How do I test code calling static factory methods with or without Mocks?

I have a dilemma trying to solve the following test. The class is a toggle created through the Togglz library. I'm catching the feature manager method execution because I'm using a JDBCStateReporsitory to read the toggle value and if something goes wrong with the DB I have to be able to return the default value of the toggle with the #EnabledByDefault annotation.
#Slf4j
public enum PocToggle {
#EnabledByDefault
USE_MY_FEATURE;
public boolean isActive() {
FeatureManager featureManager = FeatureContext.getFeatureManager();
try {
return featureManager.isActive(this);
} catch (RuntimeException ignored) {
if (log.isWarnEnabled()) {
log.warn(String.format("Failed to retrieve feature '%s' state", this.name()));
}
FeatureMetaData metaData = featureManager.getMetaData(this);
FeatureState featureState = metaData.getDefaultFeatureState();
return featureState.isEnabled();
}
}
}
I have no clue of how to do it because an object created by an inner utility static method doesn't allow me to Stub or Mock it. I just created the true and false paths of the test, but the test trying to cover the exception path is not working throwing me a Expected exception of type 'java.lang.IllegalStateException', but no exception was thrown message.
class PocToggleSpecification extends Specification {
#Rule
private TogglzRule toggleRule = TogglzRule.allEnabled(PocToggle.class)
def "Should toggle to use my feature when it is enabled"() {
when:
toggleRule.enable(USE_MY_FEATURE)
then:
USE_MY_FEATURE.isActive()
}
def "Should toggle to not to use my feature when it is disabled"() {
when:
toggleRule.disable(USE_MY_FEATURE)
then:
!USE_MY_FEATURE.isActive()
}
def "Should throw an exception when something goes wrong"() {
given:
toggleRule.enable(USE_MY_FEATURE)
FeatureManager featureManager = Stub()
featureManager.isActive() >> { throw new IllegalStateException() }
def featureContext = Spy(FeatureContext)
featureContext.getFeatureManager() >> featureManager
when:
USE_MY_FEATURE.isActive()
then:
thrown IllegalStateException
}
}
Could you please help me to solve this kind of test?
Well, first of all your test would not run as expected because your toggle class catches runtime exceptions and IllegalStateException is a runtime exception, so it will never be thrown.
Secondly, Spock cannot mock static methods for Java classes, only for Groovy classes.
So if you do not want to fiddle around with PowerMock inside of Spock - mocking static methods is always a bad smell - you still have the option of making your toggle class more testable by making the feature manager injectable via a package-scoped setter method and then use that method from the test. Try this example:
package de.scrum_master.stackoverflow;
import org.togglz.core.Feature;
import org.togglz.core.annotation.EnabledByDefault;
import org.togglz.core.context.FeatureContext;
import org.togglz.core.manager.FeatureManager;
import org.togglz.core.metadata.FeatureMetaData;
import org.togglz.core.repository.FeatureState;
public enum PocToggle implements Feature {
#EnabledByDefault
USE_MY_FEATURE;
private FeatureManager customFeatureManager;
void setFeatureManager(FeatureManager featureManager) {
this.customFeatureManager = featureManager;
}
public boolean isActive() {
FeatureManager featureManager = customFeatureManager != null
? customFeatureManager
: FeatureContext.getFeatureManager();
try {
return featureManager.isActive(this);
} catch (RuntimeException ignored) {
System.err.println(String.format("Failed to retrieve feature '%s' state", this.name()));
FeatureMetaData metaData = featureManager.getMetaData(this);
FeatureState featureState = metaData.getDefaultFeatureState();
return featureState.isEnabled();
}
}
}
package de.scrum_master.stackoverflow
import org.junit.Rule
import org.togglz.junit.TogglzRule
import org.togglz.testing.TestFeatureManager
import spock.lang.Specification
import static PocToggle.USE_MY_FEATURE
class PocToggleTest extends Specification {
#Rule
TogglzRule toggleRule = TogglzRule.allEnabled(PocToggle.class)
def "Feature is active when enabled"() {
when:
toggleRule.enable(USE_MY_FEATURE)
then:
USE_MY_FEATURE.isActive()
}
def "Feature is inactive when disabled"() {
when:
toggleRule.disable(USE_MY_FEATURE)
then:
!USE_MY_FEATURE.isActive()
}
def "Feature defaults to active upon feature manager error"() {
setup: "inject error-throwing feature manager into Togglz rule"
def featureManagerSpy = Spy(TestFeatureManager, constructorArgs: [PocToggle]) {
isActive(_) >> { throw new IllegalStateException() }
}
when: "feature is disabled and feature manager throws an error"
toggleRule.disable(USE_MY_FEATURE)
USE_MY_FEATURE.featureManager = featureManagerSpy
then: "feature is reported to be active by default"
USE_MY_FEATURE.isActive()
cleanup: "reset Togglz rule feature manager"
USE_MY_FEATURE.featureManager = null
}
}
Running the last test, you will see the log message Failed to retrieve feature 'USE_MY_FEATURE' state as expected. My test coverage tool also shows that it works:
Update 2018-01-17: solution variant using PowerMock (tested with 1.6.6 and 1.7.3)
Okay, I needed PowerMock for another reason and quickly gave your code a spin.
Disclaimer: I do prefer the first solution above, i.e. refactoring with regard to dependency injection instead of dirty tricks with PowerMock, but for what it is worth, here is how to do it.
The Java class has the dependency injection removed again, should be identical to the OP's original code.
package de.scrum_master.stackoverflow;
import org.togglz.core.Feature;
import org.togglz.core.annotation.EnabledByDefault;
import org.togglz.core.context.FeatureContext;
import org.togglz.core.manager.FeatureManager;
import org.togglz.core.metadata.FeatureMetaData;
import org.togglz.core.repository.FeatureState;
public enum PocToggle implements Feature {
#EnabledByDefault
USE_MY_FEATURE;
public boolean isActive() {
FeatureManager featureManager = FeatureContext.getFeatureManager();
try {
return featureManager.isActive(this);
} catch (RuntimeException ignored) {
System.err.println(String.format("Failed to retrieve feature '%s' state", this.name()));
FeatureMetaData metaData = featureManager.getMetaData(this);
FeatureState featureState = metaData.getDefaultFeatureState();
return featureState.isEnabled();
}
}
}
See PowerMock wiki for an explanation. BTW, Sputnik is Spock's JUnit runner.
package de.scrum_master.stackoverflow
import org.junit.Rule
import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import org.powermock.modules.junit4.PowerMockRunnerDelegate
import org.spockframework.runtime.Sputnik
import org.togglz.core.context.FeatureContext
import org.togglz.junit.TogglzRule
import org.togglz.testing.TestFeatureManager
import spock.lang.Specification
import static PocToggle.USE_MY_FEATURE
import static org.powermock.api.mockito.PowerMockito.mockStatic
import static org.powermock.api.mockito.PowerMockito.when
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(Sputnik.class)
#PrepareForTest([FeatureContext.class])
class PocToggleTest extends Specification {
#Rule
TogglzRule toggleRule = TogglzRule.allEnabled(PocToggle.class)
// ...
def "Feature defaults to active upon feature manager error (power-mocked)"() {
setup: "inject error-throwing feature manager into Togglz rule"
def featureManagerSpy = Spy(TestFeatureManager, constructorArgs: [PocToggle]) {
isActive(_) >> { throw new IllegalStateException() }
}
mockStatic(FeatureContext)
when(FeatureContext.getFeatureManager()).thenReturn(featureManagerSpy)
when: "feature is disabled and feature manager throws an error"
toggleRule.disable(USE_MY_FEATURE)
then: "feature is reported to be active by default"
USE_MY_FEATURE.isActive()
}
}
Update 2 (2018-01-19): I want to mention one more issue: Maybe you noticed that I use a Spy instead of a Stub or Mock. This is because your code catches an exception thrown by the feature manager (FM), but then in the catch block uses the FM again. This can be dangerous because if the FM is broken due to network or database failure, it might also fail upon your next call. So while the test gives you 100% code coverage, it does not guarantee that your application behaves as expected in production or that you are testing the right thing.
I think that the reason is that since the method FeatureContext.getFeatureManager() is static, you just can't place a spy, if you'll put a breakpoint at the line of creation of FeatureManager stub inside the test and check out in debugger the address of the created object, and then place a breakpoint in a line inside the test that tries to use this feature manager, you'll see that these are two different objects, so the expectation to throw an exception is not applicable here.
In terms of a solution:
I suggest getting rid of static code as much as you can since it's not really unit testable. For example, you could create an interface like this (ok you use enum here, but it could be easily refactored to a class used from within an enum so that you could test it):
public interface FeatureManagerProvider {
FeatureManager getFeatureManager();
}
public class DefaultFeatureManagerProviderImpl implements FeatureManagerProvider {
.... // inject this in real use cases
}
With this abstraction, the code could be refactored like this:
public class Activator {
private FeatureManagerProvider featureManagerProvider;
public Activator(FeatureManagerProvider provider) {
this.featureManagerProvider = provider;
}
public boolean isActive() {
...
FeatureManager fm = featureManagerProvider.getFeatureManager();
...
}
}
During the test, you could supply a stub for FeatureManagerProvider and check all the interactions.

JUnit5 - How to get test result in AfterTestExecutionCallback

I write JUnit5 Extension. But I cannot find way how to obtain test result.
Extension looks like this:
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.TestExtensionContext;
public class TestResultExtension implements AfterTestExecutionCallback {
#Override
public void afterTestExecution(TestExtensionContext context) throws Exception {
//How to get test result? SUCCESS/FAILED
}
}
Any hints how to obtain test result?
This work for me:
public class RunnerExtension implements AfterTestExecutionCallback {
#Override
public void afterTestExecution(ExtensionContext context) throws Exception {
Boolean testResult = context.getExecutionException().isPresent();
System.out.println(testResult); //false - SUCCESS, true - FAILED
}
}
#ExtendWith(RunnerExtension.class)
public abstract class Tests {
}
As other answers point out, JUnit communicates failed tests with exceptions, so an AfterTestExecutionCallback can be used to gleam what happened. Note that this is error prone as extension running later might still fail the test.
Another way to do that is to register a custom TestExecutionListener. Both of these approaches are a little roundabout, though. There is an issue that tracks a specific extension point for reacting to test results, which would likely be the most straight-forward answer to your question. If you can provide a specific use case, it would be great if you could head over to #542 and leave a comment describing it.
You can use SummaryGeneratingListener from org.junit.platform.launcher.listeners
It contains MutableTestExecutionSummary field, which implements TestExecutionSummary interface, and this way you can obtain info about containers, tests, time, failures etc.
You can create custom listener, for example:
Create class that extends SummaryGeneratingListener
public class ResultAnalyzer extends SummaryGeneratingListener {
#Override
public void testPlanExecutionFinished(TestPlan testPlan) {
//This method is invoked after all tests in all containers is finished
super.testPlanExecutionFinished(testPlan);
analyzeResult();
}
private void analyzeResult() {
var summary = getSummary();
var failures = summary.getFailures();
//Do something
}
}
Register listener by creating file
src\main\resources\META-INF\services\org.junit.platform.launcher.TestExecutionListener
and specify your implementation in it
path.to.class.ResultAnalyzer
Enable auto-detection of extensions, set parameter
-Djunit.jupiter.extensions.autodetection.enabled=true
And that's it!
Docs
https://junit.org/junit5/docs/5.0.0/api/org/junit/platform/launcher/listeners/SummaryGeneratingListener.html
https://junit.org/junit5/docs/5.0.0/api/org/junit/platform/launcher/listeners/TestExecutionSummary.html
https://junit.org/junit5/docs/current/user-guide/#extensions-registration-automatic
I have only this solution:
String testResult = context.getTestException().isPresent() ? "FAILED" : "OK";
It seems that it works well. But I am not sure if it will work correctly in all situations.
Fails in JUnit are propagated with exceptions. There are several exceptions, which indicate various types of errors.
So an exception in TestExtensionContext#getTestException() indicates an error. The method can't manipulate actual test results, so depending on your use case you might want to implement TestExecutionExceptionHandler, which allows you to swallow exceptions, thus changing whether a test succeeded or not.
You're almost there.
To implement a test execution callback and get the test result for logging (or generating a report) you can do the following:
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
public class TestResultExtension implements AfterTestExecutionCallback
{
#Override
public void afterTestExecution(ExtensionContext context) throws Exception
{
// check the context for an exception
Boolean passed = context.getExecutionException().isEmpty();
// if there isn't, the test passed
String result = passed ? "PASSED" : "FAILED";
// now that you have the result, you can do whatever you want
System.out.println("Test Result: " + context.getDisplayName() + " " + result);
}
}
And then you just add the TestResultExtension using the #ExtendWith() annotation for your test cases:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.junit.jupiter.api.Assertions.assertTrue;
#ExtendWith(TestResultExtension.class)
public class SanityTest
{
#Test
public void testSanity()
{
assertTrue(true);
}
#Test
public void testInsanity()
{
assertTrue(false);
}
}
It's a good idea to extend a base test that includes the extension
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(TestResultExtension.class)
public class BaseTest
{}
And then you don't need to include the annotation in every test:
public class SanityTest extends BaseTest
{ //... }

How to get the exception that was thrown when a Cucumber test failed in Java?

I can perform actions on test failure by using:
#After
public void afterTest(Scenario scenario) {
if (scenario.isFailed()) {
/*Do stuff*/
}
}
However some of the actions I need to perform depend on the Exception that was thrown and in what context it was thrown. Is there a way to get the Throwable that caused the test to fail? For example in JUnit I would do this by extending TestWatcher and add a rule to my tests:
#Override
protected void failed(Throwable e, Description description) {
/*Do stuff with e*/
}
However the cucumber-junit iplementation does not allow the use of rules, so this solution would not work with Cucumber.
I don't think I need to explain why accessing a thrown exception on test failure would be useful, however I will still provide an Example:
My test environment is not always stable, so my tests might fail unexpectedly at any moment (there's no specific place I can try to catch the exception since it could occur at any time). When this happens I need the test to reschedule for another attempt, and log the incident so that we can get some good statistical data on the environment instability (when, how frequent, how long etc.)
The problem with the work around suggested by Frank Escobar:
By using reflection to reach into a frameworks internals you're depending on implementation details. This is a bad practice, when ever the framework changes its implementation your code may break as you will observe in Cucumber v5.0.0.
Hooks in Cucumber are designed to manipulate the test execution context before and after a scenario. They're not made to report on the test execution itself. Reporting is cross cutting concern and best managed by using the plugin system.
For example:
package com.example;
import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.event.EventPublisher;
import io.cucumber.plugin.event.Result;
import io.cucumber.plugin.event.Status;
import io.cucumber.plugin.event.TestCase;
import io.cucumber.plugin.event.TestCaseFinished;
public class MyTestListener implements ConcurrentEventListener {
#Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseFinished.class, this::handleTestCaseFinished);
}
private void handleTestCaseFinished(TestCaseFinished event) {
TestCase testCase = event.getTestCase();
Result result = event.getResult();
Status status = result.getStatus();
Throwable error = result.getError();
String scenarioName = testCase.getName();
String id = "" + testCase.getUri() + testCase.getLine();
System.out.println("Testcase " + id + " - " + status.name());
}
}
When using JUnit 4 and TestNG you can activate this plugin using:
#CucumberOptions(plugin="com.example.MyTestListener")
With JUnit 5 you add it to junit-platform.properties:
cucumber.plugin=com.example.MyTestListener
Or if you are using the CLI
--plugin com.example.MyTestListener
I've implemented this method using reflections. You can't access directly to steps errors (stack trace). I've created this static method which allows you to access to "stepResults" attribute and then you can iterate and get the error and do whatever you want.
import cucumber.runtime.ScenarioImpl;
import gherkin.formatter.model.Result;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
#After
public void afterScenario(Scenario scenario) {
if (scenario.isFailed())
logError(scenario);
}
private static void logError(Scenario scenario) {
Field field = FieldUtils.getField(((ScenarioImpl) scenario).getClass(), "stepResults", true);
field.setAccessible(true);
try {
ArrayList<Result> results = (ArrayList<Result>) field.get(scenario);
for (Result result : results) {
if (result.getError() != null)
LOGGER.error("Error Scenario: {}", scenario.getId(), result.getError());
}
} catch (Exception e) {
LOGGER.error("Error while logging error", e);
}
}
You can to this by writing your own custom implementation of Formatter & Reporter interface. The empty implementation of Formatter is the NullFormatter.java which you can extend. You will need to provide implementations for the Reporter interface.
The methods which would be of interest will be the result() of the Reporter interface and possibly the done() method of Formatter. The result() has the Result object which has the exceptions.
You can look at RerunFormatter.java for clarity.
Github Formatter source
public void result(Result result) {
//Code to create logs or store to a database etc...
result.getError();
result.getErrorMessage();
}
You will need to add this class(com.myimpl.CustomFormRep) to the plugin option.
plugin={"pretty", "html:report", "json:reports.json","rerun:target/rerun.txt",com.myimpl.CustomFormRep}
More details on custom formatters.
You can use the rerun plugin to get a list of failed scenarios to run again. Not sure about scheduling a run of failed tests, code to create a batch job or schedule one on your CI tool.
This is the workaround for cucumber-java version 4.8.0 using reflection.
import cucumber.api.Result;
import io.cucumber.core.api.Scenario;
import io.cucumber.core.logging.Logger;
import io.cucumber.core.logging.LoggerFactory;
import io.cucumber.java.After;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
#After
public void afterScenario(Scenario scenario) throws IOException {
if(!scenario.getStatus().isOk(true)){
logError(scenario);
}
}
private static void logError(Scenario scenario) {
try {
Class clasz = ClassUtils.getClass("cucumber.runtime.java.JavaHookDefinition$ScenarioAdaptor");
Field fieldScenario = FieldUtils.getField(clasz, "scenario", true);
fieldScenario.setAccessible(true);
Object objectScenario = fieldScenario.get(scenario);
Field fieldStepResults = objectScenario.getClass().getDeclaredField("stepResults");
fieldStepResults.setAccessible(true);
ArrayList<Result> results = (ArrayList<Result>) fieldStepResults.get(objectScenario);
for (Result result : results) {
if (result.getError() != null) {
LOGGER.error(String.format("Error Scenario: %s", scenario.getId()), result.getError());
}
}
} catch (Exception e) {
LOGGER.error("Error while logging error", e);
}
}
For cucumber-js https://www.npmjs.com/package/cucumber/v/6.0.3
import { After } from 'cucumber'
After(async function(scenario: any) {
const exception = scenario.result.exception
if (exception) {
this.logger.log({ level: 'error', message: '-----------StackTrace-----------' })
this.logger.log({ level: 'error', message: exception.stack })
this.logger.log({ level: 'error', message: '-----------End-StackTrace-----------' })
}
})
After a lot of experimentation I now removed the Before/After-Annotations and rely on Cucumber-Events instead. They contain the TestCase (which is what the Scenario-class wraps) and a Result where you can call getError(); to get the Throwable.
Here is a simple example to get it working
import io.cucumber.plugin.EventListener;
import io.cucumber.plugin.event.EventPublisher;
import io.cucumber.plugin.event.Result;
import io.cucumber.plugin.event.Status;
import io.cucumber.plugin.event.TestCase;
import io.cucumber.plugin.event.TestCaseFinished;
import io.cucumber.plugin.event.TestCaseStarted;
import org.openqa.selenium.WebDriver;
public class TestCaseListener implements EventListener {
#Override
public void setEventPublisher(final EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseStarted.class, this::onTestCaseStarted);
publisher.registerHandlerFor(TestCaseFinished.class, this::onTestCaseFinished);
}
public void onTestCaseStarted(TestCaseStarted event) {
TestCase testCase = event.getTestCase();
System.out.println("Starting " + testCase.getName());
// Other stuff you did in your #Before-Method.
// ...
}
private void onTestCaseFinished(final TestCaseFinished event) {
TestCase testCase = event.getTestCase();
System.out.println("Finished " + testCase.getName());
Result result = event.getResult();
if (result.getStatus() == Status.FAILED) {
final Throwable error = result.getError();
error.printStackTrace();
}
// Other stuff you did in your #After-Method.
// ...
}
}
All that's left to do is to register this class as a Cucumber-Plugin.
I did this by modifying my #CucumberOptions-annotation:
#CucumberOptions(plugin = {"com.example.TestCaseListener"})
I find this much cleaner than all of this reflection-madness, however it requires a lot more code-changes.
Edit
I don't know why, but this caused a lot of tests to randomly fail in a multithreaded environment.
I tried to figure it out, but now also use the ugly reflections mentioned in this thread:
public class SeleniumUtils {
private static final Logger log = LoggerFactory.getLogger(SeleniumUtils.class);
private static final Field field = FieldUtils.getField(Scenario.class, "delegate", true);
private static Method getError;
public static Throwable getError(Scenario scenario) {
try {
final TestCaseState testCase = (TestCaseState) field.get(scenario);
if (getError == null) {
getError = MethodUtils.getMatchingMethod(testCase.getClass(), "getError");
getError.setAccessible(true);
}
return (Throwable) getError.invoke(testCase);
} catch (Exception e) {
log.warn("error receiving exception", e);
}
return null;
}
}
If you just want to massage the result being sent to the report then you can extend the CucumberJSONFormatter and override the result method like this:
public class CustomReporter extends CucumberJSONFormatter {
CustomReporter(Appendable out) {
super(out);
}
/**
* Truncate the error in the output to the testresult.json file.
* #param result the error result
*/
#Override
void result(Result result) {
String errorMessage = null;
if (result.error) {
errorMessage = "Error: " + truncateError(result.error);
}
Result myResult = new Result(result.status, result.duration, errorMessage);
// Log the truncated error to the JSON report
super.result(myResult);
}
}
Then set the plugin option to:
plugin = ["com.myimpl.CustomReporter:build/reports/json/testresult.json"]

Standalone Apache Camel application doesn' run

I'm on this problem: can't get my apache camel batch run. Here is the code:
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.Main;
public class Launch {
private Main main;
public static void main(String[] args) {
Launch l = new Launch();
System.out.println(System.getProperty("from") +" -> "+System.getProperty("to"));
try {
l.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
public void execute() throws Exception {
main = new Main();
main.enableHangupSupport();
main.addRouteBuilder(new FromFileToFile());
main.run();
}
private static class FromFileToFile extends RouteBuilder {
#Override
public void configure() throws Exception {
onException(Exception.class).handled(true).process(new Processor() {
public void process(Exchange arg0) throws Exception {
arg0.getException().printStackTrace();
}
});
from(System.getProperty("from") + "")
.filter(body().contains("DOTHIS"))
.process(new Processor() {
public void process(Exchange arg0) throws Exception {
System.out.println(arg0.getIn().getBody()
.toString());
}
}).to(System.getProperty("to"))
.to(System.getProperty("to") + ".BAK");
}
}
}
I don't want to use the Thread.sleep(...) workaround. I simply copied and modified the source stuff posted on this official docs page. When I run my dummy program using Eclipse, application simply hangs. I can't figure out what's wrong.
Your application doesn't probably hang, it just won't do anything. :)
You have defined filter that checks if Camel Message body contains word "DOTHIS". When you consume file with File consumer the body will be of type GenericFile. Then when your filter checks for that string it surely won't find it since the body is not string.
Solution: Convert file body to string first and then your filter will work and you get the result you were expecting. Conversion can be done like this
from(System.getProperty("from") + "")
.convertBodyTo(String.class, "UTF-8")
.filter(body().contains("DOTHIS"))
You might also want to increase logging level so you can get the grasp of what's going on in your route.
It was a problem about path. I passed arguments as options like this:
file://Users/francesco/..
As I'm using windows I must specify uri like this
file:///C:/Users/francesco/..
The batch doesn't hangs, it continues to poll directory for new files to consumes.

Permanent redirect with Play 2.0.x

I'm wondering how to do a permanent redirect 301 in Play framework 2.0.x for subdomains.
ex: www.example.com/* redirected to example.com/*. Anyone tried this before ?
The Global object will allow you to intercept the request. For obvious reasons you should do it with GET requests (ie. for SEO purposes), but others, like POST, PUT etc. should be created properly from the beginning in your views.
On the other hand, if it's just some app for serving common HTML pages for life production consider using some HTTP server on front of it - then you can do the trick with some rewriting rule.
import play.GlobalSettings;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;
import java.lang.reflect.Method;
public class Global extends GlobalSettings {
#Override
public Action onRequest(final Http.Request request, Method method) {
if ("GET".equals(request.method()) && "www.example.com".equals(request.host())) {
return new Action.Simple() {
public Result call(Http.Context ctx) throws Throwable {
return movedPermanently("http://example.com" + request.path());
}
};
}
return super.onRequest(request, method);
}
}
In conf/routes file
GET / controllers.Application.index(path = "")
GET /*path controllers.Application.index(path)
In apps/controllers/Application.scala
object Application extends Controller {
def index(path: String) = Action {
Redirect("http://example.com/" + path, status = MOVED_PERMANENTLY)
}
}

Categories