-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #295 from eclipse-passage/565011
Bug 565011 rebuild the core of condition expression evaluation
- Loading branch information
Showing
10 changed files
with
473 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
...e/passage/lic/internal/base/conditions/evaluation/AndsProtocolExpressionParseService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 ArSysOp | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* https://www.eclipse.org/legal/epl-2.0/. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* ArSysOp - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.passage.lic.internal.base.conditions.evaluation; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionParsingException; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionPasringService; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionProtocol; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression; | ||
|
||
/** | ||
* | ||
*/ | ||
@SuppressWarnings("restriction") | ||
public final class AndsProtocolExpressionParseService implements ExpressionPasringService { | ||
|
||
private final ExpressionProtocol protocol = new ExpressionProtocol.Ands(); | ||
|
||
@Override | ||
public ExpressionProtocol id() { | ||
return protocol; | ||
} | ||
|
||
/** | ||
* Expect the incoming {@code expression} to be a semicolon-separated | ||
* {@code key=value} pairs meaning {@code AND}-ed equality checks. | ||
* <p> | ||
* FIXME: contract: <no checks> situation must cause failure - cover it with a | ||
* contract test | ||
* </p> | ||
*/ | ||
@Override | ||
public ParsedExpression parsed(String expression) throws ExpressionParsingException { | ||
Objects.requireNonNull(expression); | ||
Map<String, String> checks = new HashMap<>(); | ||
// FIXME: ytbd: do further work: split and fill the map | ||
return new SimpleMapExpression(protocol, checks); | ||
} | ||
|
||
} |
20 changes: 20 additions & 0 deletions
20
...clipse/passage/lic/internal/base/conditions/evaluation/BaseEmissionFailureDiagnostic.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 ArSysOp | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* https://www.eclipse.org/legal/epl-2.0/. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* ArSysOp - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.passage.lic.internal.base.conditions.evaluation; | ||
|
||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.EmissionFailureDiagnostic; | ||
|
||
@SuppressWarnings("restriction") | ||
final class BaseEmissionFailureDiagnostic implements EmissionFailureDiagnostic { | ||
// FIXME: ytbd | ||
} |
64 changes: 64 additions & 0 deletions
64
....base/src/org/eclipse/passage/lic/internal/base/conditions/evaluation/BasePermission.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 ArSysOp | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* https://www.eclipse.org/legal/epl-2.0/. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* ArSysOp - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.passage.lic.internal.base.conditions.evaluation; | ||
|
||
import java.time.ZonedDateTime; | ||
import java.util.Objects; | ||
|
||
import org.eclipse.passage.lic.internal.api.LicensedProduct; | ||
import org.eclipse.passage.lic.internal.api.conditions.Condition; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.Permission; | ||
|
||
@SuppressWarnings("restriction") | ||
public final class BasePermission implements Permission { | ||
|
||
private final LicensedProduct product; | ||
private final Condition condition; | ||
private final ZonedDateTime lease; | ||
private final ZonedDateTime expiration; | ||
|
||
public BasePermission(LicensedProduct product, Condition condition, ZonedDateTime lease, ZonedDateTime expiration) { | ||
Objects.requireNonNull(product, "BasePermission::product"); //$NON-NLS-1$ | ||
Objects.requireNonNull(condition, "BasePermission::condition"); //$NON-NLS-1$ | ||
Objects.requireNonNull(lease, "BasePermission::lease"); //$NON-NLS-1$ | ||
Objects.requireNonNull(expiration, "BasePermission::expiration"); //$NON-NLS-1$ | ||
if (!lease.isBefore(expiration)) { | ||
throw new IllegalArgumentException("`Lease` date must strictly less than `expriation` date."); //$NON-NLS-1$ | ||
} | ||
this.product = product; | ||
this.condition = condition; | ||
this.lease = lease; | ||
this.expiration = expiration; | ||
} | ||
|
||
@Override | ||
public LicensedProduct product() { | ||
return product; | ||
} | ||
|
||
@Override | ||
public Condition condition() { | ||
return condition; | ||
} | ||
|
||
@Override | ||
public ZonedDateTime leaseDate() { | ||
return lease; | ||
} | ||
|
||
@Override | ||
public ZonedDateTime expireDate() { | ||
return expiration; | ||
} | ||
|
||
} |
119 changes: 119 additions & 0 deletions
119
...clipse/passage/lic/internal/base/conditions/evaluation/BasePermissionEmittingService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 ArSysOp | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* https://www.eclipse.org/legal/epl-2.0/. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* ArSysOp - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.passage.lic.internal.base.conditions.evaluation; | ||
|
||
import java.time.ZonedDateTime; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.Objects; | ||
|
||
import org.eclipse.passage.lic.internal.api.LicensedProduct; | ||
import org.eclipse.passage.lic.internal.api.LicensingException; | ||
import org.eclipse.passage.lic.internal.api.conditions.Condition; | ||
import org.eclipse.passage.lic.internal.api.conditions.EvaluationType; | ||
import org.eclipse.passage.lic.internal.api.conditions.ValidityPeriod; | ||
import org.eclipse.passage.lic.internal.api.conditions.ValidityPeriodClosed; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.Emission; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionEvaluationService; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionEvaluatorsRegistry; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionParsingException; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionPasringRegistry; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionTokenAssessmentService; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionTokenAssessorsRegistry; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.PermissionEmittingService; | ||
import org.eclipse.passage.lic.internal.api.registry.StringServiceId; | ||
|
||
@SuppressWarnings("restriction") | ||
public final class BasePermissionEmittingService implements PermissionEmittingService { | ||
|
||
private final StringServiceId id = new StringServiceId("default-emitter"); //$NON-NLS-1$ | ||
private final ExpressionPasringRegistry parsers; | ||
private final ExpressionTokenAssessorsRegistry assessors; | ||
private ExpressionEvaluatorsRegistry evaluators; | ||
|
||
public BasePermissionEmittingService(// | ||
ExpressionPasringRegistry parsers, // | ||
ExpressionTokenAssessorsRegistry assessors, // | ||
ExpressionEvaluatorsRegistry evaluators) { | ||
Objects.requireNonNull(parsers); | ||
Objects.requireNonNull(assessors); | ||
Objects.requireNonNull(evaluators); | ||
this.assessors = assessors; | ||
this.parsers = parsers; | ||
this.evaluators = evaluators; | ||
} | ||
|
||
@Override | ||
public StringServiceId id() { | ||
return id; | ||
} | ||
|
||
@Override | ||
public Emission emit(Collection<Condition> conditions, LicensedProduct product) { | ||
return conditions.stream() // | ||
.map(condition -> emitFor(condition, product))// | ||
.reduce(// | ||
new Emission.Successful(Collections.emptyList()), // | ||
new SumOfEmissions()); | ||
} | ||
|
||
private Emission emitFor(Condition condition, LicensedProduct product) { | ||
boolean satisfied = false; | ||
try { | ||
satisfied = expressionIsSatisfied(condition); | ||
} catch (ExpressionParsingException e) { | ||
new Emission.Failed(new BaseEmissionFailureDiagnostic()); // FIXME: ytbd: explain | ||
} catch (LicensingException e) { | ||
new Emission.Failed(new BaseEmissionFailureDiagnostic()); // FIXME: ytbd: explain | ||
} | ||
if (satisfied) { | ||
return new Emission.Successful(Arrays.asList(// | ||
new BasePermission(// | ||
product, // | ||
condition, // | ||
ZonedDateTime.now(), // | ||
expiration(condition.validityPeriod())))); | ||
} else { | ||
return new Emission.Failed(new BaseEmissionFailureDiagnostic()); // FIXME: ytbd: explain | ||
} | ||
} | ||
|
||
private boolean expressionIsSatisfied(Condition condition) throws LicensingException, ExpressionParsingException { | ||
ExpressionTokenAssessmentService assessor = // | ||
evaluator(condition.evaluationInstructions().type()); | ||
ParsedExpression expression = new FormalizedExpression( // | ||
condition.evaluationInstructions().expression(), // | ||
parsers.get()).get(); | ||
ExpressionEvaluationService evaluator = evaluators.get().service(expression.protocol()); | ||
return evaluator.evaluate(expression, assessor); | ||
} | ||
|
||
private ExpressionTokenAssessmentService evaluator(EvaluationType type) throws LicensingException { | ||
if (!assessors.get().hasService(type)) { | ||
throw new LicensingException(String.format( | ||
"Expression of [%s] evaluation type cannot be asessed: no evaluation services are geristered for the type", //$NON-NLS-1$ FIXME | ||
type)); | ||
} | ||
return assessors.get().service(type); | ||
} | ||
|
||
private ZonedDateTime expiration(ValidityPeriod period) { | ||
if (ValidityPeriodClosed.class.isInstance(period)) { | ||
return ((ValidityPeriodClosed) period).to(); | ||
} | ||
return ZonedDateTime.now().plusDays(1); | ||
} | ||
|
||
} |
80 changes: 80 additions & 0 deletions
80
...src/org/eclipse/passage/lic/internal/base/conditions/evaluation/FormalizedExpression.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2020 ArSysOp | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* https://www.eclipse.org/legal/epl-2.0/. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* ArSysOp - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.passage.lic.internal.base.conditions.evaluation; | ||
|
||
import java.util.Objects; | ||
|
||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionParsingException; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionPasringService; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionProtocol; | ||
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression; | ||
import org.eclipse.passage.lic.internal.api.registry.Registry; | ||
|
||
/** | ||
* <p> | ||
* Turns the given raw {@code expression} string into a workable | ||
* {@linkplain ParsedExpression} instance. Is aware of top-level expression | ||
* syntax (<protocol><separator><content>): | ||
* </p> | ||
* <ul> | ||
* <li>cuts the protocol part, uses default is there is no such thing</li> | ||
* <li>guided by the protocol - detects the parsing service</li> | ||
* <li>uses the service to parse content of the expression</li> | ||
* </ul> | ||
*/ | ||
@SuppressWarnings("restriction") | ||
final class FormalizedExpression { | ||
|
||
private final String raw; | ||
private final String separator; | ||
private final Registry<ExpressionProtocol, ExpressionPasringService> parsers; | ||
|
||
FormalizedExpression(String raw, String separator, Registry<ExpressionProtocol, ExpressionPasringService> parsers) { | ||
Objects.requireNonNull(raw, "RetrievedExpression::raw"); //$NON-NLS-1$ | ||
Objects.requireNonNull(separator, "RetrievedExpression::separator"); //$NON-NLS-1$ | ||
Objects.requireNonNull(parsers, "RetrievedExpression::parsers"); //$NON-NLS-1$ | ||
this.raw = raw; | ||
this.separator = separator; | ||
this.parsers = parsers; | ||
} | ||
|
||
FormalizedExpression(String raw, Registry<ExpressionProtocol, ExpressionPasringService> parsers) { | ||
this(raw, "!!", parsers); //$NON-NLS-1$ | ||
} | ||
|
||
ParsedExpression get() throws ExpressionParsingException { | ||
return service().parsed(content()); | ||
} | ||
|
||
private ExpressionPasringService service() { | ||
ExpressionProtocol protocol = protocol(); | ||
return parsers.hasService(protocol) // | ||
? parsers.service(protocol) // | ||
: parsers.service(new ExpressionProtocol.Default()); // guaranteed by Framework contract | ||
} | ||
|
||
private ExpressionProtocol protocol() { | ||
int index = raw.indexOf(separator); | ||
return index <= 0 // | ||
? new ExpressionProtocol.Default() // | ||
: new ExpressionProtocol.Of(raw.substring(0, index)); | ||
} | ||
|
||
private String content() { | ||
int index = raw.indexOf(separator); | ||
return index <= 0 // | ||
? raw // | ||
: raw.substring(index + separator.length()); | ||
} | ||
|
||
} |
Oops, something went wrong.