Repository: camel Updated Branches: refs/heads/master 32d75e290 -> cba859770
Added consumer, producer with event listeners, async and daemon solving features Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/cba85977 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/cba85977 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/cba85977 Branch: refs/heads/master Commit: cba859770c005dea2bb217e672adf40de682e416 Parents: 32d75e2 Author: Bilgin Ibryam <[email protected]> Authored: Fri Aug 21 02:09:43 2015 +0100 Committer: Bilgin Ibryam <[email protected]> Committed: Fri Aug 21 02:09:43 2015 +0100 ---------------------------------------------------------------------- .../optaplanner/OptaPlannerComponent.java | 12 +- .../optaplanner/OptaPlannerConfiguration.java | 83 +++++++++++++ .../optaplanner/OptaPlannerConstants.java | 28 +++++ .../optaplanner/OptaPlannerConsumer.java | 75 +++++++++++ .../optaplanner/OptaPlannerEndpoint.java | 80 +++++++----- .../optaplanner/OptaPlannerProducer.java | 124 +++++++++++++++++++ .../optaplanner/OptaPlannerAsyncSolverTest.java | 63 ++++++++++ .../optaplanner/OptaPlannerConsumerTest.java | 70 +++++++++++ .../OptaPlannerDaemonSolverTest.java | 96 ++++++++++++++ .../optaplanner/OptaPlannerSyncSolverTest.java | 55 ++++++++ .../component/optaplanner/OptaPlannerTest.java | 55 -------- .../optaplanner/daemonSolverConfig.xml | 55 ++++++++ .../component/optaplanner/solverConfig.xml | 2 +- 13 files changed, 704 insertions(+), 94 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerComponent.java b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerComponent.java index cb59460..b188d39 100644 --- a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerComponent.java +++ b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerComponent.java @@ -20,7 +20,6 @@ import java.util.Map; import org.apache.camel.Endpoint; import org.apache.camel.impl.UriEndpointComponent; -import org.optaplanner.core.api.solver.SolverFactory; /** * OptaPlanner component for Camel @@ -32,13 +31,10 @@ public class OptaPlannerComponent extends UriEndpointComponent { } protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { - SolverFactory solverFactory = SolverFactory.createFromXmlResource(remaining); - - OptaPlannerEndpoint endpoint = new OptaPlannerEndpoint(uri, this, remaining); - endpoint.setSolverFactory(solverFactory); - setProperties(endpoint, parameters); - - return endpoint; + OptaPlannerConfiguration configuration = new OptaPlannerConfiguration(); + configuration.setConfigFile(remaining); + setProperties(configuration, parameters); + return new OptaPlannerEndpoint(uri, this, configuration); } } http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConfiguration.java b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConfiguration.java new file mode 100644 index 0000000..0e70c77 --- /dev/null +++ b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConfiguration.java @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; +import org.apache.camel.spi.UriPath; + +@UriParams +public class OptaPlannerConfiguration { + + /** + * Specifies the solverId to user for the solver instance key + */ + @UriParam(label = "common", defaultValue = "DEFAULT_SOLVER") + private String solverId = OptaPlannerConstants.DEFAULT_SOLVER_ID; + + /** + * Specifies the location to the solver file + */ + @UriPath + @Metadata(required = "true") + private String configFile; + + /** + * Specifies the thread pool size to use when async is true + */ + @UriParam(label = "producer", defaultValue = "10") + private int threadPoolSize = 10; + + /** + * Specifies to perform operations in async mode + */ + @UriParam(label = "producer", defaultValue = "false") + private boolean async; + + public String getSolverId() { + return solverId; + } + + public void setSolverId(String solverId) { + this.solverId = solverId; + } + + public void setConfigFile(String configFile) { + this.configFile = configFile; + } + + public String getConfigFile() { + return configFile; + } + + public int getThreadPoolSize() { + return threadPoolSize; + } + + public void setThreadPoolSize(int threadPoolSize) { + this.threadPoolSize = threadPoolSize; + } + + public boolean isAsync() { + return async; + } + + public void setAsync(boolean async) { + this.async = async; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConstants.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConstants.java b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConstants.java new file mode 100644 index 0000000..986a161 --- /dev/null +++ b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConstants.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +public interface OptaPlannerConstants { + String DEFAULT_SOLVER_ID = "DEFAULT_SOLVER"; + String SOLVER_ID = "CamelOptaPlannerSolverId"; + String IS_ASYNC = "CamelOptaPlannerIsAsync"; + String BEST_SOLUTION = "CamelOptaPlannerBestSolution"; + String TIME_SPENT = "CamelOptaPlannerTimeSpent"; + String IS_SOLVING = "CamelOptaPlannerIsSolving"; + String IS_TERMINATE_EARLY = "CamelOptaPlannerIsTerminateEarly"; + String IS_FACT_PROCESSED = "CamelOptaPlannerIsFactProcessed"; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java new file mode 100644 index 0000000..0e10a79 --- /dev/null +++ b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.impl.DefaultConsumer; +import org.optaplanner.core.api.solver.Solver; +import org.optaplanner.core.api.solver.event.BestSolutionChangedEvent; +import org.optaplanner.core.api.solver.event.SolverEventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * OptaPlanner component for Camel + */ +public class OptaPlannerConsumer extends DefaultConsumer { + private static final transient Logger LOGGER = LoggerFactory.getLogger(OptaPlannerConsumer.class); + private final OptaPlannerEndpoint endpoint; + private final OptaPlannerConfiguration configuration; + private final SolverEventListener listener; + + public OptaPlannerConsumer(OptaPlannerEndpoint endpoint, Processor processor, OptaPlannerConfiguration configuration) { + super(endpoint, processor); + this.endpoint = endpoint; + this.configuration = configuration; + listener = new SolverEventListener() { + @Override + public void bestSolutionChanged(BestSolutionChangedEvent event) { + if (event.isEveryProblemFactChangeProcessed() && event.isNewBestSolutionInitialized()) { + processEvent(event); + } + } + }; + } + + public void processEvent(BestSolutionChangedEvent event) { + Exchange exchange = getEndpoint().createExchange(); + exchange.getOut().setHeader(OptaPlannerConstants.BEST_SOLUTION, event.getNewBestSolution()); + try { + getProcessor().process(exchange); + } catch (Exception e) { + LOGGER.error("Error processing event ", e); + } + } + + @Override + protected void doStart() throws Exception { + Solver solver = endpoint.getOrCreateSolver(configuration.getSolverId()); + solver.addEventListener(listener); + super.doStart(); + } + + @Override + protected void doStop() throws Exception { + Solver solver = endpoint.getOrCreateSolver(configuration.getSolverId()); + solver.removeEventListener(listener); + super.doStop(); + } +} + http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerEndpoint.java b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerEndpoint.java index 3eade1b..8424530 100644 --- a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerEndpoint.java +++ b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerEndpoint.java @@ -16,63 +16,83 @@ */ package org.apache.camel.component.optaplanner; +import java.util.HashMap; +import java.util.Map; + import org.apache.camel.Component; -import org.apache.camel.Exchange; -import org.apache.camel.ExchangePattern; -import org.apache.camel.component.ResourceEndpoint; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.UriEndpoint; -import org.apache.camel.util.ObjectHelper; -import org.optaplanner.core.api.domain.solution.Solution; +import org.apache.camel.spi.UriParam; import org.optaplanner.core.api.solver.Solver; import org.optaplanner.core.api.solver.SolverFactory; /** * OptaPlanner endpoint for Camel */ -@UriEndpoint(scheme = "optaplanner", title = "OptaPlanner", syntax = "optaplanner:resourceUri", producerOnly = true, label = "engine,planning") -public class OptaPlannerEndpoint extends ResourceEndpoint { +@UriEndpoint(scheme = "optaplanner", title = "OptaPlanner", syntax = "optaplanner:resourceUri", label = "engine,planning") +public class OptaPlannerEndpoint extends DefaultEndpoint { + protected static final Map<String, Solver> SOLVERS = new HashMap<String, Solver>(); + @UriParam + private OptaPlannerConfiguration configuration; private SolverFactory solverFactory; public OptaPlannerEndpoint() { } - public OptaPlannerEndpoint(String uri, Component component, String resourceUri) { - super(uri, component, resourceUri); + public OptaPlannerEndpoint(String uri, Component component, OptaPlannerConfiguration configuration) { + super(uri, component); + this.configuration = configuration; + solverFactory = SolverFactory.createFromXmlResource(configuration.getConfigFile()); } - public SolverFactory getSolverFactory() { - return solverFactory; + protected Solver getOrCreateSolver(String solverId) throws Exception { + synchronized (SOLVERS) { + Solver solver = SOLVERS.get(solverId); + if (solver == null) { + solver = createSolver(); + SOLVERS.put(solverId, solver); + } + return solver; + } } - public void setSolverFactory(SolverFactory solverFactory) { - this.solverFactory = solverFactory; + protected Solver createSolver() { + return solverFactory.buildSolver(); } - @Override - public ExchangePattern getExchangePattern() { - return ExchangePattern.InOut; + protected Solver getSolver(String solverId) { + synchronized (SOLVERS) { + return SOLVERS.get(solverId); + } } @Override - protected String createEndpointUri() { - return "optaplanner:" + getResourceUri(); + public Producer createProducer() throws Exception { + return new OptaPlannerProducer(this, configuration); } @Override - protected void onExchange(Exchange exchange) throws Exception { - ObjectHelper.notNull(solverFactory, "solverFactory"); - Solver solver = solverFactory.buildSolver(); - - Solution planningProblem = exchange.getIn().getMandatoryBody(Solution.class); - - solver.solve(planningProblem); - Solution bestSolution = solver.getBestSolution(); + public Consumer createConsumer(Processor processor) throws Exception { + return new OptaPlannerConsumer(this, processor, configuration); + } - exchange.getOut().setBody(bestSolution); - // propagate headers and attachments - exchange.getOut().setHeaders(exchange.getIn().getHeaders()); - exchange.getOut().setAttachments(exchange.getIn().getAttachments()); + @Override + public boolean isSingleton() { + return true; } + @Override + protected void doStop() throws Exception { + synchronized (SOLVERS) { + for (Solver solver : SOLVERS.values()) { + solver.terminateEarly(); + SOLVERS.remove(solver); + } + } + super.doStop(); + } } http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerProducer.java b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerProducer.java new file mode 100644 index 0000000..c862cd7 --- /dev/null +++ b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerProducer.java @@ -0,0 +1,124 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +import java.util.concurrent.ExecutorService; + +import org.apache.camel.Exchange; +import org.apache.camel.impl.DefaultProducer; +import org.optaplanner.core.api.domain.solution.Solution; +import org.optaplanner.core.api.solver.Solver; +import org.optaplanner.core.impl.solver.ProblemFactChange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OptaPlannerProducer extends DefaultProducer { + private static final transient Logger LOGGER = LoggerFactory.getLogger(OptaPlannerProducer.class); + private ExecutorService executor; + private final OptaPlannerEndpoint endpoint; + private final OptaPlannerConfiguration configuration; + + public OptaPlannerProducer(OptaPlannerEndpoint endpoint, OptaPlannerConfiguration configuration) { + super(endpoint); + this.endpoint = endpoint; + this.configuration = configuration; + } + + @Override + protected void doStart() throws Exception { + if (configuration.isAsync()) { + executor = endpoint.getCamelContext().getExecutorServiceManager().newFixedThreadPool( + this, endpoint.getEndpointUri(), configuration.getThreadPoolSize()); + } + super.doStart(); + } + + @Override + protected void doStop() throws Exception { + if (executor != null) { + endpoint.getCamelContext().getExecutorServiceManager().shutdown(executor); + executor = null; + } + super.doStop(); + } + + @Override + public synchronized void process(Exchange exchange) throws Exception { + final Object body = exchange.getIn().getMandatoryBody(); + final String solverId = getSolverId(exchange); + + if (body instanceof Solution) { + if (isAsync(exchange)) { + LOGGER.debug("Asynchronously solving problem: [{}] with id [{}]", body, solverId); + final Solver solver = endpoint.getOrCreateSolver(solverId); + executor.submit(new Runnable() { + @Override + public void run() { + solver.solve((Solution)body); + } + }); + } else { + LOGGER.debug("Synchronously solving problem: [{}] with id [{}]", body, solverId); + Solver solver = endpoint.getSolver(solverId); + if (solver == null) { + solver = endpoint.createSolver(); + } + solver.solve((Solution) body); + populateResult(exchange, solver); + } + } else if (body instanceof ProblemFactChange) { + LOGGER.debug("Adding ProblemFactChange to solver: [{}] with id [{}]", body, solverId); + Solver solver = endpoint.getOrCreateSolver(solverId); + solver.addProblemFactChange((ProblemFactChange)body); + if (!isAsync(exchange)) { + while (!solver.isEveryProblemFactChangeProcessed()) { + Thread.currentThread().sleep(100); + } + } + populateResult(exchange, solver); + } else { + LOGGER.debug("Retrieving best score for solver: [{}]", solverId); + Solver solver = endpoint.getSolver(solverId); + if (solver == null) { + throw new RuntimeException("Solver not found: " + solverId); + } + populateResult(exchange, solver); + } + } + + private void populateResult(Exchange exchange, Solver solver) { + exchange.getIn().setBody(solver.getBestSolution()); + exchange.getIn().setHeader(OptaPlannerConstants.TIME_SPENT, solver.getTimeMillisSpent()); + exchange.getIn().setHeader(OptaPlannerConstants.IS_FACT_PROCESSED, solver.isEveryProblemFactChangeProcessed()); + exchange.getIn().setHeader(OptaPlannerConstants.IS_TERMINATE_EARLY, solver.isTerminateEarly()); + exchange.getIn().setHeader(OptaPlannerConstants.IS_SOLVING, solver.isSolving()); + } + + private String getSolverId(Exchange exchange) throws Exception { + String solverId = exchange.getIn().getHeader(OptaPlannerConstants.SOLVER_ID, String.class); + if (solverId == null) { + solverId = configuration.getSolverId(); + } + LOGGER.debug("SolverId: [{}]", solverId); + return solverId; + } + + private boolean isAsync(Exchange exchange) { + Boolean isAsync = exchange.getIn().getHeader(OptaPlannerConstants.IS_ASYNC, Boolean.class); + return isAsync != null ? isAsync : configuration.isAsync(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerAsyncSolverTest.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerAsyncSolverTest.java b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerAsyncSolverTest.java new file mode 100644 index 0000000..cdbafe7 --- /dev/null +++ b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerAsyncSolverTest.java @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; +import org.optaplanner.examples.cloudbalancing.domain.CloudBalance; +import org.optaplanner.examples.cloudbalancing.persistence.CloudBalancingGenerator; + +/** + * OptaPlanner unit test with Camel + */ +public class OptaPlannerAsyncSolverTest extends CamelTestSupport { + + @Test + public void testAsynchronousProblemSolving() throws Exception { + getMockEndpoint("mock:result").setExpectedCount(1); + CloudBalancingGenerator generator = new CloudBalancingGenerator(true); + final CloudBalance planningProblem = generator.createCloudBalance(4, 12); + assertNull(planningProblem.getScore()); + assertNull(planningProblem.getProcessList().get(0).getComputer()); + + template.requestBody("direct:in", planningProblem); + getMockEndpoint("mock:result").assertIsSatisfied(); + + CloudBalance bestSolution = (CloudBalance) template.requestBody("direct:in", "foo"); + + assertEquals(4, bestSolution.getComputerList().size()); + assertEquals(12, bestSolution.getProcessList().size()); + assertNotNull(bestSolution.getScore()); + assertTrue(bestSolution.getScore().isFeasible()); + assertNotNull(bestSolution.getProcessList().get(0).getComputer()); + } + + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in"). + to("optaplanner:org/apache/camel/component/optaplanner/solverConfig.xml?async=true"); + + from("optaplanner:org/apache/camel/component/optaplanner/solverConfig.xml"). + to("log:com.mycompany.order?showAll=true&multiline=true"). + to("mock:result"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerConsumerTest.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerConsumerTest.java b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerConsumerTest.java new file mode 100644 index 0000000..2e86201 --- /dev/null +++ b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerConsumerTest.java @@ -0,0 +1,70 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.commons.lang.ObjectUtils; +import org.junit.Ignore; +import org.junit.Test; +import org.optaplanner.core.impl.score.director.ScoreDirector; +import org.optaplanner.core.impl.solver.ProblemFactChange; +import org.optaplanner.examples.cloudbalancing.domain.CloudBalance; +import org.optaplanner.examples.cloudbalancing.domain.CloudComputer; +import org.optaplanner.examples.cloudbalancing.domain.CloudProcess; +import org.optaplanner.examples.cloudbalancing.persistence.CloudBalancingGenerator; + +/** + * OptaPlanner unit test with Camel + */ +public class OptaPlannerConsumerTest extends CamelTestSupport { + + @Test + public void testSynchronousProblemSolving() throws Exception { + CloudBalancingGenerator generator = new CloudBalancingGenerator(true); + final CloudBalance planningProblem = generator.createCloudBalance(4, 12); + assertNull(planningProblem.getScore()); + assertNull(planningProblem.getProcessList().get(0).getComputer()); + + CloudBalance bestSolution = (CloudBalance) template.requestBody("direct:in", planningProblem); + + assertEquals(4, bestSolution.getComputerList().size()); + assertEquals(12, bestSolution.getProcessList().size()); + assertNotNull(bestSolution.getScore()); + assertTrue(bestSolution.getScore().isFeasible()); + assertNotNull(bestSolution.getProcessList().get(0).getComputer()); + } + + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in"). + to("optaplanner:org/apache/camel/component/optaplanner/solverConfig.xml"); + + from("optaplanner:org/apache/camel/component/optaplanner/solverConfig.xml"). + to("log:com.mycompany.order?showAll=true&multiline=true"). + to("mock:result"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerDaemonSolverTest.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerDaemonSolverTest.java b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerDaemonSolverTest.java new file mode 100644 index 0000000..596fd16 --- /dev/null +++ b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerDaemonSolverTest.java @@ -0,0 +1,96 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.commons.lang.ObjectUtils; +import org.junit.Test; +import org.optaplanner.core.impl.score.director.ScoreDirector; +import org.optaplanner.core.impl.solver.ProblemFactChange; +import org.optaplanner.examples.cloudbalancing.domain.CloudBalance; +import org.optaplanner.examples.cloudbalancing.domain.CloudComputer; +import org.optaplanner.examples.cloudbalancing.domain.CloudProcess; +import org.optaplanner.examples.cloudbalancing.persistence.CloudBalancingGenerator; + +/** + * OptaPlanner unit test with Camel + */ +public class OptaPlannerDaemonSolverTest extends CamelTestSupport { + + @Test + public void testAsynchronousProblemSolving() throws Exception { + getMockEndpoint("mock:result").setExpectedCount(1); + CloudBalancingGenerator generator = new CloudBalancingGenerator(true); + final CloudBalance planningProblem = generator.createCloudBalance(4, 12); + assertNull(planningProblem.getScore()); + assertNull(planningProblem.getProcessList().get(0).getComputer()); + + template.requestBody("direct:in", planningProblem); + getMockEndpoint("mock:result").assertIsSatisfied(); + getMockEndpoint("mock:result").reset(); + getMockEndpoint("mock:result").setExpectedCount(1); + + template.requestBody("direct:in", new ProblemFactChange() { + @Override + public void doChange(ScoreDirector scoreDirector) { + CloudBalance cloudBalance = (CloudBalance) scoreDirector.getWorkingSolution(); + CloudComputer computer = null; + for (CloudProcess process : cloudBalance.getProcessList()) { + computer = process.getComputer(); + if (ObjectUtils.equals(process.getComputer(), computer)) { + scoreDirector.beforeVariableChanged(process, "computer"); + process.setComputer(null); + scoreDirector.afterVariableChanged(process, "computer"); + } + } + cloudBalance.setComputerList(new ArrayList<CloudComputer>(cloudBalance.getComputerList())); + for (Iterator<CloudComputer> it = cloudBalance.getComputerList().iterator(); it.hasNext();) { + CloudComputer workingComputer = it.next(); + if (ObjectUtils.equals(workingComputer, computer)) { + scoreDirector.beforeProblemFactRemoved(workingComputer); + it.remove(); // remove from list + scoreDirector.beforeProblemFactRemoved(workingComputer); + break; + } + } + } + }); + + getMockEndpoint("mock:result").assertIsSatisfied(); + CloudBalance bestSolution = (CloudBalance) template.requestBody("direct:in", "foo"); + + assertEquals(3, bestSolution.getComputerList().size()); + } + + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in"). + to("optaplanner:org/apache/camel/component/optaplanner/daemonSolverConfig.xml?async=true"); + + from("optaplanner:org/apache/camel/component/optaplanner/daemonSolverConfig.xml"). + to("log:com.mycompany.order?showAll=true&multiline=true"). + to("mock:result"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerSyncSolverTest.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerSyncSolverTest.java b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerSyncSolverTest.java new file mode 100644 index 0000000..ed2e7c6 --- /dev/null +++ b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerSyncSolverTest.java @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.optaplanner; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; +import org.optaplanner.examples.cloudbalancing.domain.CloudBalance; +import org.optaplanner.examples.cloudbalancing.persistence.CloudBalancingGenerator; + +/** + * OptaPlanner unit test with Camel + */ +public class OptaPlannerSyncSolverTest extends CamelTestSupport { + + @Test + public void testSynchronousProblemSolving() throws Exception { + CloudBalancingGenerator generator = new CloudBalancingGenerator(true); + final CloudBalance planningProblem = generator.createCloudBalance(4, 12); + assertNull(planningProblem.getScore()); + assertNull(planningProblem.getProcessList().get(0).getComputer()); + + CloudBalance bestSolution = (CloudBalance) template.requestBody("direct:in", planningProblem); + + assertEquals(4, bestSolution.getComputerList().size()); + assertEquals(12, bestSolution.getProcessList().size()); + assertNotNull(bestSolution.getScore()); + assertTrue(bestSolution.getScore().isFeasible()); + assertNotNull(bestSolution.getProcessList().get(0).getComputer()); + } + + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:in"). + to("optaplanner:org/apache/camel/component/optaplanner/solverConfig.xml"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerTest.java ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerTest.java b/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerTest.java deleted file mode 100644 index 5a7fd15..0000000 --- a/components/camel-optaplanner/src/test/java/org/apache/camel/component/optaplanner/OptaPlannerTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.camel.component.optaplanner; - -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; -import org.optaplanner.examples.cloudbalancing.domain.CloudBalance; -import org.optaplanner.examples.cloudbalancing.persistence.CloudBalancingGenerator; - -/** - * OptaPlanner unit test with Camel - */ -public class OptaPlannerTest extends CamelTestSupport { - - @Test - public void testCloudBalance4computers12processes() throws Exception { - CloudBalancingGenerator generator = new CloudBalancingGenerator(true); - final CloudBalance planningProblem = generator.createCloudBalance(4, 12); - assertNull(planningProblem.getScore()); - assertNull(planningProblem.getProcessList().get(0).getComputer()); - - CloudBalance bestSolution = (CloudBalance) template.requestBody("direct:in", planningProblem); - - assertEquals(4, bestSolution.getComputerList().size()); - assertEquals(12, bestSolution.getProcessList().size()); - assertNotNull(bestSolution.getScore()); - assertTrue(bestSolution.getScore().isFeasible()); - assertNotNull(bestSolution.getProcessList().get(0).getComputer()); - } - - protected RouteBuilder createRouteBuilder() { - return new RouteBuilder() { - public void configure() { - from("direct:in"). - to("optaplanner:org/apache/camel/component/optaplanner/solverConfig.xml"); - } - }; - } - -} http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/daemonSolverConfig.xml ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/daemonSolverConfig.xml b/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/daemonSolverConfig.xml new file mode 100644 index 0000000..45e60f3 --- /dev/null +++ b/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/daemonSolverConfig.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<solver> + + <!-- Run in daemon mode --> + <daemon>true</daemon> + + <!--<environmentMode>FAST_ASSERT</environmentMode>--> + + <!-- Domain model configuration --> + <solutionClass>org.optaplanner.examples.cloudbalancing.domain.CloudBalance</solutionClass> + <entityClass>org.optaplanner.examples.cloudbalancing.domain.CloudProcess</entityClass> + + <!-- Score configuration --> + <scoreDirectorFactory> + <scoreDefinitionType>HARD_SOFT</scoreDefinitionType> + <scoreDrl>org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl> + </scoreDirectorFactory> + + <!-- Optimization algorithms configuration --> + <termination> + <terminationCompositionStyle>AND</terminationCompositionStyle> + <secondsSpentLimit>2</secondsSpentLimit> + <bestScoreFeasible>true</bestScoreFeasible> + </termination> + <constructionHeuristic> + <constructionHeuristicType>FIRST_FIT_DECREASING</constructionHeuristicType> + <forager> + <pickEarlyType>FIRST_NON_DETERIORATING_SCORE</pickEarlyType> + </forager> + </constructionHeuristic> + <localSearch> + <acceptor> + <entityTabuSize>7</entityTabuSize> + </acceptor> + <forager> + <acceptedCountLimit>1000</acceptedCountLimit> + </forager> + </localSearch> +</solver> http://git-wip-us.apache.org/repos/asf/camel/blob/cba85977/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/solverConfig.xml ---------------------------------------------------------------------- diff --git a/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/solverConfig.xml b/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/solverConfig.xml index 6ecf1a6..68f3e5b 100644 --- a/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/solverConfig.xml +++ b/components/camel-optaplanner/src/test/resources/org/apache/camel/component/optaplanner/solverConfig.xml @@ -31,7 +31,7 @@ <!-- Optimization algorithms configuration --> <termination> <terminationCompositionStyle>AND</terminationCompositionStyle> - <secondsSpentLimit>10</secondsSpentLimit> + <secondsSpentLimit>2</secondsSpentLimit> <bestScoreFeasible>true</bestScoreFeasible> </termination> <constructionHeuristic>
