Merge "Issue #2000 Subscription duplication/overlap detection" into development

Former-commit-id: a5a0e3e280 [formerly db10de3aca3d0ef373df68a3de9871483128b645]
Former-commit-id: 341ce0c8c2
This commit is contained in:
Dustin Johnson 2013-05-14 15:48:58 -05:00 committed by Gerrit Code Review
commit c302fafbd2
22 changed files with 1677 additions and 91 deletions

View file

@ -22,6 +22,7 @@
<constructor-arg ref="subscriptionNotificationService" />
<constructor-arg ref="bandwidthService" />
<constructor-arg ref="permissionsService" />
<constructor-arg ref="subscriptionOverlapService" />
</bean>
<bean name="dataDeliveryServices"

View file

@ -114,8 +114,9 @@ import com.raytheon.viz.ui.presenter.IDisplay;
* and SubscriptionConfigurationManager.
* Jan 21, 2013 1501 djohnson Only send notification if subscription was actually activated/deactivated,
* remove race condition of GUI thread updating the table after notification.
* Jan 22, 2013 1520 mpduff Removed menu accelerators.
* Jan 22, 2013 1520 mpduff Removed menu accelerators.
* Mar 29, 2013 1841 djohnson Subscription implementations now provide a copy method.
* May 29, 2013 2000 djohnson Copy subscription now requires editing first to prevent duplicates, and remove duplicate code.
* </pre>
*
* @author mpduff
@ -680,31 +681,12 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements
* Handle the copy action.
*/
private void handleCopy() {
if (tableComp.getTable().getSelectionCount() == 0) {
DataDeliveryUtils.showMessage(shell, SWT.ERROR, "No Rows Selected",
"Please select a row to Copy");
if (!tableComp.verifySingleRowSelected()) {
return;
}
if (tableComp.getTable().getSelectionCount() > 1) {
int choice = DataDeliveryUtils
.showMessage(
shell,
SWT.ERROR | SWT.YES | SWT.NO,
"Single Selection Only",
"Multiple subscriptions are selected.\n"
+ "Only the first selected item will be copied.\n\n"
+ "Continue with Copy?");
if (choice == SWT.NO) {
return;
}
}
// Get the subscription data
int idx = tableComp.getTable().getSelectionIndices()[0];
SubscriptionManagerRowData row = tableComp.getSubscriptionData()
.getDataRow(idx);
Subscription sub = row.getSubscription();
Subscription sub = tableComp.getSelectedSubscription();
FileNameDlg fnd = new FileNameDlg(getShell(), sub.getName());
String newName = (String) fnd.open();
@ -713,17 +695,8 @@ public class SubscriptionManagerDlg extends CaveSWTDialog implements
&& !newName.equals(sub.getName())) {
Subscription newSub = sub.copy(newName);
// Object is copied, now store it
try {
DataDeliveryServices.getSubscriptionService().store(
newSub,
new CancelForceApplyAndIncreaseLatencyDisplayText(
"create", getShell()));
handleRefresh();
} catch (RegistryHandlerException e) {
statusHandler.handle(Priority.PROBLEM,
"Error saving subscription data to the registry.", e);
}
// Object is copied, now bring up the edit screen with the copy
tableComp.editSubscription(newSub);
}
}

View file

@ -22,6 +22,7 @@ package com.raytheon.uf.viz.datadelivery.subscription;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
@ -30,9 +31,11 @@ import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Shell;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.raytheon.uf.common.auth.user.IUser;
import com.raytheon.uf.common.datadelivery.bandwidth.IBandwidthService;
import com.raytheon.uf.common.datadelivery.bandwidth.IProposeScheduleResponse;
@ -44,6 +47,8 @@ import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandler
import com.raytheon.uf.common.datadelivery.registry.handlers.IPendingSubscriptionHandler;
import com.raytheon.uf.common.datadelivery.registry.handlers.ISubscriptionHandler;
import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService;
import com.raytheon.uf.common.datadelivery.service.subscription.ISubscriptionOverlapService;
import com.raytheon.uf.common.datadelivery.service.subscription.ISubscriptionOverlapService.ISubscriptionOverlapResponse;
import com.raytheon.uf.common.registry.handler.RegistryHandlerException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
@ -73,6 +78,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils;
* Jan 04, 2013 1441 djohnson Separated out notification methods into their own service.
* Jan 28, 2013 1530 djohnson Reset unscheduled flag with each update.
* Mar 29, 2013 1841 djohnson Subscription is now UserSubscription.
* May 14, 2013 2000 djohnson Check for subscription overlap/duplication.
*
* </pre>
*
@ -120,6 +126,22 @@ public class SubscriptionService implements ISubscriptionService {
return forceApplyPromptResponse;
}
/**
* {@inheritDoc}
*/
@Override
public void displayMessage(
IForceApplyPromptDisplayText displayTextStrategy,
final String message) {
final Shell shell = displayTextStrategy.getShell();
shell.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
DataDeliveryUtils.showMessage(shell, SWT.OK,
"Shared Subscription", message);
}
});
}
}
private final IUFStatusHandler statusHandler = UFStatus
@ -136,6 +158,8 @@ public class SubscriptionService implements ISubscriptionService {
private final IDisplayForceApplyPrompt forceApplyPrompt;
private final ISubscriptionOverlapService subscriptionOverlapService;
/**
* Implementation of {@link ISubscriptionServiceResult}.
*/
@ -248,6 +272,15 @@ public class SubscriptionService implements ISubscriptionService {
Set<String> wouldBeUnscheduledSubscriptions);
ForceApplyPromptResponse getForceApplyPromptResponse();
/**
* Display a popup message to the user.
*
* @param displayTextStrategy
* @param message
*/
void displayMessage(IForceApplyPromptDisplayText displayTextStrategy,
String message);
}
/**
@ -291,15 +324,18 @@ public class SubscriptionService implements ISubscriptionService {
* the subscription notification service
* @param bandwidthService
* the bandwidth service
* @param subscriptionOverlapService
*/
@VisibleForTesting
SubscriptionService(ISubscriptionNotificationService notificationService,
IBandwidthService bandwidthService,
IPermissionsService permissionsService,
ISubscriptionOverlapService subscriptionOverlapService,
IDisplayForceApplyPrompt displayForceApplyPrompt) {
this.notificationService = notificationService;
this.bandwidthService = bandwidthService;
this.permissionsService = permissionsService;
this.subscriptionOverlapService = subscriptionOverlapService;
this.forceApplyPrompt = displayForceApplyPrompt;
}
@ -309,16 +345,19 @@ public class SubscriptionService implements ISubscriptionService {
* tying specifically to the implementation class.
*
* @param notificationService
* @param permissionsService
* @param bandwidthService
* @param permissionsService
* @param
* @return the subscription service
*/
public static ISubscriptionService newInstance(
ISubscriptionNotificationService notificationService,
IBandwidthService bandwidthService,
IPermissionsService permissionsService) {
IPermissionsService permissionsService,
ISubscriptionOverlapService subscriptionOverlapService) {
return new SubscriptionService(notificationService, bandwidthService,
permissionsService, new DisplayForceApplyPrompt());
permissionsService, subscriptionOverlapService,
new DisplayForceApplyPrompt());
}
/**
@ -546,6 +585,39 @@ public class SubscriptionService implements ISubscriptionService {
final IForceApplyPromptDisplayText displayTextStrategy)
throws RegistryHandlerException {
for (Subscription subscription : subscriptions) {
final ISubscriptionHandler subscriptionHandler = DataDeliveryHandlers
.getSubscriptionHandler();
final List<Subscription> potentialDuplicates = subscriptionHandler
.getActiveByDataSetAndProvider(
subscription.getDataSetName(),
subscription.getProvider());
List<String> overlappingSubscriptions = Lists.newArrayList();
for (Subscription potentialDuplicate : potentialDuplicates) {
final ISubscriptionOverlapResponse overlapResponse = subscriptionOverlapService
.isOverlapping(potentialDuplicate, subscription);
final String potentialDuplicateName = potentialDuplicate
.getName();
if (overlapResponse.isDuplicate()) {
return new SubscriptionServiceResult(true,
"This subscription would be an exact duplicate of "
+ potentialDuplicateName);
}
if (overlapResponse.isOverlapping()) {
overlappingSubscriptions.add(potentialDuplicateName);
}
}
if (!overlappingSubscriptions.isEmpty()) {
Collections.sort(overlappingSubscriptions);
forceApplyPrompt.displayMessage(
displayTextStrategy,
StringUtil
.createMessage(
ISubscriptionOverlapService.OVERLAPPING_SUBSCRIPTIONS,
overlappingSubscriptions));
}
}
try {
final ProposeResult result = proposeScheduleAndAction(
subscriptions, action);

View file

@ -99,6 +99,7 @@ import com.raytheon.uf.viz.datadelivery.utils.DataDeliveryUtils.TABLE_TYPE;
* Jan 07, 2013 1437 bgonzale Added sort column direction updates.
* Jan 28, 2013 1529 djohnson Disable menu items if no subscriptions are selected.
* Apr 08, 2013 1826 djohnson Remove delivery options, move column value parsing to the columns themselves.
* May 29, 2013 2000 djohnson Consolidate and remove duplicate code.
*
* </pre>
*
@ -197,26 +198,21 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction {
* Handle subscription editing.
*/
public void handleEdit() {
if (table.getSelectionCount() == 0) {
DataDeliveryUtils.showMessage(this.getShell(), SWT.ERROR,
"No Rows Selected", "Please select a row to Edit");
if (!verifySingleRowSelected()) {
return;
}
if (table.getSelectionCount() > 1) {
int choice = DataDeliveryUtils
.showMessage(
this.getShell(),
SWT.ERROR | SWT.YES | SWT.NO,
"Single Selection Only",
"Multiple subscriptions are selected.\n"
+ "Only the first selected item will be edited.\n\n"
+ "Continue with Edit?");
if (choice == SWT.NO) {
return;
}
}
editSubscription(getSelectedSubscription());
}
/**
* Bring up the edit screen with the given subscription. The user
* permissions will be verified prior to launching the dialog.
*
* @param subscription
* the subscription
*/
public void editSubscription(Subscription subscription) {
final DataDeliveryPermission permission = DataDeliveryPermission.SUBSCRIPTION_CREATE;
IUser user = UserController.getUserObject();
String msg = user.uniqueId()
@ -226,12 +222,8 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction {
try {
if (DataDeliveryServices.getPermissionsService()
.checkPermissions(user, msg, permission).isAuthorized()) {
// Get the subscription data
int idx = table.getSelectionIndex();
SubscriptionManagerRowData row = subManagerData.getDataRow(idx);
SubsetManagerDlg<?, ?, ?> dlg = SubsetManagerDlg
.fromSubscription(this.getShell(), true,
row.getSubscription());
.fromSubscription(this.getShell(), true, subscription);
dlg.open();
}
@ -242,15 +234,15 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction {
}
/**
* Open the Add To Group dialog.
* Verifies a single row is selected.
*
* @return true if a single row is selected
*/
private void handleGroupAdd() {
// Ensure a row is selected
public boolean verifySingleRowSelected() {
if (table.getSelectionCount() == 0) {
DataDeliveryUtils.showMessage(this.getShell(), SWT.ERROR,
"No Rows Selected", "Please select a row to Edit");
return;
"No Rows Selected", "Please select a row.");
return false;
}
if (table.getSelectionCount() > 1) {
@ -260,11 +252,21 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction {
SWT.ERROR | SWT.YES | SWT.NO,
"Single Selection Only",
"Multiple subscriptions are selected.\n"
+ "Only the first selected item will be edited.\n\n"
+ "Continue with Edit?");
if (choice == SWT.NO) {
return;
}
+ "Only the first selected item will be used.\n\n"
+ "Continue?");
return choice != SWT.NO;
}
return true;
}
/**
* Open the Add To Group dialog.
*/
private void handleGroupAdd() {
if (!verifySingleRowSelected()) {
return;
}
// Check permissions
@ -277,11 +279,9 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction {
try {
if (DataDeliveryServices.getPermissionsService()
.checkPermissions(user, msg, permission).isAuthorized()) {
// Get the subscription data
int idx = table.getSelectionIndex();
SubscriptionManagerRowData row = subManagerData.getDataRow(idx);
GroupAddDlg groupAdd = new GroupAddDlg(this.getShell(),
row.getSubscription(), this);
getSelectedSubscription(), this);
groupAdd.open();
}
} catch (VizException e) {
@ -827,4 +827,16 @@ public class SubscriptionTableComp extends TableComp implements IGroupAction {
public void setSubscriptionNameList(List<String> subscriptionNameList) {
this.subscriptionNameList = subscriptionNameList;
}
/**
* Return the selected subscription.
*
* @return the subscription
*/
public Subscription getSelectedSubscription() {
int idx = this.getTable().getSelectionIndices()[0];
SubscriptionManagerRowData row = this.getSubscriptionData().getDataRow(
idx);
return row.getSubscription();
}
}

View file

@ -13,8 +13,15 @@ Require-Bundle:
com.raytheon.uf.common.status;bundle-version="1.12.1174",
com.raytheon.uf.common.datadelivery.request;bundle-version="1.0.0",
com.raytheon.uf.common.registry.ebxml;bundle-version="1.0.0",
com.raytheon.uf.common.auth;bundle-version="1.12.1174"
com.raytheon.uf.common.auth;bundle-version="1.12.1174",
org.geotools;bundle-version="2.6.4",
com.raytheon.uf.common.util;bundle-version="1.12.1174",
org.springframework;bundle-version="2.5.6",
com.raytheon.uf.common.localization;bundle-version="1.12.1174",
com.google.guava;bundle-version="1.0.0",
com.raytheon.uf.common.geospatial;bundle-version="1.12.1174"
Export-Package:
com.raytheon.uf.common.datadelivery.service
com.raytheon.uf.common.datadelivery.service,
com.raytheon.uf.common.datadelivery.service.subscription

View file

@ -7,4 +7,10 @@
<bean id="subscriptionNotificationService"
class="com.raytheon.uf.common.datadelivery.service.SendToServerSubscriptionNotificationService" />
<bean id="subscriptionDuplicateChecker" class="com.raytheon.uf.common.datadelivery.service.subscription.SubscriptionDuplicateChecker" />
<bean id="subscriptionOverlapService" class="com.raytheon.uf.common.datadelivery.service.subscription.SubscriptionOverlapService">
<constructor-arg ref="subscriptionDuplicateChecker" />
</bean>
</beans>

View file

@ -0,0 +1,85 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import com.raytheon.uf.common.datadelivery.registry.Subscription;
/**
* Checks for duplication among subscriptions.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 02, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public interface ISubscriptionDuplicateChecker {
/**
* Returns the percent, 0-100, of how many parameters from sub2 are
* satisfied by sub1.
*
* @param sub1
* @param sub2
*
* @return 0-100
*/
int getParameterDuplicationPercent(Subscription sub1, Subscription sub2);
/**
* Returns the percent, 0-100, of how many forecast hours from sub2 are
* satisfied by sub1.
*
* @param sub1
* @param sub2
*
* @return 0-100
*/
int getForecastHourDuplicationPercent(Subscription sub1, Subscription sub2);
/**
* Returns the percent, 0-100, of how many cycle hours from sub2 are
* satisfied by sub1.
*
* @param sub1
* @param sub2
*
* @return 0-100
*/
int getCycleDuplicationPercent(Subscription sub2, Subscription sub1);
/**
* Returns the percent, 0-100, of how much spatial coverage from sub2 is
* satisfied by sub1.
*
* @param sub1
* @param sub2
*
* @return 0-100
*/
int getSpatialDuplicationPercent(Subscription sub1, Subscription sub2);
}

View file

@ -0,0 +1,79 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import com.raytheon.uf.common.datadelivery.registry.Subscription;
/**
* Checks subscriptions to see if they would be considered duplicates.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 09, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public interface ISubscriptionOverlapService {
int ONE_HUNDRED_PERCENT = 100;
String OVERLAPPING_SUBSCRIPTIONS = "The following subscriptions overlap with this one "
+ "and are candidates for a shared subscription: ";
/**
* Response interface for a subscription overlap check.
*/
public static interface ISubscriptionOverlapResponse {
/**
* Check whether the two subscriptions were exact duplicates.
*
* @return true if the subscriptions are duplicates
*/
boolean isDuplicate();
/**
* Check whether the two subscriptions were determined to overlap.
*
* @return true if the subscriptions should be considered as overlapping
* according to the configuration
*/
boolean isOverlapping();
};
/**
* Returns whether sub2 exceeds configured overlap criteria to sub1
* according to the configuration.
*
* @param sub1
* @param sub2
*
* @return the overlap check response
*/
ISubscriptionOverlapResponse isOverlapping(Subscription sub1,
Subscription sub2);
}

View file

@ -0,0 +1,135 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import java.util.Collection;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.datadelivery.registry.Coverage;
import com.raytheon.uf.common.datadelivery.registry.Subscription;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.util.CollectionUtil;
/**
* Checks for duplication among subscriptions.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 02, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public class SubscriptionDuplicateChecker implements
ISubscriptionDuplicateChecker {
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(SubscriptionDuplicateChecker.class);
private static final String UNABLE_TO_DETERMINE_SPATIAL_OVERLAP = "Unable to determine spatial overlap. "
+ "Subscriptions will not be considered to be overlapping spatially.";
/**
* {@inheritDoc}
*/
@Override
public int getParameterDuplicationPercent(Subscription sub1,
Subscription sub2) {
return getDuplicationPercent(sub1.getParameter(), sub2.getParameter());
}
/**
* {@inheritDoc}
*/
@Override
public int getForecastHourDuplicationPercent(Subscription sub1,
Subscription sub2) {
return getDuplicationPercent(sub1.getTime().getSelectedTimeIndices(),
sub2.getTime().getSelectedTimeIndices());
}
/**
* {@inheritDoc}
*/
@Override
public int getCycleDuplicationPercent(Subscription sub1, Subscription sub2) {
return getDuplicationPercent(sub1.getTime().getCycleTimes(), sub2
.getTime().getCycleTimes());
}
/**
* {@inheritDoc}
*/
@Override
public int getSpatialDuplicationPercent(Subscription sub1, Subscription sub2) {
final Coverage sub1Coverage = sub1.getCoverage();
final Coverage sub2Coverage = sub2.getCoverage();
if (sub1Coverage != null && sub2Coverage != null) {
final ReferencedEnvelope sub1Envelope = sub1Coverage
.getRequestEnvelope();
final ReferencedEnvelope sub2Envelope = sub2Coverage
.getRequestEnvelope();
if (sub1Envelope != null && sub2Envelope != null) {
try {
ReferencedEnvelope intersection = MapUtil
.reprojectAndIntersect(sub1Envelope, sub2Envelope);
final double intersectionArea = intersection.getArea();
return (int) ((intersectionArea * 100) / sub2Envelope
.getArea());
} catch (TransformException e) {
statusHandler.handle(Priority.PROBLEM,
UNABLE_TO_DETERMINE_SPATIAL_OVERLAP, e);
}
}
}
return 0;
}
private <T> int getDuplicationPercent(Collection<T> coll1,
Collection<T> coll2) {
int numberSatisfiedByFirstCollection = 0;
if (!CollectionUtil.isNullOrEmpty(coll1)
&& !CollectionUtil.isNullOrEmpty(coll2)) {
for (T entry : coll2) {
if (coll1.contains(entry)) {
numberSatisfiedByFirstCollection++;
}
}
// Convert percent to 0-100
return (numberSatisfiedByFirstCollection * 100) / (coll2.size());
}
return 0;
}
}

View file

@ -0,0 +1,191 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Configuration for the {@link ISubscriptionOverlapService}.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 08, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class SubscriptionOverlapConfig {
public static final SubscriptionOverlapConfig NEVER_OVERLAPS = new SubscriptionOverlapConfig(
ISubscriptionOverlapService.ONE_HUNDRED_PERCENT,
ISubscriptionOverlapService.ONE_HUNDRED_PERCENT,
ISubscriptionOverlapService.ONE_HUNDRED_PERCENT,
ISubscriptionOverlapService.ONE_HUNDRED_PERCENT,
SubscriptionOverlapMatchStrategy.MATCH_ALL);
@XmlElement(required = true)
private int maxAllowedParameterDuplication;
@XmlElement(required = true)
private int maxAllowedForecastHourDuplication;
@XmlElement(required = true)
private int maxAllowedCycleDuplication;
@XmlElement(required = true)
private int maxAllowedSpatialDuplication;
@XmlElement(required = true)
private SubscriptionOverlapMatchStrategy matchStrategy;
/**
* Constructor.
*/
public SubscriptionOverlapConfig() {
}
/**
* Constructor.
*
* @param maxAllowedParameterDuplication
* @param maxAllowedForecastHourDuplication
* @param maxAllowedCycleDuplication
* @param maxAllowedSpatialDuplication
* @param matchStrategy
*/
public SubscriptionOverlapConfig(int maxAllowedParameterDuplication,
int maxAllowedForecastHourDuplication,
int maxAllowedCycleDuplication, int maxAllowedSpatialDuplication,
SubscriptionOverlapMatchStrategy matchStrategy) {
this.maxAllowedParameterDuplication = maxAllowedParameterDuplication;
this.maxAllowedForecastHourDuplication = maxAllowedForecastHourDuplication;
this.maxAllowedCycleDuplication = maxAllowedCycleDuplication;
this.maxAllowedSpatialDuplication = maxAllowedSpatialDuplication;
this.matchStrategy = matchStrategy;
}
/**
* @return the maxAllowedParameterDuplication
*/
public int getMaxAllowedParameterDuplication() {
return maxAllowedParameterDuplication;
}
/**
* @param maxAllowedParameterDuplication
* the maxAllowedParameterDuplication to set
*/
public void setMaxAllowedParameterDuplication(
int maxAllowedParameterDuplication) {
this.maxAllowedParameterDuplication = maxAllowedParameterDuplication;
}
/**
* @return the maxAllowedForecastHourDuplication
*/
public int getMaxAllowedForecastHourDuplication() {
return maxAllowedForecastHourDuplication;
}
/**
* @param maxAllowedForecastHourDuplication
* the maxAllowedForecastHourDuplication to set
*/
public void setMaxAllowedForecastHourDuplication(
int maxAllowedForecastHourDuplication) {
this.maxAllowedForecastHourDuplication = maxAllowedForecastHourDuplication;
}
/**
* @return the maxAllowedCycleDuplication
*/
public int getMaxAllowedCycleDuplication() {
return maxAllowedCycleDuplication;
}
/**
* @param maxAllowedCycleDuplication
* the maxAllowedCycleDuplication to set
*/
public void setMaxAllowedCycleDuplication(int maxAllowedCycleDuplication) {
this.maxAllowedCycleDuplication = maxAllowedCycleDuplication;
}
/**
* @return the maxAllowedSpatialDuplication
*/
public int getMaxAllowedSpatialDuplication() {
return maxAllowedSpatialDuplication;
}
/**
* @param maxAllowedSpatialDuplication
* the maxAllowedSpatialDuplication to set
*/
public void setMaxAllowedSpatialDuplication(int maxAllowedSpatialDuplication) {
this.maxAllowedSpatialDuplication = maxAllowedSpatialDuplication;
}
/**
* @return the matchStrategy
*/
public SubscriptionOverlapMatchStrategy getMatchStrategy() {
return matchStrategy;
}
/**
* @param matchStrategy
* the matchStrategy to set
*/
public void setMatchStrategy(SubscriptionOverlapMatchStrategy matchStrategy) {
this.matchStrategy = matchStrategy;
}
/**
* Check whether the given duplication percents indicate an overlapping
* subscription.
*
* @param parameterDuplicationPercent
* @param forecastHourDuplicationPercent
* @param cycleDuplicationPercent
* @param spatialDuplicationPercent
* @return true if the subscription should be considered overlapping
*/
public boolean isOverlapping(int parameterDuplicationPercent,
int forecastHourDuplicationPercent, int cycleDuplicationPercent,
int spatialDuplicationPercent) {
// Pass through to the match strategy
return this.matchStrategy.isOverlapping(this,
parameterDuplicationPercent, forecastHourDuplicationPercent,
cycleDuplicationPercent, spatialDuplicationPercent);
}
}

View file

@ -0,0 +1,138 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import javax.xml.bind.annotation.XmlEnum;
/**
* Strategy for how to apply the rules in the subscription overlap
* configuration.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 14, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
@XmlEnum
public enum SubscriptionOverlapMatchStrategy {
MATCH_ANY {
@Override
public boolean isOverlapping(SubscriptionOverlapConfig config,
int parameterDuplicationPercent,
int forecastHourDuplicationPercent,
int cycleDuplicationPercent, int spatialDuplicationPercent) {
final boolean exceedsAllowedParameterDuplication = parameterDuplicationPercent > config
.getMaxAllowedParameterDuplication();
final boolean exceedsAllowedForecastHourDuplication = forecastHourDuplicationPercent > config
.getMaxAllowedForecastHourDuplication();
final boolean exceedsAllowedCycleDuplication = cycleDuplicationPercent > config
.getMaxAllowedCycleDuplication();
final boolean exceedsAllowedSpatialDuplication = spatialDuplicationPercent > config
.getMaxAllowedSpatialDuplication();
return exceedsAllowedParameterDuplication
|| exceedsAllowedForecastHourDuplication
|| exceedsAllowedCycleDuplication
|| exceedsAllowedSpatialDuplication;
}
},
MATCH_ALL {
@Override
public boolean isOverlapping(SubscriptionOverlapConfig config,
int parameterDuplicationPercent,
int forecastHourDuplicationPercent,
int cycleDuplicationPercent, int spatialDuplicationPercent) {
final boolean exceedsAllowedParameterDuplication = parameterDuplicationPercent > config
.getMaxAllowedParameterDuplication();
final boolean exceedsAllowedForecastHourDuplication = forecastHourDuplicationPercent > config
.getMaxAllowedForecastHourDuplication();
final boolean exceedsAllowedCycleDuplication = cycleDuplicationPercent > config
.getMaxAllowedCycleDuplication();
final boolean exceedsAllowedSpatialDuplication = spatialDuplicationPercent > config
.getMaxAllowedSpatialDuplication();
return exceedsAllowedParameterDuplication
&& exceedsAllowedForecastHourDuplication
&& exceedsAllowedCycleDuplication
&& exceedsAllowedSpatialDuplication;
}
},
AT_LEAST_HALF {
@Override
public boolean isOverlapping(SubscriptionOverlapConfig config,
int parameterDuplicationPercent,
int forecastHourDuplicationPercent,
int cycleDuplicationPercent, int spatialDuplicationPercent) {
final boolean exceedsAllowedParameterDuplication = parameterDuplicationPercent > config
.getMaxAllowedParameterDuplication();
final boolean exceedsAllowedForecastHourDuplication = forecastHourDuplicationPercent > config
.getMaxAllowedForecastHourDuplication();
final boolean exceedsAllowedCycleDuplication = cycleDuplicationPercent > config
.getMaxAllowedCycleDuplication();
final boolean exceedsAllowedSpatialDuplication = spatialDuplicationPercent > config
.getMaxAllowedSpatialDuplication();
boolean[] toCheck = new boolean[] {
exceedsAllowedParameterDuplication,
exceedsAllowedForecastHourDuplication,
exceedsAllowedCycleDuplication,
exceedsAllowedSpatialDuplication };
final int numBooleans = toCheck.length;
final int halfNumBooleans = numBooleans / 2;
int exceeded = 0;
for (boolean check : toCheck) {
if (check) {
exceeded++;
if (exceeded >= halfNumBooleans) {
return true;
}
}
}
return false;
}
};
/**
* Check whether the given duplication percents indicate an overlapping
* subscription.
*
* @param config
* @param parameterDuplicationPercent
* @param forecastHourDuplicationPercent
* @param cycleDuplicationPercent
* @param spatialDuplicationPercent
* @return true if the subscription should be considered overlapping
*/
public abstract boolean isOverlapping(SubscriptionOverlapConfig config,
int parameterDuplicationPercent,
int forecastHourDuplicationPercent, int cycleDuplicationPercent,
int spatialDuplicationPercent);
}

View file

@ -0,0 +1,194 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import java.util.MissingResourceException;
import javax.xml.bind.JAXBException;
import com.google.common.annotations.VisibleForTesting;
import com.raytheon.uf.common.datadelivery.registry.Subscription;
import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.serialization.JAXBManager;
import com.raytheon.uf.common.serialization.SerializationException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
/**
* Checks subscriptions to see if they would be considered duplicates.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 07, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public class SubscriptionOverlapService implements ISubscriptionOverlapService {
/**
* Base response object implementing {@link ISubscriptionOverlapResponse}.
*/
public class SubscriptionOverlapResponse implements
ISubscriptionOverlapResponse {
private final boolean duplicate;
private final boolean overlapping;
/**
* Constructor.
*
* @param duplicate
* @param overlapping
*/
public SubscriptionOverlapResponse(boolean duplicate,
boolean overlapping) {
this.duplicate = duplicate;
this.overlapping = overlapping;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDuplicate() {
return duplicate;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isOverlapping() {
return overlapping;
}
}
private static final IUFStatusHandler statusHandler = UFStatus
.getHandler(SubscriptionOverlapService.class);
private static final String UNABLE_TO_UNMARSHAL = "Unable to unmarshal the configuration file. "
+ "No subscriptions will be considered to overlap!";
private static final String SUBSCRIPTION_OVERLAP_CONFIG_FILE_PATH = "datadelivery/subscriptionOverlapRules.xml";
private final ISubscriptionDuplicateChecker duplicateChecker;
private final JAXBManager jaxbManager;
/**
* Constructor.
*
* @param duplicateChecker
*/
public SubscriptionOverlapService(
ISubscriptionDuplicateChecker duplicateChecker) {
this.duplicateChecker = duplicateChecker;
try {
jaxbManager = new JAXBManager(SubscriptionOverlapConfig.class);
} catch (JAXBException e) {
throw new ExceptionInInitializerError(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public ISubscriptionOverlapResponse isOverlapping(Subscription sub1,
Subscription sub2) {
// Ignore requests to compare with itself
if (sub1.getName().equals(sub2.getName())) {
return new SubscriptionOverlapResponse(false, false);
}
final IPathManager pathManager = PathManagerFactory.getPathManager();
final LocalizationFile localizationFile = pathManager
.getStaticLocalizationFile(SUBSCRIPTION_OVERLAP_CONFIG_FILE_PATH);
SubscriptionOverlapConfig config;
try {
if (!localizationFile.exists()) {
throw new MissingResourceException(localizationFile.getName()
+ " does not exist.",
SubscriptionOverlapConfig.class.getName(), "");
}
config = localizationFile.jaxbUnmarshal(
SubscriptionOverlapConfig.class, jaxbManager);
} catch (Exception e) {
statusHandler.handle(Priority.PROBLEM, UNABLE_TO_UNMARSHAL, e);
config = SubscriptionOverlapConfig.NEVER_OVERLAPS;
}
final int parameterDuplicationPercent = duplicateChecker
.getParameterDuplicationPercent(sub1, sub2);
final int forecastHourDuplicationPercent = duplicateChecker
.getForecastHourDuplicationPercent(sub1, sub2);
final int cycleDuplicationPercent = duplicateChecker
.getCycleDuplicationPercent(sub1, sub2);
final int spatialDuplicationPercent = duplicateChecker
.getSpatialDuplicationPercent(sub1, sub2);
final boolean overlaps = config.isOverlapping(
parameterDuplicationPercent, forecastHourDuplicationPercent,
cycleDuplicationPercent, spatialDuplicationPercent);
final boolean duplicate = (parameterDuplicationPercent == ONE_HUNDRED_PERCENT)
&& (forecastHourDuplicationPercent == ONE_HUNDRED_PERCENT)
&& (cycleDuplicationPercent == ONE_HUNDRED_PERCENT)
&& (spatialDuplicationPercent == ONE_HUNDRED_PERCENT);
return new SubscriptionOverlapResponse(duplicate, overlaps);
}
/**
* Writes the new configuration.
*
* @param config
* the configuration
* @throws SerializationException
* on error serializing the configuration
*/
@VisibleForTesting
void writeNewConfig(SubscriptionOverlapConfig config)
throws SerializationException {
final LocalizationFile configFile = PathManagerFactory
.getPathManager()
.getStaticLocalizationFile(
SubscriptionOverlapService.SUBSCRIPTION_OVERLAP_CONFIG_FILE_PATH);
this.jaxbManager.jaxbMarshalToXmlFile(config, configFile.getFile()
.getAbsolutePath());
}
}

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<subscriptionOverlapConfig>
<!-- Each value is represented by a percent, 0-100 -->
<maxAllowedParameterDuplication>65</maxAllowedParameterDuplication>
<maxAllowedForecastHourDuplication>65</maxAllowedForecastHourDuplication>
<maxAllowedCycleDuplication>65</maxAllowedCycleDuplication>
<maxAllowedSpatialDuplication>65</maxAllowedSpatialDuplication>
<!--
Available options:
MATCH_ANY: Any of the maxAllowed options will
cause the subscription to be considered overlapping.
MATCH_ALL: All maxAllowed options must be exceeded
to cause the subscription to be considered overlapping.
AT_LEAST_HALF: At least half of the maxAllowed options
must be exceeded to cause the subscription to be considered
overlapping.
-->
<matchStrategy>MATCH_ANY</matchStrategy>
</subscriptionOverlapConfig>

View file

@ -34,6 +34,7 @@ import com.raytheon.uf.common.registry.handler.RegistryHandlerException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.util.CollectionUtil;
/**
* Performs subscription integrity verification.
@ -46,7 +47,8 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* ------------ ---------- ----------- --------------------------
* Dec 7, 2012 1104 djohnson Initial creation
* Feb 05, 2013 1580 mpduff EventBus refactor.
* 3/18/2013 1802 bphillip Modified to use proper transaction boundaries
* 3/18/2013 1802 bphillip Modified to use proper transaction boundaries
* May 08, 2013 2000 djohnson Shortcut out if no subscriptions are returned for the dataset.
*
* </pre>
*
@ -171,6 +173,10 @@ public class SubscriptionIntegrityVerifier {
.getActiveByDataSetAndProvider(dataSet.getDataSetName(),
dataSet.getProviderName());
if (CollectionUtil.isNullOrEmpty(subscriptions)) {
return;
}
for (Subscription subscription : subscriptions) {
if (!subscription.isValid()) {

View file

@ -38,6 +38,7 @@ import java.util.TimeZone;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import org.junit.Ignore;
import org.junit.Test;
import com.raytheon.edex.esb.Headers;
@ -46,7 +47,6 @@ import com.raytheon.edex.plugin.redbook.common.RedbookRecord;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.localization.PathManagerFactoryTest;
import com.raytheon.uf.common.util.FileUtil;
import com.sun.xml.internal.ws.util.ByteArrayBuffer;
/**
* Regression Test RedbookRecords decoded by the RedbookDecoder against known
@ -59,13 +59,14 @@ import com.sun.xml.internal.ws.util.ByteArrayBuffer;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 22, 2013 1958 bgonzale Initial creation
* May 08, 2013 2000 djohnson Ignore broken test.
*
* </pre>
*
* @author bgonzale
* @version 1.0
*/
@Ignore("Test is broken")
public class RedbookDecoderTest {
final static String DataDir = "./data/Redbook";
@ -160,14 +161,13 @@ public class RedbookDecoderTest {
}
private Collection<RedbookTest> tests;
private final Collection<RedbookTest> tests;
public RedbookDecoderTest() throws IOException {
PathManagerFactoryTest.initLocalization();
tests = new ArrayList<RedbookDecoderTest.RedbookTest>();
// load test byte arrays, test header data, and result objects.
InputStream inStrm = null;
ByteArrayBuffer outStrm = null;
for (RedbookInput redbookInput : RedbookInput.getInputs()) {
byte[] rawMessage = null;
@ -267,7 +267,7 @@ public class RedbookDecoderTest {
assertEquals(test.id
+ " Failure, incorrect number of results returned for "
+ test.id, expectedNumberOfResults, result.length);
RedbookRecord expectedResult = (RedbookRecord) (test.hasResults() ? test.result
RedbookRecord expectedResult = (test.hasResults() ? test.result
: null);
RedbookRecord actualResult = (RedbookRecord) (result.length > 0 ? result[0]
: null);

View file

@ -61,8 +61,8 @@ public class GriddedCoverageFixture extends AbstractFixture<GriddedCoverage> {
public GriddedCoverage getInstance(long seedValue, Random random) {
LatLonGridCoverage gridCoverage = new LatLonGridCoverage();
gridCoverage.setCrsWKT("Polygon");
gridCoverage.setLa1(10);
gridCoverage.setLo1(-10);
gridCoverage.setLa1(10 + seedValue);
gridCoverage.setLo1(-10 - seedValue);
gridCoverage.setDx(1.0);
gridCoverage.setDy(1.0);
gridCoverage.setNx(21);

View file

@ -0,0 +1,234 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.junit.Test;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.datadelivery.registry.GriddedCoverage;
import com.raytheon.uf.common.datadelivery.registry.Parameter;
import com.raytheon.uf.common.datadelivery.registry.ParameterFixture;
import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture;
import com.raytheon.uf.common.datadelivery.registry.UserSubscription;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
/**
* TesT {@link SubscriptionDuplicateChecker}.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 02, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public class SubscriptionDuplicateCheckerTest {
private static final ISubscriptionDuplicateChecker dupeChecker = new SubscriptionDuplicateChecker();
@Test
public void returnsPercentOfParametersThatAreTheSame() {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
sub1.getParameter().clear();
sub1.addParameter(ParameterFixture.INSTANCE.get(1));
sub2.getParameter().clear();
sub2.addParameter(sub1.getParameter().iterator().next());
sub2.addParameter(ParameterFixture.INSTANCE.get(2));
assertThat(dupeChecker.getParameterDuplicationPercent(sub1, sub2),
is(50));
assertThat(dupeChecker.getParameterDuplicationPercent(sub2, sub1),
is(100));
}
@Test
public void returnsZeroPercentOfParametersForNullsOrEmpties() {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
sub1.setParameter(null);
sub2.getParameter().clear();
sub2.addParameter(ParameterFixture.INSTANCE.get(2));
assertThat(dupeChecker.getParameterDuplicationPercent(sub1, sub2),
is(0));
assertThat(dupeChecker.getParameterDuplicationPercent(sub2, sub1),
is(0));
sub1.setParameter(Collections.<Parameter> emptyList());
assertThat(dupeChecker.getParameterDuplicationPercent(sub1, sub2),
is(0));
assertThat(dupeChecker.getParameterDuplicationPercent(sub2, sub1),
is(0));
}
@Test
public void returnsPercentOfForecastHoursThatAreTheSame() {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
final List<Integer> sub1SelectedTimes = Arrays.asList(0, 1);
sub1.getTime().setSelectedTimeIndices(sub1SelectedTimes);
final List<Integer> sub2SelectedTimes = Arrays.asList(0, 3, 4);
sub2.getTime().setSelectedTimeIndices(sub2SelectedTimes);
assertThat(dupeChecker.getForecastHourDuplicationPercent(sub1, sub2),
is(33));
assertThat(dupeChecker.getForecastHourDuplicationPercent(sub2, sub1),
is(50));
}
@Test
public void returnsZeroPercentOfForecastHoursForNullsOrEmpties() {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
sub1.getTime().setSelectedTimeIndices(null);
final List<Integer> sub2SelectedTimes = Arrays.asList(0, 3, 4);
sub2.getTime().setSelectedTimeIndices(sub2SelectedTimes);
assertThat(dupeChecker.getForecastHourDuplicationPercent(sub1, sub2),
is(0));
assertThat(dupeChecker.getForecastHourDuplicationPercent(sub2, sub1),
is(0));
sub1.getTime()
.setSelectedTimeIndices(Collections.<Integer> emptyList());
assertThat(dupeChecker.getForecastHourDuplicationPercent(sub1, sub2),
is(0));
assertThat(dupeChecker.getForecastHourDuplicationPercent(sub2, sub1),
is(0));
}
@Test
public void returnsPercentOfCyclesThatAreTheSame() {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
final List<Integer> sub1CycleTimes = Arrays.asList(0, 6);
sub1.getTime().setCycleTimes(sub1CycleTimes);
final List<Integer> sub2CycleTimes = Arrays.asList(0, 12, 18);
sub2.getTime().setCycleTimes(sub2CycleTimes);
assertThat(dupeChecker.getCycleDuplicationPercent(sub1, sub2),
is(33));
assertThat(dupeChecker.getCycleDuplicationPercent(sub2, sub1),
is(50));
}
@Test
public void returnsZeroPercentOfCyclesForNullsOrEmpties() {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
sub1.getTime().setCycleTimes(null);
final List<Integer> cycleTimes = Arrays.asList(0, 3, 4);
sub2.getTime().setCycleTimes(cycleTimes);
assertThat(dupeChecker.getCycleDuplicationPercent(sub1, sub2), is(0));
assertThat(dupeChecker.getCycleDuplicationPercent(sub2, sub1), is(0));
sub1.getTime().setCycleTimes(Collections.<Integer> emptyList());
assertThat(dupeChecker.getCycleDuplicationPercent(sub1, sub2), is(0));
assertThat(dupeChecker.getCycleDuplicationPercent(sub2, sub1), is(0));
}
@Test
public void returnsPercentOfSpatialThatIsTheSame()
throws TransformException {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
ReferencedEnvelope envelope1 = new ReferencedEnvelope(new Envelope(
new Coordinate(-5, 0), new Coordinate(0, 5)),
MapUtil.LATLON_PROJECTION);
// dx = 6, dy = 3, area = 18
ReferencedEnvelope envelope2 = new ReferencedEnvelope(new Envelope(
new Coordinate(-3, 3), new Coordinate(3, 6)),
MapUtil.LATLON_PROJECTION);
// The intersection should have coordinates: (-3, 3) (0, 5)
// dx = 3, dy = 2, area = 6
sub1.getCoverage().setRequestEnvelope(envelope1);
sub2.getCoverage().setRequestEnvelope(envelope2);
// The expected percent overlap: 6 / 18 = .33
assertThat(dupeChecker.getSpatialDuplicationPercent(sub1, sub2), is(33));
}
@Test
public void returnsZeroPercentOfSpatialWhenNoOverlap()
throws TransformException {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
ReferencedEnvelope envelope1 = new ReferencedEnvelope(new Envelope(
new Coordinate(-5, 0), new Coordinate(0, 5)),
MapUtil.LATLON_PROJECTION);
ReferencedEnvelope envelope2 = new ReferencedEnvelope(new Envelope(
new Coordinate(-10, -20), new Coordinate(-6, -15)),
MapUtil.LATLON_PROJECTION);
sub1.getCoverage().setRequestEnvelope(envelope1);
sub2.getCoverage().setRequestEnvelope(envelope2);
assertThat(dupeChecker.getSpatialDuplicationPercent(sub1, sub2), is(0));
}
@Test
public void returnsZeroPercentOfSpatialForNulls() throws TransformException {
final UserSubscription sub1 = SubscriptionFixture.INSTANCE.get(1);
final UserSubscription sub2 = SubscriptionFixture.INSTANCE.get(2);
sub1.setCoverage(null);
assertThat(dupeChecker.getSpatialDuplicationPercent(sub1, sub2), is(0));
assertThat(dupeChecker.getSpatialDuplicationPercent(sub2, sub1), is(0));
// No envelope set
sub1.setCoverage(new GriddedCoverage());
assertThat(dupeChecker.getSpatialDuplicationPercent(sub1, sub2), is(0));
assertThat(dupeChecker.getSpatialDuplicationPercent(sub2, sub1), is(0));
}
}

View file

@ -0,0 +1,129 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import static com.raytheon.uf.common.datadelivery.service.subscription.SubscriptionOverlapMatchStrategy.AT_LEAST_HALF;
import static com.raytheon.uf.common.datadelivery.service.subscription.SubscriptionOverlapMatchStrategy.MATCH_ALL;
import static com.raytheon.uf.common.datadelivery.service.subscription.SubscriptionOverlapMatchStrategy.MATCH_ANY;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
/**
* Test {@link SubscriptionOverlapMatchStrategy}.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 14, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public class SubscriptionOverlapMatchStrategyTest {
private static final SubscriptionOverlapConfig MUST_EXCEED_FIFTY_PERCENT = new SubscriptionOverlapConfig(
50, 50, 50, 50, null);
@Test
public void matchAnyReturnsTrueIfAnyExceedMaxAllowed() {
assertThat(MATCH_ANY.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55, 45,
45, 45), is(true));
assertThat(MATCH_ANY.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45, 55,
45, 45), is(true));
assertThat(MATCH_ANY.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45, 45,
55, 45), is(true));
assertThat(MATCH_ANY.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45, 45,
45, 55), is(true));
}
@Test
public void matchAnyReturnsFalseIfNoneExceedMaxAllowed() {
assertThat(MATCH_ANY.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 50, 50,
50, 50), is(false));
assertThat(
MATCH_ANY.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 0, 0, 0, 0),
is(false));
assertThat(MATCH_ANY.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 25, 25,
25, 25), is(false));
}
@Test
public void matchAllReturnsTrueIfAllExceedMaxAllowed() {
assertThat(MATCH_ALL.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55, 55,
55, 55), is(true));
assertThat(MATCH_ALL.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 100, 100,
100, 100), is(true));
}
@Test
public void matchAllReturnsFalseIfNotAllExceedMaxAllowed() {
assertThat(MATCH_ALL.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55, 55,
55, 45), is(false));
assertThat(MATCH_ALL.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55, 55,
45, 55), is(false));
assertThat(MATCH_ALL.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55, 45,
55, 55), is(false));
assertThat(MATCH_ALL.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45, 55,
55, 55), is(false));
}
@Test
public void atLeastHalfReturnsTrueIfAllExceedMaxAllowed() {
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55,
55, 55, 55), is(true));
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 100,
100, 100, 100), is(true));
}
@Test
public void atLeastHalfReturnsTrueIfHalfExceedMaxAllowed() {
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45,
45, 55, 55), is(true));
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55,
55, 45, 45), is(true));
}
@Test
public void atLeastHalfReturnsFalseIfLessThanHalfExceedMaxAllowed() {
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45,
45, 45, 55), is(false));
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45,
45, 55, 45), is(false));
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 45,
55, 45, 45), is(false));
assertThat(AT_LEAST_HALF.isOverlapping(MUST_EXCEED_FIFTY_PERCENT, 55,
45, 45, 45), is(false));
}
}

View file

@ -0,0 +1,229 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.uf.common.datadelivery.service.subscription;
import static com.raytheon.uf.common.datadelivery.service.subscription.SubscriptionOverlapMatchStrategy.MATCH_ALL;
import static com.raytheon.uf.common.datadelivery.service.subscription.SubscriptionOverlapMatchStrategy.MATCH_ANY;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.datadelivery.registry.Subscription;
import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture;
import com.raytheon.uf.common.localization.PathManagerFactoryTest;
import com.raytheon.uf.common.serialization.SerializationException;
/**
* Test {@link SubscriptionOverlapService}.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 07, 2013 2000 djohnson Initial creation
*
* </pre>
*
* @author djohnson
* @version 1.0
*/
public class SubscriptionOverlapServiceTest {
private static final SubscriptionOverlapConfig ANY_MUST_EXCEED_65_PERCENT = new SubscriptionOverlapConfig(
65, 65, 65, 65, MATCH_ANY);
private static final SubscriptionOverlapConfig ALL_MUST_EXCEED_65_PERCENT = new SubscriptionOverlapConfig(
65, 65, 65, 65, MATCH_ALL);
private final ISubscriptionDuplicateChecker duplicateChecker = mock(ISubscriptionDuplicateChecker.class);
private final SubscriptionOverlapService service = new SubscriptionOverlapService(
duplicateChecker);
private final Subscription sub1 = SubscriptionFixture.INSTANCE.get(1);
private final Subscription sub2 = SubscriptionFixture.INSTANCE.get(2);
@Before
public void setUp() {
PathManagerFactoryTest.initLocalization();
}
@Test
public void moreParametersInCommonThanAllowedOverlaps() {
when(duplicateChecker.getParameterDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(true));
}
@Test
public void lessParametersInCommonThanAllowedDoesNotOverlap() {
when(duplicateChecker.getParameterDuplicationPercent(sub1, sub2))
.thenReturn(64);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(false));
}
@Test
public void moreForecastHoursInCommonThanAllowedOverlaps() {
when(duplicateChecker.getForecastHourDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(true));
}
@Test
public void lessForecastHoursInCommonThanAllowedDoesNotOverlap() {
when(duplicateChecker.getForecastHourDuplicationPercent(sub1, sub2))
.thenReturn(64);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(false));
}
@Test
public void moreCyclesInCommonThanAllowedOverlaps() {
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(true));
}
@Test
public void lessCyclesInCommonThanAllowedDoesNotOverlap() {
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(64);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(false));
}
@Test
public void moreSpatialInCommonThanAllowedOverlaps()
throws TransformException {
when(duplicateChecker.getSpatialDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(true));
}
@Test
public void lessSpatialInCommonThanAllowedDoesNotOverlap()
throws TransformException {
when(duplicateChecker.getSpatialDuplicationPercent(sub1, sub2))
.thenReturn(64);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(false));
}
@Test
public void matchesAnyTrueWillConsiderOneExceededValueAsOverlaps()
throws SerializationException {
service.writeNewConfig(ANY_MUST_EXCEED_65_PERCENT);
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(true));
}
@Test
public void matchesAnyFalseWillNotConsiderOneExceededValueAsOverlaps()
throws SerializationException {
service.writeNewConfig(ALL_MUST_EXCEED_65_PERCENT);
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(false));
}
@Test
public void matchesAnyTrueWillConsiderAllExceededValuesAsOverlaps()
throws SerializationException, TransformException {
service.writeNewConfig(ANY_MUST_EXCEED_65_PERCENT);
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(66);
when(duplicateChecker.getForecastHourDuplicationPercent(sub1, sub2))
.thenReturn(66);
when(duplicateChecker.getParameterDuplicationPercent(sub1, sub2))
.thenReturn(66);
when(duplicateChecker.getSpatialDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(true));
}
@Test
public void matchesAnyFalseWillConsiderAllExceededValuesAsOverlaps()
throws SerializationException, TransformException {
service.writeNewConfig(ALL_MUST_EXCEED_65_PERCENT);
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(66);
when(duplicateChecker.getForecastHourDuplicationPercent(sub1, sub2))
.thenReturn(66);
when(duplicateChecker.getParameterDuplicationPercent(sub1, sub2))
.thenReturn(66);
when(duplicateChecker.getSpatialDuplicationPercent(sub1, sub2))
.thenReturn(66);
assertThat(service.isOverlapping(sub1, sub2).isOverlapping(), is(true));
}
@Test
public void whenAllComparisonsReturnOneHundredPercentReturnsDuplicate()
throws SerializationException, TransformException {
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(100);
when(duplicateChecker.getForecastHourDuplicationPercent(sub1, sub2))
.thenReturn(100);
when(duplicateChecker.getParameterDuplicationPercent(sub1, sub2))
.thenReturn(100);
when(duplicateChecker.getSpatialDuplicationPercent(sub1, sub2))
.thenReturn(100);
assertThat(service.isOverlapping(sub1, sub2).isDuplicate(), is(true));
}
@Test
public void whenAllComparisonsDontReturnOneHundredPercentReturnsNotDuplicate()
throws SerializationException, TransformException {
when(duplicateChecker.getCycleDuplicationPercent(sub1, sub2))
.thenReturn(100);
when(duplicateChecker.getForecastHourDuplicationPercent(sub1, sub2))
.thenReturn(100);
when(duplicateChecker.getParameterDuplicationPercent(sub1, sub2))
.thenReturn(100);
when(duplicateChecker.getSpatialDuplicationPercent(sub1, sub2))
.thenReturn(99);
assertThat(service.isOverlapping(sub1, sub2).isDuplicate(), is(false));
}
}

View file

@ -25,10 +25,12 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.util.Arrays;
@ -49,8 +51,11 @@ import com.raytheon.uf.common.datadelivery.registry.SubscriptionFixture;
import com.raytheon.uf.common.datadelivery.registry.handlers.DataDeliveryHandlers;
import com.raytheon.uf.common.datadelivery.registry.handlers.ISubscriptionHandler;
import com.raytheon.uf.common.datadelivery.service.ISubscriptionNotificationService;
import com.raytheon.uf.common.datadelivery.service.subscription.ISubscriptionOverlapService;
import com.raytheon.uf.common.datadelivery.service.subscription.ISubscriptionOverlapService.ISubscriptionOverlapResponse;
import com.raytheon.uf.common.registry.handler.RegistryHandlerException;
import com.raytheon.uf.common.registry.handler.RegistryObjectHandlersUtil;
import com.raytheon.uf.common.util.FileUtil;
import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService.ISubscriptionServiceResult;
import com.raytheon.uf.viz.datadelivery.subscription.SubscriptionService.ForceApplyPromptResponse;
import com.raytheon.uf.viz.datadelivery.subscription.SubscriptionService.IDisplayForceApplyPrompt;
@ -70,6 +75,7 @@ import com.raytheon.uf.viz.datadelivery.subscription.SubscriptionService.IForceA
* Nov 7, 2012 1286 djohnson Initial creation
* Nov 20, 2012 1286 djohnson Rewrite to support proposing subscription stores/updates and force applying.
* Jan 02, 2012 1345 djohnson Fix broken tests from using VizApp to move work off the UI thread.
* May 08, 2000 2013 djohnson Allow checks for duplicate subscriptions.
*
* </pre>
*
@ -105,18 +111,20 @@ public abstract class AbstractSubscriptionServiceTest {
final IPermissionsService permissionsService = mock(IPermissionsService.class);
final ISubscriptionOverlapService subscriptionOverlapService = mock(ISubscriptionOverlapService.class);
final IDisplayForceApplyPrompt mockDisplay = mock(IDisplayForceApplyPrompt.class);
final SubscriptionService service = new SubscriptionService(
notificationService, mockBandwidthService, permissionsService,
mockDisplay);
subscriptionOverlapService, mockDisplay);
final IProposeScheduleResponse mockProposeScheduleResponse = mock(IProposeScheduleResponse.class);
final IForceApplyPromptDisplayText mockPromptDisplayText = mock(IForceApplyPromptDisplayText.class);
@Before
public void setUp() {
public void setUp() throws RegistryHandlerException {
RegistryObjectHandlersUtil.initMemory();
when(
@ -126,6 +134,14 @@ public abstract class AbstractSubscriptionServiceTest {
when(mockBandwidthService.proposeSchedule(any(Subscription.class)))
.thenReturn(mockProposeScheduleResponse);
// By default all tests will not find duplicate/overlapping
// subscriptions
final ISubscriptionOverlapResponse response = mock(ISubscriptionOverlapResponse.class);
when(
subscriptionOverlapService.isOverlapping(
any(Subscription.class), any(Subscription.class)))
.thenReturn(response);
setupForceApplyPromptDisplayTextValues();
}
@ -158,7 +174,7 @@ public abstract class AbstractSubscriptionServiceTest {
performServiceInteraction();
verifyZeroInteractions(DataDeliveryHandlers.getSubscriptionHandler());
verifyOnlyCheckingForDuplicateSubscriptions();
}
@Test
@ -295,9 +311,7 @@ public abstract class AbstractSubscriptionServiceTest {
performServiceInteraction();
final ISubscriptionHandler subscriptionHandler = DataDeliveryHandlers
.getSubscriptionHandler();
verifyZeroInteractions(subscriptionHandler);
verifyOnlyCheckingForDuplicateSubscriptions();
}
@Test
@ -330,6 +344,45 @@ public abstract class AbstractSubscriptionServiceTest {
verifyBandwidthManagerReinitializeInvoked();
}
@Test
public void testOverlappingSubscriptionsNotifiesUser()
throws RegistryHandlerException {
final ISubscriptionHandler subscriptionHandler = DataDeliveryHandlers
.getSubscriptionHandler();
// Store a duplicate subscription
Subscription duplicateSub = sub1.copy("duplicateSub");
subscriptionHandler.store(duplicateSub);
final ISubscriptionOverlapResponse response = mock(ISubscriptionOverlapResponse.class);
when(subscriptionOverlapService.isOverlapping(duplicateSub, sub1))
.thenReturn(response);
when(response.isOverlapping()).thenReturn(true);
performServiceInteraction();
verify(mockDisplay).displayMessage(
mockPromptDisplayText,
ISubscriptionOverlapService.OVERLAPPING_SUBSCRIPTIONS
+ FileUtil.EOL
+ duplicateSub.getName());
}
/**
* Verifies that the only interactions with the subscription handler are to
* check for duplicate/overlapping subscriptions.
*
* @throws RegistryHandlerException
*/
protected void verifyOnlyCheckingForDuplicateSubscriptions()
throws RegistryHandlerException {
final ISubscriptionHandler subscriptionHandler = DataDeliveryHandlers
.getSubscriptionHandler();
verify(subscriptionHandler, atLeastOnce())
.getActiveByDataSetAndProvider(anyString(), anyString());
verifyNoMoreInteractions(subscriptionHandler);
}
/**
* Verifies that the bandwidth manager was requested to reinitialize itself
* from the persistent store.

View file

@ -28,7 +28,6 @@ import static org.mockito.Matchers.same;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.Collections;
@ -60,6 +59,7 @@ import com.raytheon.uf.viz.datadelivery.subscription.ISubscriptionService.ISubsc
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Nov 21, 2012 1286 djohnson Initial creation
* May 08, 2000 2013 djohnson Allow checks for duplicate subscriptions.
*
* </pre>
*
@ -86,7 +86,7 @@ public class SubscriptionServiceMassUpdateTest extends
service.updateWithPendingCheck(subs, mockPromptDisplayText);
verifyZeroInteractions(DataDeliveryHandlers.getSubscriptionHandler());
verifyOnlyCheckingForDuplicateSubscriptions();
}
@Test

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<subscriptionOverlapConfig>
<!-- Each value is represented by a percent, 0-100 -->
<maxAllowedParameterDuplication>65</maxAllowedParameterDuplication>
<maxAllowedForecastHourDuplication>65</maxAllowedForecastHourDuplication>
<maxAllowedCycleDuplication>65</maxAllowedCycleDuplication>
<maxAllowedSpatialDuplication>65</maxAllowedSpatialDuplication>
<!--
Available options:
MATCH_ANY: Any of the maxAllowed options will
cause the subscription to be considered overlapping.
MATCH_ALL: All maxAllowed options must be exceeded
to cause the subscription to be considered overlapping.
AT_LEAST_HALF: At least half of the maxAllowed options
must be exceeded to cause the subscription to be considered
overlapping.
-->
<matchStrategy>MATCH_ANY</matchStrategy>
</subscriptionOverlapConfig>