Skip to content

Commit

Permalink
Merge pull request #72 from eparovyshnaya/553807
Browse files Browse the repository at this point in the history
# 553807 - revise permission observatory API

 - Observatory is renamed to Pool
 - GuardedObservatory is renamed to Observatory
 - schedule semantics is formed to a separate class
 - which is, in turn, covered with tests
 - lic.base bundle version is incremented in _patch_ part according to [semver](semver.org) as the new release cycle has just begun

Signed-off-by: elena.parovyshnaya <[email protected]>
  • Loading branch information
eparovyshnaya authored Dec 6, 2019
2 parents aaafdf3 + 01dc63f commit aef90fb
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 131 deletions.
2 changes: 1 addition & 1 deletion bundles/org.eclipse.passage.lic.base/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Automatic-Module-Name: org.eclipse.passage.lic.api.base
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.passage.lic.base
Bundle-Version: 0.6.0.qualifier
Bundle-Version: 0.6.1.qualifier
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-Copyright: %Bundle-Copyright
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,25 @@
import java.util.stream.StreamSupport;

import org.eclipse.passage.lic.api.access.FeaturePermission;
import org.eclipse.passage.lic.internal.base.permission.observatory.GuardedObservatory;
import org.eclipse.passage.lic.internal.base.permission.observatory.CheckSchedule;
import org.eclipse.passage.lic.internal.base.permission.observatory.Observatory;

/**
* <p>
* Base implementation for {@linkplain PermissionObservatory} component.
* </p>
* <p>
* Covers {@linkplain GuardedObservatory} tuned for permission tracking and is
* it's representation for the domain specific environment.
* Covers {@linkplain Observatory} tuned for permission tracking and is it's
* representation for the domain specific environment.
* </p>
*
* @since 0.6
*/
public final class BasePermissionObservatory implements PermissionObservatory {
private final GuardedObservatory<LimitedPermission> observatory;
private final Observatory<LimitedPermission> observatory;

public BasePermissionObservatory(int seconds, Consumer<Set<LimitedPermission>> farewell) {
this.observatory = new GuardedObservatory<LimitedPermission>(seconds, farewell);
public BasePermissionObservatory(CheckSchedule schedule, Consumer<Set<LimitedPermission>> farewell) {
this.observatory = new Observatory<LimitedPermission>(schedule, farewell);
}

public void watch(Iterable<FeaturePermission> permissions) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
import java.util.Date;

import org.eclipse.passage.lic.api.access.FeaturePermission;
import org.eclipse.passage.lic.internal.base.permission.observatory.GuardedObservatory;
import org.eclipse.passage.lic.internal.base.permission.observatory.Observatory;
import org.eclipse.passage.lic.internal.base.permission.observatory.Limited;

/**
* Adapter for {@linkplain FeaturePermission} to implement {@linkplain Limited}
* interface to be properly tracked by {@linkplain GuardedObservatory}
* interface to be properly tracked by {@linkplain Observatory}
*
* @since 0.6
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
*******************************************************************************/
package org.eclipse.passage.lic.internal.base.permission;

import org.eclipse.passage.lic.internal.base.permission.observatory.GuardedObservatory;
import org.eclipse.passage.lic.internal.base.permission.observatory.Observatory;

/**
* Marker interface for a component that holds {@linkplain GuardedObservatory}
* Marker interface for a component that holds {@linkplain Observatory}
* for permission tracking.
*
* @since 0.6
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (c) 2019 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://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.permission.observatory;

import java.time.temporal.ChronoUnit;

/**
* <p>
* Schedule for observatory checks.
* </p>
*
* <p>
* Been defined for <i>5 minutes</i>, causes the observatory to check for new
* expired entries each 5 minutes (or so).
* </p>
*
* @since 0.6
*/
public class CheckSchedule {

private final int amount;
private final ChronoUnit unit;

/**
* <p>
* Use desired units to define the most suitable check schedule.
* </p>
*
* <p>
* For example, {@code new CheckSchedule(2, ChronoUnit.DAYS)}, been given to an
* observatory, will cause the closest expiration check to happen only in two
* days since the observatory opening.
* </p>
*
* @param amount number of units
* @unit {@linkplain ChronoUnit} constant to measure {@code amount}
* @since 0.6
*/
public CheckSchedule(int amount, ChronoUnit unit) {
this.amount = amount;
this.unit = unit;
}

/**
* Default schedules are measured in minutes.
*
* @param minutes number of minutes
* @since 0.6
*/
public CheckSchedule(int minutes) {
this(minutes, ChronoUnit.MINUTES);
}

/**
* Default schedule is 10 minutes.
*
* @since 0.6
*/
public CheckSchedule() {
this(10, ChronoUnit.MINUTES);
}

/**
* Reports the scheduled period duration in seconds.
*
* @since 0.6
*/
public long seconds() {
return unit.getDuration().getSeconds() * amount;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@

final class Guard<T extends Limited> implements Runnable {

private final int period;
private final Observatory<T> pool;
private final long period;
private final Pool<T> pool;
private final Consumer<Set<T>> onExpire;
private final Executor executor;

/**
* @param onExpire never gets {@code null} or empty set. The callback is
* expected to complete shortly.
*/
Guard(int seconds, Observatory<T> pool, Consumer<Set<T>> onExpire) {
this.period = seconds;
Guard(CheckSchedule schedule, Pool<T> pool, Consumer<Set<T>> onExpire) {
this.period = schedule.seconds();
this.pool = pool;
this.onExpire = onExpire;
executor = Executors.newSingleThreadExecutor();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,95 @@
*******************************************************************************/
package org.eclipse.passage.lic.internal.base.permission.observatory;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.function.Consumer;

final class Observatory<T extends Limited> {
private final Set<T> watched = new HashSet<>();
/**
* <p>
* This observatory keeps an eye on any captured entry, that can say in a moment
* of time whether it is expired already or not yet.
* </p>
*
* <p>
* Ones in a period of time the observatory checks all watched entries if they
* are expired already. And for the ones who do, a configured action is called.
* Since this moment an expired entry in not watched anymore.
* </p>
*
* <p>
* There is no check on an observatory opening. The closest one takes place only
* after a scheduled period of time is over.
* </p>
*
* <p>
* An entry can be put under the observatory control and removed from it
* preliminary, prior this is done by TTL.
* </p>
*
* <p>
* To configure an observatory, you need only define
* <ul>
* <li><i>how often</i> it will check expiration and</li>
* <li>what will it do for expired entries</li>
* </ul>
* </p>
*
* @since 0.6
*/
public final class Observatory<T extends Limited> {
private final Pool<T> pool;
private final Guard<T> guard;

void watch(T target) {
synchronized (watched) {
watched.add(target);
}
/**
* <p>
* When the time comes and an entry expires, {@code farewell} action is called
* for it.
* </p>
*
* <p>
* The observatory does the brushing checks each {@code schedule} seconds, so an
* entry cannot be processed precisely in a moment it expires, but some time
* like {@code schedule} seconds after.
* </p>
*
* @param schedule period (in seconds) between checks
* @param farewell handler to be notified of expired entries. Is not intended to
* work long. Never bothered for naught: never gets {@code null}
* or empty set.
* @since 0.6
*/
public Observatory(CheckSchedule schedule, Consumer<Set<T>> farewell) {
pool = new Pool<T>();
guard = new Guard<T>(schedule, pool, farewell);
}

void forget(T target) {
synchronized (watched) {
watched.remove(target);
}
/**
* The observatory can accept entries to watch and dismiss them after, but
* checks start only after it is open.
*
* @since 0.6
*/
public void open() {
new Thread(guard).start();
}

Expired<T> popExpired() {
synchronized (watched) {
Set<T> expired = watched.stream().filter(Limited::expired).collect(Collectors.toSet());
watched.removeAll(expired);
return new Expired<T>(expired);
}
/**
* Put a {@link Limited} entry under the observatory control.
*
* @since 0.6
*/
public void watch(T limited) {
pool.watch(limited);
}

/**
* Remove a {@link Limited} entry from the observatory control intentionally
* prior it's expiration.
*
* @since 0.6
*/
public void forget(T limited) {
pool.forget(limited);
}

}
Loading

0 comments on commit aef90fb

Please sign in to comment.