Skip to content

Commit

Permalink
Add uri pattern matching logic and test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
neelam-kushwah committed Jul 6, 2024
1 parent 4606171 commit 52c0e3e
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 18 deletions.
12 changes: 8 additions & 4 deletions src/main/java/org/eclipse/uprotocol/uri/factory/UriFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
* URI Factory that builds URIs from protos.
*/
public interface UriFactory {
String WILDCARD_AUTHORITY = "*";
int WILDCARD_ENTITY_ID = 0xFFFF;
int WILDCARD_ENTITY_VERSION = 0xFF;
int WILDCARD_RESOURCE_ID = 0xFFFF;

/**
* Builds a UEntity for an protobuf generated code Service Descriptor.
Expand Down Expand Up @@ -68,8 +72,8 @@ static UUri fromProto(ServiceDescriptor descriptor, int resourceId, String autho
* @return Returns a UEntity for an protobuf generated code Service Descriptor.
*/
UUri ANY = UUri.newBuilder()
.setAuthorityName("*")
.setUeId(0xFFFF)
.setUeVersionMajor(0xFF)
.setResourceId(0xFFFF).build();
.setAuthorityName(WILDCARD_AUTHORITY)
.setUeId(WILDCARD_ENTITY_ID)
.setUeVersionMajor(WILDCARD_ENTITY_VERSION)
.setResourceId(WILDCARD_RESOURCE_ID).build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.eclipse.uprotocol.uri.serializer;

import org.eclipse.uprotocol.uri.factory.UriFactory;
import org.eclipse.uprotocol.uri.validator.UriValidator;
import org.eclipse.uprotocol.v1.UUri;

Expand All @@ -21,10 +22,7 @@
*/
public interface UriSerializer {

/**
* The wildcard id for a field.
*/
int WILDCARD_ID = 0xFFFF;


/**
* Support for serializing {@link UUri} objects into their String format.
Expand Down Expand Up @@ -113,12 +111,12 @@ static UUri deserialize(String uProtocolUri) {
}

// Ensure the major version is less than the wildcard
if (builder.getUeVersionMajor() > UriValidator.MAJOR_VERSION_WILDCARD) {
if (builder.getUeVersionMajor() > UriFactory.WILDCARD_ENTITY_VERSION) {
return UUri.getDefaultInstance();
}

// Ensure the resource id is less than the wildcard
if (builder.getResourceId() > WILDCARD_ID) {
if (builder.getResourceId() > UriFactory.WILDCARD_ENTITY_ID) {
return UUri.getDefaultInstance();
}

Expand Down
121 changes: 113 additions & 8 deletions src/main/java/org/eclipse/uprotocol/uri/validator/UriValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.eclipse.uprotocol.uri.validator;

import org.eclipse.uprotocol.uri.factory.UriFactory;
import org.eclipse.uprotocol.v1.UUri;

/**
Expand All @@ -29,10 +30,6 @@ public interface UriValidator {
*/
int DEFAULT_RESOURCE_ID = 0;

/**
* major version wildcard
*/
int MAJOR_VERSION_WILDCARD = 0xFF;

/**
* Indicates that this URI is an empty as it does not contain authority, entity,
Expand All @@ -47,16 +44,15 @@ static boolean isEmpty(UUri uri) {
}

/**
* Returns true if URI is of type RPC. A UUri is of type RPC if it contains the
* word rpc in the resource name
* and has an instance name and/or the id is less than MIN_TOPIC_ID.
* Returns true if URI is of type RPC. A UUri is of type RPC if its
* resource ID is less than MIN_TOPIC_ID and greater than RESOURCE_ID_RESPONSE.
*
* @param uri {@link UUri} to check if it is of type RPC method
* @return Returns true if URI is of type RPC.
*/
static boolean isRpcMethod(UUri uri) {
return !isEmpty(uri) &&
uri.getResourceId() != DEFAULT_RESOURCE_ID &&
uri.getResourceId() > DEFAULT_RESOURCE_ID &&
uri.getResourceId() < MIN_TOPIC_ID;
}

Expand Down Expand Up @@ -89,4 +85,113 @@ static boolean isDefaultResourceId(UUri uri) {
static boolean isTopic(UUri uri) {
return !isEmpty(uri) && uri.getResourceId() >= MIN_TOPIC_ID;
}

/**
* Checks if the authority of the uriToMatch matches the candidateUri.
* A match occurs if the authority name in uriToMatch is a wildcard
* or if both URIs have the same authority name.
*
* @param uriToMatch The URI to match.
* @param candidateUri The candidate URI to match against.
* @return True if the authority names match, False otherwise.
*/
static boolean matchesAuthority(UUri uriToMatch, UUri candidateUri) {
return UriFactory.WILDCARD_AUTHORITY.equals(uriToMatch.getAuthorityName()) ||
uriToMatch.getAuthorityName().equals(candidateUri.getAuthorityName());
}

/**
* Checks if the entity ID of the uriToMatch matches the candidateUri.
* A match occurs if the entity ID in uriToMatch is a wildcard (0xFFFF)
* or if the masked entity IDs of both URIs are equal.
* The entity ID masking is performed using a bitwise AND operation with
* 0xFFFF. If the result of the bitwise AND operation between the
* uriToMatch's entity ID and 0xFFFF is 0xFFFF, it indicates that the
* uriToMatch's entity ID is a wildcard and can match any entity ID.
* Otherwise, the function checks if the masked entity IDs of both URIs
* are equal, meaning that the relevant parts of their entity IDs match.
*
* @param uriToMatch The URI to match.
* @param candidateUri The candidate URI to match against.
* @return True if the entity IDs match, False otherwise.
*/
static boolean matchesEntityId(UUri uriToMatch, UUri candidateUri) {
return (uriToMatch.getUeId() & UriFactory.WILDCARD_ENTITY_ID) == UriFactory.WILDCARD_ENTITY_ID ||
(uriToMatch.getUeId() & UriFactory.WILDCARD_ENTITY_ID) ==
(candidateUri.getUeId() & UriFactory.WILDCARD_ENTITY_ID);
}

/**
* Checks if the entity instance of the uriToMatch matches the candidateUri.
* A match occurs if the upper 16 bits of the entity ID in uriToMatch are zero
* or if the upper 16 bits of the entity IDs of both URIs are equal.
*
* @param uriToMatch The URI to match.
* @param candidateUri The candidate URI to match against.
* @return True if the entity instances match, False otherwise.
*/
static boolean matchesEntityInstance(UUri uriToMatch, UUri candidateUri) {
return (uriToMatch.getUeId() & 0xFFFF0000) == 0x00000000 ||
(uriToMatch.getUeId() & 0xFFFF0000) == (candidateUri.getUeId() & 0xFFFF0000);
}

/**
* Checks if the entity version of the uriToMatch matches the candidateUri.
* A match occurs if the entity version in uriToMatch is a wildcard
* or if both URIs have the same entity version.
*
* @param uriToMatch The URI to match.
* @param candidateUri The candidate URI to match against.
* @return True if the entity versions match, False otherwise.
*/
static boolean matchesEntityVersion(UUri uriToMatch, UUri candidateUri) {
return UriFactory.WILDCARD_ENTITY_VERSION == uriToMatch.getUeVersionMajor() ||
uriToMatch.getUeVersionMajor() == candidateUri.getUeVersionMajor();
}

/**
* Checks if the entity of the uriToMatch matches the candidateUri.
* A match occurs if the entity ID, entity instance, and entity version
* of both URIs match according to their respective rules.
*
* @param uriToMatch The URI to match.
* @param candidateUri The candidate URI to match against.
* @return True if the entities match, False otherwise.
*/
static boolean matchesEntity(UUri uriToMatch, UUri candidateUri) {
return matchesEntityId(uriToMatch, candidateUri) &&
matchesEntityInstance(uriToMatch, candidateUri) &&
matchesEntityVersion(uriToMatch, candidateUri);
}

/**
* Checks if the resource of the uriToMatch matches the candidateUri.
* A match occurs if the resource ID in uriToMatch is a wildcard
* or if both URIs have the same resource ID.
*
* @param uriToMatch The URI to match.
* @param candidateUri The candidate URI to match against.
* @return True if the resource IDs match, False otherwise.
*/
static boolean matchesResource(UUri uriToMatch, UUri candidateUri) {
return UriFactory.WILDCARD_RESOURCE_ID == uriToMatch.getResourceId() ||
uriToMatch.getResourceId() == candidateUri.getResourceId();
}

/**
* Checks if the entire URI (authority, entity, and resource) of the uriToMatch
* matches the candidateUri. A match occurs if the authority, entity, and resource
* of both URIs match according to their respective rules.
*
* @param uriToMatch The URI to match.
* @param candidateUri The candidate URI to match against.
* @return True if the entire URIs match, False otherwise.
*/
static boolean matches(UUri uriToMatch, UUri candidateUri) {
return matchesAuthority(uriToMatch, candidateUri) &&
matchesEntity(uriToMatch, candidateUri) &&
matchesResource(uriToMatch, candidateUri);
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.eclipse.uprotocol.uri.validator;


import org.eclipse.uprotocol.uri.serializer.UriSerializer;
import org.eclipse.uprotocol.v1.UUri;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -166,4 +167,116 @@ public void test_isRpcMethod_should_be_false_when_resourceId_is_0() {
.setResourceId(0).build();
assertFalse(UriValidator.isRpcMethod(uri));
}

@Test
@DisplayName("Matches succeeds for identical URIs")
public void test_Matches_Succeeds_For_Identical_Uris() {
UUri patternUri = UriSerializer.deserialize("//authority/A410/3/1003");
UUri candidateUri = UriSerializer.deserialize("//authority/A410/3/1003");
assertTrue(UriValidator.matches(patternUri, candidateUri));
}

@Test
@DisplayName("Matches succeeds for pattern with wildcard authority")
public void test_Matches_Succeeds_For_Pattern_With_Wildcard_Authority() {
UUri patternUri = UriSerializer.deserialize("//*/A410/3/1003");
UUri candidateUri = UriSerializer.deserialize("//authority/A410/3/1003");
assertTrue(UriValidator.matches(patternUri, candidateUri));
}

@Test
@DisplayName("Matches succeeds for pattern with wildcard authority and local candidate URI")
public void test_Matches_Succeeds_For_Pattern_With_Wildcard_Authority_And_Local_Candidate_Uri() {
UUri patternUri = UriSerializer.deserialize("//*/A410/3/1003");
UUri candidateUri = UriSerializer.deserialize("/A410/3/1003");
assertTrue(UriValidator.matches(patternUri, candidateUri));
}

@Test
@DisplayName("Matches succeeds for pattern with wildcard entity ID")
public void test_Matches_Succeeds_For_Pattern_With_Wildcard_Entity_Id() {
UUri patternUri = UriSerializer.deserialize("//authority/FFFF/3/1003");
UUri candidateUri = UriSerializer.deserialize("//authority/A410/3/1003");
assertTrue(UriValidator.matches(patternUri, candidateUri));
}

@Test
@DisplayName("Matches succeeds for pattern with matching entity instance")
public void test_Matches_Succeeds_For_Pattern_With_Matching_Entity_Instance() {
UUri patternUri = UriSerializer.deserialize("//authority/A410/3/1003");
UUri candidateUri = UriSerializer.deserialize("//authority/2A410/3/1003");
assertTrue(UriValidator.matches(patternUri, candidateUri));
}

@Test
@DisplayName("Matches succeeds for pattern with wildcard entity version")
public void test_Matches_Succeeds_For_Pattern_With_Wildcard_Entity_Version() {
UUri patternUri = UriSerializer.deserialize("//authority/A410/FF/1003");
UUri candidateUri = UriSerializer.deserialize("//authority/A410/3/1003");
assertTrue(UriValidator.matches(patternUri, candidateUri));
}

@Test
@DisplayName("Matches succeeds for pattern with wildcard resource")
public void test_Matches_Succeeds_For_Pattern_With_Wildcard_Resource() {
UUri patternUri = UriSerializer.deserialize("//authority/A410/3/FFFF");
UUri candidateUri = UriSerializer.deserialize("//authority/A410/3/1003");
assertTrue(UriValidator.matches(patternUri, candidateUri));
}

@Test
@DisplayName("Matches fails for upper case authority")
public void test_Matches_Fail_For_Upper_Case_Authority() {
UUri pattern = UriSerializer.deserialize("//Authority/A410/3/1003");
UUri candidate = UriSerializer.deserialize("//authority/A410/3/1003");
assertFalse(UriValidator.matches(pattern, candidate));
}

@Test
@DisplayName("Matches fails for local pattern with authority")
public void test_Matches_Fail_For_Local_Pattern_With_Authority() {
UUri pattern = UriSerializer.deserialize("/A410/3/1003");
UUri candidate = UriSerializer.deserialize("//authority/A410/3/1003");
assertFalse(UriValidator.matches(pattern, candidate));
}

@Test
@DisplayName("Matches fails for different authority")
public void test_Matches_Fail_For_Different_Authority() {
UUri pattern = UriSerializer.deserialize("//other/A410/3/1003");
UUri candidate = UriSerializer.deserialize("//authority/A410/3/1003");
assertFalse(UriValidator.matches(pattern, candidate));
}

@Test
@DisplayName("Matches fails for different entity ID")
public void test_Matches_Fail_For_Different_Entity_Id() {
UUri pattern = UriSerializer.deserialize("//authority/45/3/1003");
UUri candidate = UriSerializer.deserialize("//authority/A410/3/1003");
assertFalse(UriValidator.matches(pattern, candidate));
}

@Test
@DisplayName("Matches fails for different entity instance")
public void test_Matches_Fail_For_Different_Entity_Instance() {
UUri pattern = UriSerializer.deserialize("//authority/30A410/3/1003");
UUri candidate = UriSerializer.deserialize("//authority/2A410/3/1003");
assertFalse(UriValidator.matches(pattern, candidate));
}

@Test
@DisplayName("Matches fails for different entity version")
public void test_Matches_Fail_For_Different_Entity_Version() {
UUri pattern = UriSerializer.deserialize("//authority/A410/1/1003");
UUri candidate = UriSerializer.deserialize("//authority/A410/3/1003");
assertFalse(UriValidator.matches(pattern, candidate));
}

@Test
@DisplayName("Matches fails for different resource")
public void test_Matches_Fail_For_Different_Resource() {
UUri pattern = UriSerializer.deserialize("//authority/A410/3/ABCD");
UUri candidate = UriSerializer.deserialize("//authority/A410/3/1003");
assertFalse(UriValidator.matches(pattern, candidate));
}
}

0 comments on commit 52c0e3e

Please sign in to comment.