diff --git a/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/IssueFloatingLicense.java b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/IssueFloatingLicense.java index 39a1a3d43..f172266a5 100644 --- a/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/IssueFloatingLicense.java +++ b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/IssueFloatingLicense.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Optional; import java.util.function.BinaryOperator; +import java.util.stream.Collectors; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; @@ -39,10 +40,12 @@ import org.eclipse.passage.lic.licenses.model.api.FloatingLicensePack; import org.eclipse.passage.lic.licenses.model.api.LicenseRequisites; import org.eclipse.passage.lic.licenses.model.api.ProductRef; +import org.eclipse.passage.lic.licenses.model.api.UserGrant; import org.eclipse.passage.loc.internal.api.IssuedFloatingLicense; import org.eclipse.passage.loc.internal.api.OperatorProductService; import org.eclipse.passage.loc.internal.licenses.LicenseRegistry; import org.eclipse.passage.loc.internal.licenses.core.i18n.LicensesCoreMessages; +import org.eclipse.passage.loc.internal.licenses.core.issue.FloatingLicenseIssuingProtection; import org.eclipse.passage.loc.internal.licenses.trouble.code.LicenseIssuingFailed; import org.eclipse.passage.loc.internal.licenses.trouble.code.LicenseValidationFailed; import org.eclipse.passage.loc.internal.products.ProductRegistry; @@ -62,13 +65,25 @@ final class IssueFloatingLicense { ServiceInvocationResult issue(FloatingLicensePack pack, Collection configs) { + FloatingLicensePack license = shielded(EcoreUtil.copy(pack), configs); try { - new UpdateLicensePlan(licenses).withFloating(EcoreUtil.copy(pack)); + new UpdateLicensePlan(licenses).withFloating(license); } catch (IOException e) { return new BaseServiceInvocationResult<>(new Trouble(new LicenseIssuingFailed(), LicensesCoreMessages.LicenseOperatorServiceImpl_error_io, e)); } - return persistLicenseFiles(EcoreUtil.copy(pack), configs); + return persistLicenseFiles(EcoreUtil.copy(license), configs); + } + + private FloatingLicensePack shielded(FloatingLicensePack pack, Collection configs) { + new FloatingLicenseIssuingProtection().accept(pack); + Collection users = pack.getUsers().stream()// + .map(UserGrant::getUser)// + .collect(Collectors.toSet()); + Collection redundant = configs.stream()// + .filter(c -> !users.contains(c.getUser())).collect(Collectors.toSet()); + configs.removeAll(redundant); + return pack; } private ServiceInvocationResult persistLicenseFiles(FloatingLicensePack pack, diff --git a/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/FeatureGrantCapacityReduction.java b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/FeatureGrantCapacityReduction.java new file mode 100644 index 000000000..09524c70f --- /dev/null +++ b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/FeatureGrantCapacityReduction.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2021 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.loc.internal.licenses.core.issue; + +import org.eclipse.passage.lic.licenses.model.api.FeatureGrant; + +@SuppressWarnings("restriction") +final class FeatureGrantCapacityReduction implements Reduction { + + private final int capacity = 3; + + @Override + public void accept(FeatureGrant grant) { + grant.setCapacity(Math.min(capacity, grant.getCapacity())); + } + +} diff --git a/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/FloatingLicenseIssuingProtection.java b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/FloatingLicenseIssuingProtection.java new file mode 100644 index 000000000..492ddc474 --- /dev/null +++ b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/FloatingLicenseIssuingProtection.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2021 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.loc.internal.licenses.core.issue; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +import org.eclipse.passage.lic.internal.base.conditions.BaseValidityPeriodClosed; +import org.eclipse.passage.lic.internal.equinox.EquinoxPassage; +import org.eclipse.passage.lic.licenses.model.api.FeatureGrant; +import org.eclipse.passage.lic.licenses.model.api.FloatingLicensePack; +import org.eclipse.passage.lic.licenses.model.api.ValidityPeriod; +import org.eclipse.passage.lic.licenses.model.api.ValidityPeriodClosed; +import org.eclipse.passage.lic.licenses.model.meta.LicensesFactory; + +@SuppressWarnings("restriction") +public final class FloatingLicenseIssuingProtection implements Consumer { + + private final String feature = "org.eclipse.passage.loc.operator.issue.floating.full"; //$NON-NLS-1$ + private final List> featureReductions; + private final List> licReductions; + + public FloatingLicenseIssuingProtection() { + this.featureReductions = Arrays.asList(// + new ClosedValidityPeriodReduction(this::validGet, this::validSet), // + new FeatureGrantCapacityReduction()// + ); + this.licReductions = Arrays.asList(// + new ClosedValidityPeriodReduction(this::validGet, this::validSet), // + new UserGrantsAmountReduction()// + ); + } + + @Override + public void accept(FloatingLicensePack license) { + if (new EquinoxPassage().canUse(feature)) { + return; + } + // TODO: log diminishing + diminish(license); + } + + private void diminish(FloatingLicensePack license) { + diminishFeatureGrants(license); + diminishLicense(license); + } + + private void diminishFeatureGrants(FloatingLicensePack license) { + license.getFeatures().forEach(this::diminishGrant); + } + + private void diminishLicense(FloatingLicensePack lic) { + licReductions.forEach(r -> r.accept(lic)); + } + + private void diminishGrant(FeatureGrant grant) { + featureReductions.forEach(r -> r.accept(grant)); + } + + private Optional validGet( + FloatingLicensePack lic) { + return validGet(lic.getLicense().getValid()); + } + + private Optional validGet( + FeatureGrant grant) { + return validGet(grant.getValid()); + } + + private Optional validGet( + ValidityPeriod period) { + if (!(period instanceof ValidityPeriodClosed)) { + return Optional.empty(); // nothing we can reduce for now + } + ValidityPeriodClosed closed = (ValidityPeriodClosed) period; + return Optional.of(new BaseValidityPeriodClosed(date(closed.getFrom()), date(closed.getUntil()))); + } + + private void validSet(FloatingLicensePack lic, + org.eclipse.passage.lic.internal.api.conditions.ValidityPeriodClosed period) { + lic.getLicense().setValid(convert(period)); + } + + private void validSet(FeatureGrant grant, + org.eclipse.passage.lic.internal.api.conditions.ValidityPeriodClosed period) { + grant.setValid(convert(period)); + } + + private ValidityPeriodClosed convert(org.eclipse.passage.lic.internal.api.conditions.ValidityPeriodClosed period) { + org.eclipse.passage.lic.licenses.model.api.ValidityPeriodClosed valid = LicensesFactory.eINSTANCE + .createValidityPeriodClosed(); + valid.setFrom(Date.from(period.from().toInstant())); + valid.setUntil(Date.from(period.to().toInstant())); + return valid; + } + + private ZonedDateTime date(Date date) { + return ZonedDateTime.from(date.toInstant().atZone(ZoneId.systemDefault())); + } + +} diff --git a/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/UserGrantsAmountReduction.java b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/UserGrantsAmountReduction.java new file mode 100644 index 000000000..a160106ac --- /dev/null +++ b/bundles/org.eclipse.passage.loc.licenses.core/src/org/eclipse/passage/loc/internal/licenses/core/issue/UserGrantsAmountReduction.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2021 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.loc.internal.licenses.core.issue; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.passage.lic.licenses.model.api.FloatingLicensePack; +import org.eclipse.passage.lic.licenses.model.api.UserGrant; + +@SuppressWarnings("restriction") +final class UserGrantsAmountReduction implements Reduction { + + private final int amount = 1; + + @Override + public void accept(FloatingLicensePack license) { + EList users = license.getUsers(); + if (users.size() > amount) { + for (int i = users.size() - 1; i >= amount; i--) { + users.remove(i); + } + } + } + +}