Skip to content

Commit

Permalink
JAMES-2344 Strong type QuotaSize and QuotaCount to allow representing…
Browse files Browse the repository at this point in the history
… more cases

	switch from long to strong type to prevent some error types and
	use Optional to force decision to happen in the right place.

	Also, it should be compatible with current stored quota in production
	but encoding to/from long is done at the protocol level now, as expected.
  • Loading branch information
mbaechler committed Mar 7, 2018
1 parent 90fa81a commit ebcb09a
Show file tree
Hide file tree
Showing 91 changed files with 2,135 additions and 715 deletions.
20 changes: 15 additions & 5 deletions mailbox/api/pom.xml
Expand Up @@ -65,11 +65,6 @@
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
Expand All @@ -89,6 +84,21 @@
<artifactId>assertj-guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand Down
Expand Up @@ -18,39 +18,34 @@
****************************************************************/
package org.apache.james.mailbox.exception;

import org.apache.james.mailbox.quota.QuotaValue;

/**
* {@link MailboxException} which identicate that a user was over-quota
*
*
*/
public class OverQuotaException extends MailboxException {

/**
*
*/
private static final long serialVersionUID = 532673188582481689L;

private long used;
private long max;
private QuotaValue<?> used;
private QuotaValue<?> max;

public OverQuotaException(String msg, long max, long used) {
public OverQuotaException(String msg, QuotaValue<?> max, QuotaValue<?> used) {
super(msg);
this.used = used;
this.max = max;
}

public OverQuotaException(long max, long used) {
public OverQuotaException(QuotaValue<?> max, QuotaValue<?> used) {
this(null, max, used);
}

public long getUsed() {
public QuotaValue<?> getUsed() {
return used;
}

public long getMax() {
public QuotaValue<?> getMax() {
return max;
}



}
47 changes: 24 additions & 23 deletions mailbox/api/src/main/java/org/apache/james/mailbox/model/Quota.java
Expand Up @@ -18,43 +18,42 @@
****************************************************************/
package org.apache.james.mailbox.model;

import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import java.util.Optional;

public class Quota {
import org.apache.james.mailbox.quota.QuotaValue;

public static final long UNLIMITED = -1;

public static final long UNKNOWN = Long.MIN_VALUE;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;

private static final Quota UNLIMITED_QUOTA = new Quota(UNKNOWN, UNLIMITED);
public class Quota<T extends QuotaValue<T>> {

public static Quota unlimited() {
return UNLIMITED_QUOTA;
public static <T extends QuotaValue<T>> Quota<T> quota(T used, T max) {
Preconditions.checkNotNull(used);
return new Quota<>(Optional.of(used), max);
}

public static Quota quota(long used, long max) {
return new Quota(used, max);
public static <T extends QuotaValue<T>> Quota<T> unknownUsedQuota(T max) {
return new Quota<>(Optional.empty(), max);
}

private final long max;
private long used;
private final T max;
private final Optional<T> used;

private Quota(long used, long max) {
private Quota(Optional<T> used, T max) {
this.used = used;
this.max = max;
}

public long getMax() {
public T getMax() {
return max;
}

public long getUsed() {
public Optional<T> getUsed() {
return used;
}

public void addValueToQuota(long value) {
used += value;
public Quota<T> addValueToQuota(T value) {
return new Quota<T>(used.map(x -> x.add(value)), max);
}

/**
Expand All @@ -68,8 +67,10 @@ public boolean isOverQuota() {

public boolean isOverQuotaWithAdditionalValue(long additionalValue) {
Preconditions.checkArgument(additionalValue >= 0);
return max != UNLIMITED
&& used + additionalValue > max;
if (!max.isLimited()) {
return false;
}
return used.map(x -> x.add(additionalValue).isGreaterThan(max)).orElse(false);
}

@Override
Expand All @@ -82,9 +83,9 @@ public boolean equals(Object o) {
if (o == null || ! (o instanceof Quota)) {
return false;
}
Quota other = (Quota) o;
return used == other.getUsed()
&& max == other.getMax();
Quota<?> other = (Quota<?>) o;
return Objects.equal(used, other.getUsed())
&& Objects.equal(max,other.getMax());
}

@Override
Expand Down
Expand Up @@ -27,8 +27,8 @@
*/
public interface CurrentQuotaManager {

long getCurrentMessageCount(QuotaRoot quotaRoot) throws MailboxException;
QuotaCount getCurrentMessageCount(QuotaRoot quotaRoot) throws MailboxException;

long getCurrentStorage(QuotaRoot quotaRoot) throws MailboxException;
QuotaSize getCurrentStorage(QuotaRoot quotaRoot) throws MailboxException;

}
Expand Up @@ -19,6 +19,8 @@

package org.apache.james.mailbox.quota;

import java.util.Optional;

import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.QuotaRoot;

Expand All @@ -34,52 +36,83 @@ public interface MaxQuotaManager {
* @param quotaRoot Quota root argument from RFC 2087 ( correspond to the user owning this mailbox )
* @param maxStorageQuota The new storage quota ( in bytes ) for this user
*/
void setMaxStorage(QuotaRoot quotaRoot, long maxStorageQuota) throws MailboxException;
void setMaxStorage(QuotaRoot quotaRoot, QuotaSize maxStorageQuota) throws MailboxException;

/**
* Method allowing you to set the maximum message count allowed for this user
* Method allowing you to set the maximum message count allowed for this quotaroot
*
* @param quotaRoot Quota root argument from RFC 2087 ( correspond to the user owning this mailbox )
* @param maxMessageCount The new message count allowed for this user.
* @param quotaRoot Quota root argument from RFC 2087
* @param maxMessageCount The new message count allowed.
*/
void setMaxMessage(QuotaRoot quotaRoot, QuotaCount maxMessageCount) throws MailboxException;

/**
* Method allowing you to remove the maximum messages count allowed for this quotaroot
*
* @param quotaRoot Quota root argument from RFC 2087
*/
void setMaxMessage(QuotaRoot quotaRoot, long maxMessageCount) throws MailboxException;
void removeMaxMessage(QuotaRoot quotaRoot) throws MailboxException;

/**
* Method allowing you to remove the maximum messages size allowed for this quotaroot
*
* @param quotaRoot Quota root argument from RFC 2087
*/
void removeMaxStorage(QuotaRoot quotaRoot) throws MailboxException;

/**
* Method allowing you to set the default maximum storage in bytes.
*
* @param defaultMaxStorage new default maximum storage
*/
void setDefaultMaxStorage(long defaultMaxStorage) throws MailboxException;
void setDefaultMaxStorage(QuotaSize defaultMaxStorage) throws MailboxException;

/**
* Method allowing you to remove the default maximum messages size in bytes.
*/
void removeDefaultMaxStorage() throws MailboxException;

/**
* Method allowing you to set the default maximum message count allowed
*
* @param defaultMaxMessageCount new default message count
*/
void setDefaultMaxMessage(long defaultMaxMessageCount) throws MailboxException;
void setDefaultMaxMessage(QuotaCount defaultMaxMessageCount) throws MailboxException;

long getDefaultMaxStorage() throws MailboxException;
/**
* Method allowing you to remove the default maximum messages count.
*/
void removeDefaultMaxMessage() throws MailboxException;

long getDefaultMaxMessage() throws MailboxException;
/**
* Method allowing you to get the default maximum storage in bytes.
*
* @return default maximum storage, if defined
*/
Optional<QuotaSize> getDefaultMaxStorage() throws MailboxException;

/**
* Method allowing you to get the default maximum message count allowed
*
* @return default maximum message count, if defined
*/
Optional<QuotaCount> getDefaultMaxMessage() throws MailboxException;

/**
* Return the maximum storage which is allowed for the given {@link QuotaRoot} (in fact the user which the session is bound to)
*
* The returned valued must be in <strong>bytes</strong>
*
* @param quotaRoot Quota root argument from RFC 2087 ( correspond to the user owning this mailbox )
* @return maxBytesThe maximum storage
* @throws MailboxException
* @return The maximum storage in bytes if any
*/
long getMaxStorage(QuotaRoot quotaRoot) throws MailboxException;

Optional<QuotaSize> getMaxStorage(QuotaRoot quotaRoot) throws MailboxException;

/**
* Return the maximum message count which is allowed for the given {@link QuotaRoot} (in fact the user which the session is bound to)
*
* @param quotaRoot Quota root argument from RFC 2087 ( correspond to the user owning this mailbox )
* @return maximum of allowed message count
* @throws MailboxException
*/
long getMaxMessage(QuotaRoot quotaRoot) throws MailboxException;
Optional<QuotaCount> getMaxMessage(QuotaRoot quotaRoot) throws MailboxException;
}
@@ -0,0 +1,90 @@
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
****************************************************************/
package org.apache.james.mailbox.quota;

import java.util.Optional;

import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;

public class QuotaCount implements QuotaValue<QuotaCount> {

public static QuotaCount unlimited() {
return new QuotaCount(Optional.empty());
}

public static QuotaCount count(long value) {
return new QuotaCount(Optional.of(value));
}

private final Optional<Long> value;

private QuotaCount(Optional<Long> value) {
this.value = value;
}

@Override
public long asLong() {
return value.orElseThrow(IllegalStateException::new);
}

@Override
public boolean isLimited() {
return value.isPresent();
}

@Override
public QuotaCount add(long additionalValue) {
return new QuotaCount(value.map(x -> x + additionalValue));
}

@Override
public QuotaCount add(QuotaCount additionalValue) {
if (additionalValue.isUnlimited()) {
return unlimited();
}
return new QuotaCount(value.map(x -> x + additionalValue.asLong()));
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("value", value.map(String::valueOf).orElse("unlimited"))
.toString();
}

@Override
public boolean isGreaterThan(QuotaCount other) {
return value.orElse(Long.MAX_VALUE) > other.value.orElse(Long.MAX_VALUE);
}

@Override
public final boolean equals(Object o) {
if (o instanceof QuotaCount) {
QuotaCount that = (QuotaCount) o;
return Objects.equal(this.value, that.value);
}
return false;
}

@Override
public final int hashCode() {
return Objects.hashCode(value);
}
}
Expand Up @@ -37,7 +37,7 @@ public interface QuotaManager {
* @return quota
* @throws MailboxException
*/
Quota getMessageQuota(QuotaRoot quotaRoot) throws MailboxException;
Quota<QuotaCount> getMessageQuota(QuotaRoot quotaRoot) throws MailboxException;


/**
Expand All @@ -48,5 +48,5 @@ public interface QuotaManager {
* @return quota
* @throws MailboxException
*/
Quota getStorageQuota(QuotaRoot quotaRoot) throws MailboxException;
Quota<QuotaSize> getStorageQuota(QuotaRoot quotaRoot) throws MailboxException;
}

0 comments on commit ebcb09a

Please sign in to comment.