I just encounter a problem when using spring state machine #WithStateMachine.
#WithStateMachine just work when I use it on inner class which defined in the class annotated by #EnableStateMachine, but when I define class in other place it seems not work.
Here is my code:
#Configuration#EnableStateMachine public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {
#Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.UNPAID)
.states(EnumSet.allOf(States.class));
}
#Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.UNPAID).target(States.WAITING_FOR_RECEIVE)
.event(Events.PAY)
.and()
.withExternal()
.source(States.WAITING_FOR_RECEIVE).target(States.DONE)
.event(Events.RECEIVE);
}
#Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
throws Exception {
config
.withConfiguration()
.autoStartup(true);
}
#WithStateMachine
public class Action {
private Logger logger = LoggerFactory.getLogger(getClass());
#OnTransition(target = "UNPAID")
public void create() {
logger.info("UNPAID");
}
#OnTransition(source = "UNPAID", target = "WAITING_FOR_RECEIVE")
public void pay() {
logger.info("WAITING_FOR_RECEIVE");
}
#OnTransition(source = "WAITING_FOR_RECEIVE", target = "DONE")
public void receive() {
logger.info("DONE");
}
}}
but when I define Action in another class file, it is not work
my pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>1.2.3.RELEASE</version>
</dependency><dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
#WithStateMachine is a meta-annotation having spring #Component. Check that your Action class is either component scanned or created manually as #Bean.
Then it exist in application context and statemachine can find it.
Related
I saw in another post how manually adding the camel context and starting it should work, but it hasn't for me. I double checked the from, and to paths and they seem to be correct. Not sure why it's not calling the method and would appreciate some advice
public class CsvRouteBuilder extends DdsRouteBuilder {
private CsvConverterProcessor csvConverterProcessor;
private CamelContext camelContext;
#Autowired
public CsvRouteBuilder(CsvConverterProcessor csvConverterProcessor) throws Exception {
this.csvConverterProcessor = csvConverterProcessor;
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("{{input.files.csv}}")
.routeId("CSVConverter")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("hitting");
}
})
.to("{{output.files.csv}}");
}
});
camelContext.start();
}
The processor is not called simply because your route is not properly declared such that Spring Boot is not aware of it.
The proper way is to make your class extend RouteBuilder to define your route(s) and annotate your class with #Component to mark it as candidate for auto-detection when using annotation-based configuration and classpath scanning.
Your code should rather be something like this:
#Component
public class CsvRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("{{input.files.csv}}")
.routeId("CSVConverter")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("hitting");
}
})
.to("{{output.files.csv}}");
}
}
I have two-page objects called OrderSelection and OrderDetails. In addition, I have SharedState class and OrderSelectionStepDef and OrderDetailsStepDef. I declared two variables for OrderSelection and OrderDetails in SharedState. However, they are not initialized in the constructor of SharedState.
In OrderSelectionStepDef and OrderDetailsStepDef classes, I declared their constructors and pass SharedState object.
public OrderSelectionStepDef(SharedState sharedState) {
this.sharedState = sharedState;
}
public OrderDetailsStepDef(SharedState sharedState) {
this.sharedState = sharedState;
}
When I call sharedState.orderDetails within OrderDetailsStepDef or OrderSelectionStepDef a NullPointerException was thrown.
Then, I initialized OrderSelection and OrderDetails class objects in SharedState constructor. Then the issue was solved. But is this implementation ok with cucumber pico container concept?.
Step 1. OrderSelectionStepDef & OrderDetailsStepDef would look like below (please change name as per your implementation)
/**
* Step Definition implementation class for Cucumber Steps defined in Feature file
*/
public class HomePageSteps extends BaseSteps {
TestContext testContext;
public HomePageSteps(TestContext context) {
testContext = context;
}
#When("^User is on Brand Home Page (.+)$")
public void user_is_on_Brand_Home_Page(String siteName) throws InterruptedException {
homePage = new HomePage().launchBrandSite(siteName);
testContext.scenarioContext.setContext(Context.HOMEPAGE, homePage);
}
#Then("^Clicking on Sign In link shall take user to Sign In Page$")
public void clicking_on_Sign_In_link_shall_take_user_to_Sign_In_Page() {
homePage = (HomePage) testContext.scenarioContext.getContext(Context.HOMEPAGE);
signInPage = homePage.ecommSignInPageNavigation();
testContext.scenarioContext.setContext(Context.SIGNINPAGE, signInPage);
}
For your reference
public class BaseSteps {
protected HomePage homePage;
protected PLPPage plpPage;
protected PDPPage pdpPage;
protected ShoppingBagPage shoppingBagPage;
protected ShippingPage shippingPage;
More implementation goes here.....
}
Step 2. Please add below 2 Classes under your framework -
First, Java file name - ScenarioContext.java
public class ScenarioContext {
private Map<String, Object> scenarioContext;
public ScenarioContext(){
scenarioContext = new HashMap<String, Object>();
}
public void setContext(Context key, Object value) {
scenarioContext.put(key.toString(), value);
}
public Object getContext(Context key){
return scenarioContext.get(key.toString());
}
public Boolean isContains(Context key){
return scenarioContext.containsKey(key.toString());
}
}
Second, Java file name - TestContext.java
public class TestContext {
public ScenarioContext scenarioContext;
public TestContext(){
scenarioContext = new ScenarioContext();
}
public ScenarioContext getScenarioContext() {
return scenarioContext;
}
}
Step 3. POM Dependency - picocontainer shall be as per your cucumber version
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
</dependency>
Hope this helps.
I am leaning CDI Annotation have a question with respect to Produces Annotation:
I have a Bank
public interface Bank {
public void withdrawal();
public void deposit();
}
Two Implementation flavors
public class BankOfAmerica implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Bank Of America");
}
public void deposit() {
System.out.println("You are depositing in Bank Of America");
}
}
public class Chase implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Chase");
}
public void deposit() {
System.out.println("You are depositing in Chase");
}
}
A Qualifier
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankProducer {
}
An Enum
public enum BankName {
DCU(DCU.class), Chase(Chase.class), BankOfAmerica(BankOfAmerica.class);
private Class<? extends Bank> bankType;
private BankName(Class<? extends Bank> bankType) {
this.bankType = bankType;
}
public Class<? extends Bank> getBankType() {
return bankType;
}
}
An Annotation to bind the BankName
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankType {
#Nonbinding
BankName value();
}
A Factory
public class BankFactory {
#Produces
#BankProducer
public Bank createBank(#Any Instance<Bank> instance, InjectionPoint injectionPoint) {
Annotated annotated = injectionPoint.getAnnotated();
BankType bankTypeAnnotation = annotated.getAnnotation(BankType.class);
Class<? extends Bank> bankType = bankTypeAnnotation.value().getBankType();
return instance.select(bankType).get();
}
}
And a JUnit
#RunWith(Arquillian.class)
public class ProducesTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class).addPackages(true, "com.tutorial.produces")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml").merge(getDependecies());
}
private static JavaArchive getDependecies() {
JavaArchive[] javaArchives = Maven.configureResolver().loadPomFromFile("pom.xml")
.resolve("org.projectlombok:lombok").withTransitivity().as(JavaArchive.class);
JavaArchive mergedLibraries = ShrinkWrap.create(JavaArchive.class);
for (JavaArchive javaArchive : javaArchives) {
mergedLibraries.merge(javaArchive);
}
return mergedLibraries;
}
#Test
public void create() {
assertEquals(banks.getBankOfAmerica().getClass(), BankOfAmerica.class);
}
}
POM - using tomee
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0-1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>arquillian-tomee-embedded</artifactId>
<version>7.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-depchain</artifactId>
<version>2.2.2</version>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
I am getting a NullPointer exception in my factory createBank method. InjectionPoint is Null. What is the issue and how do I resolve it?
Alternate Solution: Tried Weld
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.2.8.Final</version>
</dependency>
JUnit
#RunWith(WeldJUnit4Runner.class)
public class ProducesWeldTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Test
public void create() {
assertEquals(bankOfAmerica.getClass(), BankOfAmerica.class);
}
}
WeldContext and WeldJUnit4Runner are from here -
http://memorynotfound.com/java-se-unit-testing-cdi-junit-jboss-weld-se/
As I already mentioned in my comment to the post, the CDI implememtatin seems to work. I think the problem lies in the test. Originally, I just wrote a simple test with a main() method and everything works. Now I moved the same code to the JUnit test and it still works. To test your implementation I just added the following client for your factory and a test class as follows:
public class BankClient {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
public void deposit() {
bankOfAmerica.deposit();
}
public void withdrawal() {
bankOfAmerica.withdrawal();
}
}
// JUnit test
public class BankServiceTest {
private static Weld weld = new Weld();
private static BankClient sut;
#BeforeClass
public static void initWeld() {
WeldContainer container = weld.initialize();;
sut = container.instance().select(BankClient.class).get();
}
#Test
public void deposit_should_be_invoked() {
sut.deposit();
}
#Test
public void withdrawal_should_be_called() {
sut.withdrawal();
}
#AfterClass
public static void shutDown() {
weld.shutdown();
}
}
After executing the test, you should see the following output on the console and JUnit green bar:
You are depositing in Bank Of America
You are withdrawing from Bank Of America
I am implementing a restful service in java using JAX-RS, and when testing the service it works only for one of my methods, when I add a new method with a different #PATH annotation the test web page is just blank without errors
My resource class
#Path("beer")
public class BeerResources {
#Context
private UriInfo context;
/**
* Creates a new instance of BeerResources
*/
public BeerResources() {
}
#GET
#Path("/costliest")
#Produces(MediaType.TEXT_PLAIN)
public String getCostliest() {
//TODO return proper representation object
return new BusinessLayer().getCostliest();
}
#GET
#Path("/cheapest")
#Produces(MediaType.APPLICATION_XML)
public String getCheapest() {
//TODO return proper representation object
return new BusinessLayer().getCheapest();
}
}
Application config class
#javax.ws.rs.ApplicationPath("/webresources")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(beerrestful.BeerResources.class);
}
}
You can try to use Spring Boot + JAX-RS approach or Spring Boot + Spring MVC. Here are both of them on my Github page.
Also there is Spring Boot + JAX-RS source code:
Application.java:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
new Application().configure(builder).run(args);
}
}
DrinkEndpoint.java:
#Component
#Path("/drinks")
public class DrinkEndpoint {
#Autowired
private DrinkService drinkService;
#GET
#Path("/list")
#Produces(MediaType.APPLICATION_JSON)
public Iterable<Drink> getCostliest() {
return drinkService.getDrinks();
}
#GET
#Path("/{drink}")
#Produces(MediaType.APPLICATION_JSON)
public Response getCheapest(#PathParam("drink") String name) {
Optional<Drink> drink = drinkService.getDrink(name);
if (drink.isPresent()) {
return Response.status(201).entity(drink.get().getName()).build();
} else {
return Response.status(201).entity("NOT_FOUND").build();
}
}
}
DrinkService.java:
public interface DrinkService {
Iterable<Drink> getDrinks();
Optional<Drink> getDrink(String name);
}
DrinkServiceImpl.java:
#Component
public class DrinkServiceImpl implements DrinkService {
private List<Drink> drinks = new ArrayList<Drink>() {{
add(new Drink("Coca Cola", 1886));
add(new Drink("Pepsi", 1903));
}};
public Iterable<Drink> getDrinks() {
return drinks;
}
public Optional<Drink> getDrink(String name) {
for (Drink drink : drinks) {
if (drink.getName().equalsIgnoreCase(name)) {
return Optional.of(drink);
}
}
return Optional.empty();
}
}
ApplicationConfig.java:
#Component
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(DrinkEndpoint.class);
}
}
Drink.java:
public class Drink {
private String name;
private int since;
public Drink(String name, int since) {
this.name = name;
this.since = since;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSince() {
return since;
}
public void setSince(int since) {
this.since = since;
}
}
pom.xml:
<project>
....
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
To start application run:
mvn spring-boot:run
Then open in browser:
http://localhost:8080/drinks/list
http://localhost:8080/drinks/pepsi
Make sure you are returning proper XML format
Example:
#Produces(MediaType.APPLICATION_XML)
public String getCheapest() {
return "<abc>xyz</abc>";
}
If BusinessLayer().getCheapest() function is returning String and you have used tag #Produces(MediaType.APPLICATION_XML) it will just show you a blank page.
Use appropriate MediaType in #Produces tag according to the value returned from BusinessLayer().getCheapest() function
I created this test in Jersey (from the docs), which works fine, with one problem: the #WebListener ServletContextListener is not being invoked.
The Resource classes that I need to test rely on an attribute set on the ServletContext by the ServletContextListener.
Can I make sure it is invoked, or can I manipulate the ServletContext in some other way?
public class SimpleTest extends JerseyTest {
#WebListener
public static class AppContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
System.out.println("Context initialized");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Context destroyed");
}
}
#Path("hello")
public static class HelloResource {
#GET
public String getHello() {
return "Hello World!";
}
}
#Override
protected Application configure() {
return new ResourceConfig(HelloResource.class);
}
#Test
public void test() {
final String hello = target("hello").request().get(String.class);
assertEquals("Hello World!", hello);
}
}
I added these dependencies to make this work:
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.18</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.18</version>
</dependency>
The JerseyTest needs to be set up to run in a Servlet environment, as mentioned here. Here are the good parts:
#Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
#Override
protected DeploymentContext configureDeployment() {
ResourceConfig config = new ResourceConfig(SessionResource.class);
return ServletDeploymentContext.forServlet(new ServletContainer(config))
.addListener(AppContextListener.class)
.build();
}
See the APIs for
ServletDeploymentContext and
ServletDeployementContext.Builder (which is what is returned when you call forServlet on the ServletDeploymentContext).