Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package ai.timefold.solver.core.enterprise;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
Expand Down Expand Up @@ -42,6 +41,14 @@

public interface TimefoldSolverEnterpriseService {

final class InstanceCarrier {

// Workaround to be able to have a lazy singleton inside of an interface.
// Otherwise load() would be calling the reflective constructor every time, which is expensive.
private static volatile TimefoldSolverEnterpriseService INSTANCE;

}

String SOLVER_NAME = "Timefold Solver";
String COMMUNITY_NAME = "Community Edition";
String COMMUNITY_COORDINATES = "ai.timefold.solver:timefold-solver-core";
Expand All @@ -62,14 +69,21 @@ static String identifySolverVersion() {
}

@SuppressWarnings("unchecked")
static TimefoldSolverEnterpriseService load()
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// Avoids ServiceLoader by using reflection directly.
var clz = (Class<? extends TimefoldSolverEnterpriseService>) Class
.forName("ai.timefold.solver.enterprise.core.DefaultTimefoldSolverEnterpriseService");
Method method = clz.getMethod("getInstance", Function.class);
return (TimefoldSolverEnterpriseService) method.invoke(null,
(Function<Class<?>, String>) TimefoldSolverEnterpriseService::getVersionString);
static TimefoldSolverEnterpriseService load() throws ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, IllegalAccessException, InstantiationException {
if (InstanceCarrier.INSTANCE == null) {
synchronized (InstanceCarrier.class) {
if (InstanceCarrier.INSTANCE == null) {
// Avoids ServiceLoader by using reflection directly.
var clz = (Class<? extends TimefoldSolverEnterpriseService>) Class
.forName("ai.timefold.solver.enterprise.core.DefaultTimefoldSolverEnterpriseService");
var ctor = clz.getDeclaredConstructor(Function.class);
InstanceCarrier.INSTANCE =
ctor.newInstance((Function<Class<?>, String>) TimefoldSolverEnterpriseService::getVersionString);
}
}
}
return InstanceCarrier.INSTANCE;
}

static String getVersionString(Class<?> clz) {
Expand All @@ -84,17 +98,15 @@ static TimefoldSolverEnterpriseService loadOrFail(Feature feature) {
throw new IllegalStateException("""
No valid Timefold Enterprise License was found.
Please contact Timefold to obtain a valid license,
or if you believe that this message was given in error.""",
cause);
or if you believe that this message was given in error.""", cause);
} catch (Exception cause) {
throw new IllegalStateException("""
%s requested but %s %s could not be loaded.
Maybe add the %s dependency, or %s.
Note: %s %s is a commercial product.
Visit https://timefold.ai to find out more, or contact Timefold customer support."""
.formatted(feature.getName(), SOLVER_NAME, ENTERPRISE_NAME, feature.getWorkaround(),
ENTERPRISE_COORDINATES, SOLVER_NAME, ENTERPRISE_NAME),
cause);
Visit https://timefold.ai to find out more, or contact Timefold customer support.""".formatted(
feature.getName(), SOLVER_NAME, ENTERPRISE_NAME, feature.getWorkaround(), ENTERPRISE_COORDINATES,
SOLVER_NAME, ENTERPRISE_NAME), cause);
}
}

Expand Down Expand Up @@ -146,21 +158,18 @@ <Solution_> DestinationSelector<Solution_> applyNearbySelection(DestinationSelec
SelectionOrder resolvedSelectionOrder, ElementDestinationSelector<Solution_> destinationSelector);

<Solution_> AbstractMoveSelectorFactory<Solution_, MultistageMoveSelectorConfig>
buildBasicMultistageMoveSelectorFactory(
MultistageMoveSelectorConfig moveSelectorConfig);
buildBasicMultistageMoveSelectorFactory(MultistageMoveSelectorConfig moveSelectorConfig);

<Solution_> AbstractMoveSelectorFactory<Solution_, ListMultistageMoveSelectorConfig>
buildListMultistageMoveSelectorFactory(
ListMultistageMoveSelectorConfig moveSelectorConfig);
buildListMultistageMoveSelectorFactory(ListMultistageMoveSelectorConfig moveSelectorConfig);

InnerConstraintProfiler buildConstraintProfiler();

enum Feature {
MULTITHREADED_SOLVING("Multi-threaded solving", "remove moveThreadCount from solver configuration"),
PARTITIONED_SEARCH("Partitioned search", "remove partitioned search phase from solver configuration"),
NEARBY_SELECTION("Nearby selection", "remove nearby selection from solver configuration"),
AUTOMATIC_NODE_SHARING("Automatic node sharing",
"remove automatic node sharing from solver configuration"),
AUTOMATIC_NODE_SHARING("Automatic node sharing", "remove automatic node sharing from solver configuration"),
MULTISTAGE_MOVE("Multistage move selector",
"remove multistageMoveSelector and/or listMultistageMoveSelector from the solver configuration"),
CONSTRAINT_PROFILING("Constraint profiling", "remove constraintStreamProfilingEnabled from the solver configuration");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ such as <<nearbySelection,nearby selection>> and <<multithreadedSolving,multi-th
These features are essential to scale out to huge datasets.

Unlike Timefold Solver Community Edition, the Enterprise Edition is not open-source.
You are allowed to use Timefold Solver Enterprise Edition for evaluation and development.
We offer free licenses to non-profit organizations and for academic research.
Everyone else may be entitled to a trial license to evaluate the product before purchasing.
Please https://timefold.ai/contact[contact Timefold]
to obtain the credentials necessary to start your evaluation.
to obtain an Enterprise license.

TIP: Looking for quicker time-to-value?
Timefold offers https://docs.timefold.ai/[pre-built, fully tuned optimization models], no constraint building required.
Expand All @@ -23,92 +24,16 @@ see https://timefold.ai/pricing[Timefold Pricing].
[#switchToEnterpriseEdition]
== Switch to Enterprise Edition

// Uncomment the following when ready to enable the Enterprise license
// =============================
// To switch from Timefold Solver Community Edition to Enterprise Edition,
// https://timefold.ai/contact[contact us first] to obtain an Enterprise License.
// This license is represented by a file named `timefold-solver-enterprise-license.pem`,
// which you can introduce to your project by one of the following methods:
//
// * Place the file in the user's home directory.
// * Store the path to the file in `TIMEFOLD_ENTERPRISE_LICENSE` system property.
// * Place the file in the root of your application classpath.
//
// Having done that, reference the Enterprise Edition Maven repository in your project:
// =============================
// Also delete the next line of text.

First reference the Enterprise Edition Maven repository in your project:
To switch from Timefold Solver Community Edition to Enterprise Edition,
https://timefold.ai/contact[contact us first] to obtain an Enterprise License.
This license is represented by a file named `timefold-solver-enterprise-license.pem`,
which you can introduce to your project by one of the following methods:

[tabs]
====
Maven::
+
--
Add the following repository to your `pom.xml`:

[source,xml,options="nowrap"]
----
<project>
...
<repositories>
<repository>
<id>timefold-solver-enterprise</id>
<name>Timefold Solver Enterprise Edition</name>
<url>https://timefold.jfrog.io/artifactory/releases/</url>
</repository>
</repositories>
...
</project>
----

Then create `.m2/settings.xml` in your home directory with the following content:

[source,xml,options="nowrap"]
----
<settings>
...
<servers>
<server>
<!-- Replace "my_username" and "my_password" with credentials obtained from a Timefold representative. -->
<id>timefold-solver-enterprise</id>
<username>my_username</username>
<password>my_password</password>
</server>
</servers>
...
</settings>
----

See https://maven.apache.org/settings.html[Settings Reference] for more information on Maven settings.
--

Gradle::
+
--
Add the following in your `build.gradle`:

[source,groovy,options="nowrap"]
----
repositories {
mavenCentral()
maven {
url "https://timefold.jfrog.io/artifactory/releases/"
credentials { // Replace "my_username" and "my_password" with credentials obtained from a Timefold representative.
username "my_username"
password "my_password"
}
authentication {
basic(BasicAuthentication)
}
}
}
----
--
====
* Place the file in the user's home directory.
* Store the path to the file in `TIMEFOLD_ENTERPRISE_LICENSE` system property.
* Place the file in the root of your application classpath.

Finally, having done all of the above,
replace references to Community Edition artifacts by their Enterprise Edition counterparts
Having done that, replace references to Community Edition artifacts by their Enterprise Edition counterparts
as shown in the following table:

|===
Expand Down
Loading