Skip to content
Open
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,7 @@
package ai.timefold.solver.core.enterprise;

import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import java.lang.reflect.Method;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
Expand Down Expand Up @@ -57,52 +57,47 @@ static String identifySolverVersion() {
return packaging + " " + version;
}

private static String getVersionString(Class<?> clz) {
var version = clz.getPackage().getImplementationVersion();
return (version == null ? DEVELOPMENT_SNAPSHOT : "v" + version);
}

static TimefoldSolverEnterpriseService load() throws ClassNotFoundException, NoSuchMethodException,
InvocationTargetException, InstantiationException, IllegalAccessException {
@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");
return clz.getDeclaredConstructor().newInstance();
Method method = clz.getMethod("getInstance", Function.class);
return (TimefoldSolverEnterpriseService) method.invoke(null,
(Function<Class<?>, String>) TimefoldSolverEnterpriseService::getVersionString);
}

static String getVersionString(Class<?> clz) {
var version = clz.getPackage().getImplementationVersion();
return (version == null ? DEVELOPMENT_SNAPSHOT : "v" + version);
}

static TimefoldSolverEnterpriseService loadOrFail(Feature feature) {
TimefoldSolverEnterpriseService service;
try {
service = load();
return load();
} catch (EnterpriseLicenseException cause) {
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);
} catch (Exception cause) {
throw new IllegalStateException("""
%s requested but %s %s not found on classpath.
Either add the %s dependency, or %s.
Note: %s %s is a commercial product. Visit https://timefold.ai to find out more."""
%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);
}
var communityVersion = getVersionString(TimefoldSolverEnterpriseService.class);
var enterpriseVersion = getVersionString(service.getClass());
if (Objects.equals(communityVersion, enterpriseVersion)) { // Identical versions.
return service;
} else if (enterpriseVersion.equals(DEVELOPMENT_SNAPSHOT)) { // Don't enforce when running Enterprise tests.
return service;
}
throw new IllegalStateException("""
Detected mismatch between versions of %s %s (%s) and %s (%s).
Ensure your project uses the same version of %s and %s dependencies."""
.formatted(SOLVER_NAME, COMMUNITY_NAME, communityVersion, ENTERPRISE_NAME, enterpriseVersion,
COMMUNITY_COORDINATES, ENTERPRISE_COORDINATES));
}

static <T> T buildOrDefault(Function<TimefoldSolverEnterpriseService, T> builder, Supplier<T> defaultValue) {
static <T> T loadOrDefault(Function<TimefoldSolverEnterpriseService, T> builder, Supplier<T> defaultValue) {
try {
var service = load();
return builder.apply(service);
} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException
| IllegalAccessException e) {
return builder.apply(load());
} catch (Exception e) {
return defaultValue.get();
}
}
Expand Down Expand Up @@ -166,4 +161,16 @@ public String getWorkaround() {

}

final class EnterpriseLicenseException extends RuntimeException {

public EnterpriseLicenseException(String message) {
super(message);
}

public EnterpriseLicenseException(String message, Throwable cause) {
super(message, cause);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public final class VariableListenerSupport<Solution_> implements SupplyManager {

public static <Solution_> VariableListenerSupport<Solution_> create(InnerScoreDirector<Solution_, ?> scoreDirector) {
return new VariableListenerSupport<>(scoreDirector, new NotifiableRegistry<>(scoreDirector.getSolutionDescriptor()),
TimefoldSolverEnterpriseService.buildOrDefault(service -> service::buildTopologyGraph,
TimefoldSolverEnterpriseService.loadOrDefault(service -> service::buildTopologyGraph,
() -> DefaultTopologicalOrderGraph::new));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,32 @@ You are allowed to use Timefold Solver Enterprise Edition for evaluation and dev
Please https://timefold.ai/contact[contact Timefold]
to obtain the credentials necessary to start your evaluation.

TIP: Looking for quicker time-to-value? Timefold offers https://docs.timefold.ai/[pre-built, fully tuned optimization models], no constraint building required. Just plug into our API and start optimizing immediately.
TIP: Looking for quicker time-to-value?
Timefold offers https://docs.timefold.ai/[pre-built, fully tuned optimization models], no constraint building required.
Just plug into our API and start optimizing immediately.

For a high-level overview of the differences between Timefold offerings,
see https://timefold.ai/pricing[Timefold Pricing].

[#switchToEnterpriseEdition]
== Switch to Enterprise Edition

To switch from Timefold Solver Community Edition to Enterprise Edition,
first reference the Enterprise Edition Maven repository in your project:
// 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:

[tabs]
====
Expand Down Expand Up @@ -91,7 +107,8 @@ repositories {
--
====

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

|===
Expand Down
Loading