Set a ListMoveChange filter when using OptaPlanner Spring Boot starter - spring-boot

We are using the OptaPlanner Spring Boot starter to create a vehicle routing problem solver based on the example in the OptaPlanner quickstarts:
https://github.com/kiegroup/optaplanner-quickstarts/tree/stable/use-cases/vehicle-routing
So we do not have an solveConfig.xml file. We would like to define a filter for ListChangeMoves but it's not clear how we would register this without using an XML file. We have tried using a solverConfig.xml e.g.
<localSearch>
<unionMoveSelector>
<listChangeMoveSelector>
<filterClass>my.filter.Class</filterClass>
</listChangeMoveSelector>
</unionMoveSelector>
</localSearch>
But this is not working. Is there an example of setting up a filter for list moves?

This is a XML solver config using a a swap move selector and a change move selector with move filtering:
<constructionHeuristic/>
<localSearch>
<unionMoveSelector>
<changeMoveSelector>
<filterClass>org.acme.vehiclerouting.solver.ChangeMoveSelectorFilter</filterClass>
</changeMoveSelector>
<swapMoveSelector/>
</unionMoveSelector>
</localSearch>
If you don't want to use swap moves, then you don't need the union move selector and the configuration can be simplified to:
<constructionHeuristic/>
<localSearch>
<changeMoveSelector>
<filterClass>org.acme.vehiclerouting.solver.ChangeMoveSelectorFilter</filterClass>
</changeMoveSelector>
</localSearch>
A few comments:
I'm including the CH phase because it is necessary in a typical case. See OptaPlanner terminates immediately if I add constructionHeuristic config for an explanation.
The ChangeMoveSelector is automatically configured to produce ListChangeMoves if the planning entity has a #PlanningListVariable. There is no <listChangeMoveSelector> config element.
More information including how to implement the move selection filter can be found in the documentation.
UPDATE: No XML configuration
It's possible to inject SolverConfig, modify it and then use it to create other objects, for example Solver, SolverManager, and ScoreManager.
The code would look something like this:
#Component
class MyService {
// Don't inject these.
private final SolverManager<VrpSolution, Long> solverManager;
private final ScoreManager<VrpSolution, HardSoftScore> scoreManager;
// But inject the SolverConfig.
public MyService(SolverConfig solverConfig) {
// And instantiate SolverManager and ScoreManager manually.
this.solverManager = SolverManager.<VrpSolution, Long>create(
solverConfig.withPhaseList(Arrays.asList(
new ConstructionHeuristicPhaseConfig(),
new LocalSearchPhaseConfig().withMoveSelectorConfig(
new ChangeMoveSelectorConfig()
.withFilterClass(MyFilter.class)))));
this.scoreManager = ScoreManager.create(SolverFactory.create(solverConfig));
}
}
Pros:
SolverConfig will be initialized by OptaPlannerAutoConfiguration (from optaplanner-spring-boot-starter) before it's injected into your component. That means:
The solution and entity classes will be auto-discovered and you don't have to specify them (which you have to in solverConfig.xml).
You can use application.properties to do minor solver config tweaks, for example set time-spent termination.
Cons:
You have to create Solver,SolverManager, and ScoreManager instances manually. Specifically, you can't have a #Bean method producing an instance of one of the types above because that would deactivate OptaPlannerAutoConfiguration, which creates the SolverConfig bean.

Related

Spring Boot : how auto configure works and #JsonTest

I've read some stuff about how auto-configuration works behind the scene (configuration classes with #Conditional, spring.factories inside /META-INF etc...)
Now I'm trying to understand with an example : #JsonTest
I can see this annotation is annotated with things like #AutoConfigureJson
What this #AutoConfigureJson does exactly ? Does it import some configuration classes with beans inside ? How Spring know how to use this annotation (basically this annotation is almost empty and doesn't say which classes to scan)
#AutoConfigure... (like #AutoConfigureJson) annotations are the way to allow tests with multiple "slices".
Slices load into your tests only a subset of the application, making them run faster. Let's say you need to test a component that uses the Jackson Object Mapper, then you would need the #JsonTest slice. (here is the list of all available slices.)
But you may also need some other part of the framework in your test not just tha single slice; let's say the JPA layer. You may want to annotate the test with both #JsonTest and #DataJpaTest to load both slices. According to the docs, this is not supported.
What you should do instead is choose one of the#...Test annotation, and include the other with an #AutoConfigure... annotation.
#JsonTest
#AutoConfigureDataJpa
class MyTests {
// tests
}
Update:
at a certain point while evaluating the annotation, Spring Boot will hit this line and will pass to the method SpringFactoriesLoader.loadFactoryNames() a source, that is the fully qualified name of the annotation (like interface org.springframework.boot.test.autoconfigure.json.AutoConfigureJson for example).
The loadFactoryNames method will do its magic and read the necessary information from here.
If more details are needed, the best thing is to use a debugger and just follow along all the steps.

Why use spring beans instead of object initialization

I am trying to understand the idea of spring beans and why I should use them. If I create a bean and use it to print something out like this.
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Account acc = (Account)context.getBean("account");
acc.printAccName();
Why not just create an object of that class like this
Account acc2 = new Account();
acc.printAccName();
I have been watching some video's and did some reading but I did not get an answer why it is better.
Usually what you inject is business logic or services which typically is what changes in a system.
You are trying to inject a domain object Account these objects are not subject to change so it is okay to create the object via new. Perhaps, this is what it is confusing you.
The idea, is to let the container handle the instantiation of your logic or services that change regularly so you can swap them easily without having to open the client classes, because these might be already in production, tested and a developer could potentially introduce new bugs and break things. One way to avoid this is to follow a principle called Open-Closed principle. Then you code to abstractions so you can easily inject concrete implementations via dependency injection.
Imagine the following escenario. For a bookstore, you have different implementations of how to save a book into a database e.g. using JDBC BookServiceJDBCImpl, or using an ORM BookServiceHibernateImpl etc..
// Create & get the Spring container, where you configure your implementations
// e.g. bookServiceJDBC, or bookServiceHibernate
ApplicationContext container = new ClassPathXmlApplicationContext("spring-config.xml");
// the container loads the appropriate bean say bookServiceHibernate
BookService bookService = (BookService) container.getBean("bookService");
//Create a new book this is a domain object usually you use new
Book newBook = new Book("1234", "Spring in Action","Rod Johnson");
//Now save the book using the implementation defined in the
//container
bookService.registerNewBook(newBook);
This is how part of the container file may look like, in here you define the concrete implementation:
<bean id="bookService" class="service.BookServiceHibernateImpl"/>
By letting the container handle this you could inject different implementations without having to touch the client class or even knowing which implementation will be passed.
Check this Dependency Injection blog post it explains a way to achieve it using Spring.
Bare in mind that in Spring you can use java annotations or xml, and that there are different ways to inject dependencies e.g. via get/set, constructors etc this is just an illustrative example of the general DI concept. The design is up to the developer.
Another reason why you would use beans is to aid testing.
We also extract the RestTemplate into a #Bean to make it easier to
test (it can be mocked more easily that way). Link

How to list resolvedDataSources from AbstractRoutingDataSource?

I implemented Dynamic DataSource Routing using Spring Boot (JavaConfig) to add and switch new DataSources in runtime.
I implemented AbstractRoutingDataSource and I need access to all resolvedDataSources that is a private property. How can I do it?
I actually don't know why that field has not been made protected to let implementing classes access the data sources set. Regarding your questions two options come into my mind.
Option 1:
Copy the code of AbstractRoutingDataSource into a class of your own. Then you can expose the resolvedDataSources simply by a getter. This should work as long as the configuration relies on the interface AbstractDataSource and not AbstractRoutingDataSource.
Option 2
Pick the brute force way by accessing the field via Reflection API

Configurable Component Scan

Is there a way to make the component scan configurable externally or through an intermediate resolver class? My requirement is that a common library should include one or more of other smaller facilities (each having their own controller, services etc.) depending on whether those are "configured" or needed - e.g. in application properties.
The closest I can see a possibility of designing this is to declare a #Configuration class in the common library and keep it in the component scan class path (always). In this class I need some way to say that the following are the allowed scan paths (based on how downstream projects have configured their application properties).
Seems like TypeFilter custom implementation should do it. But how do I read application properties from inside the type filter implementation (annotation takes only the .class, so Spring must be initializing it.
Any other ways? Thanks!
Regards,
Arnab.
This document describes how to create your own Auto-Configuration. It allows you to read properties and utilize several variations of #Conditional annotation.

How can I explicitly define an order in which Spring's out-of-the-box process of reading properties out of an available-in-classpath application.yml

UPDATE: I just published this question also here, I might have done a better work phrasing it there.
How can I explicitly define an order in which Spring's out-of-the-box process of reading properties out of an available-in-classpath application.yml will take place BEFORE my #Configuration annotated class which reads configuration data from zookeeper and places them as system properties which are later easily read and injected into members using #Value?
I have a #Configuration class, which defines a creation of a #Bean, in a which configuration data from zookeeper is read and placed as system properties, in a way that they can easily be read and injected into members using #Value.
#Profile("prod")
#Configuration
public class ZookeeperConfigurationReader {
#Value("${zookeeper.url}")
static String zkUrl;
#Bean
public static PropertySourcesPlaceholderConfigurer zkPropertySourcesPlaceHolderConfigurer() {
PropertySourcesConfigurerAdapter propertiesAdapter = new PropertySourcesConfigurerAdapter();
new ConfigurationBuilder().populateAdapterWithDataFromZk(propertiesAdapter);
return propertiesAdapter.getConfigurer();
}
public void populateAdapterWithDataFromZk(ConfigurerAdapter ca) {
...
}
}
Right now I pass the zookeeper.url into the executed program using a -Dzookeeper.url which is added to the execution line. Right now I read it by calling directly System.getProperty("zookeeper.url").
Since I'm using Spring-Boot application, I also have a application.yml configuration file.
I would like to be able to set the zookeeper.url in the application.yml, and keep my execution line clean as possible from explicit properties.
The mission turns out to be harder than I thought.
As you can see in the above code sniplet of ZookeeperConfigurationReader, I'm trying to inject that value using #Value("${zookeeper.url}") into a member in the class which performs the actual read of data from zookeeper, but at the time the code that needs that value accesses it, it is still null. The reason for that is that in spring life cycle wise, I'm still in the phase of "configuration" as I'm a #Configuration annotated class myself, and the spring's code which reads the application.yml data and places them as system properties, hasn't been executed yet.
So bottom line, what I'm looking for is a way to control the order and tell spring to first read application.yml into system properties, and then load ZookeeperConfigurationReader class.
You can try to use Spring Cloud Zookeeper. I posted a brief example of use here

Resources