Search in sources :

Example 6 with CompoundKey

use of com.linkedin.restli.common.CompoundKey in project rest.li by linkedin.

the class GroupMembershipsResource3 method complexKeyToCompoundKey.

private static CompoundKey complexKeyToCompoundKey(ComplexResourceKey<GroupMembershipKey, GroupMembershipParam> id) {
    GroupMembershipKey key = id.getKey();
    CompoundKey compoundKey = new CompoundKey();
    compoundKey.append(GROUP_ID, key.getGroupID(GetMode.NULL));
    compoundKey.append(MEMBER_ID, key.getMemberID(GetMode.NULL));
    return compoundKey;
}
Also used : CompoundKey(com.linkedin.restli.common.CompoundKey) GroupMembershipKey(com.linkedin.restli.examples.groups.api.GroupMembershipKey)

Example 7 with CompoundKey

use of com.linkedin.restli.common.CompoundKey in project rest.li by linkedin.

the class TestGroupsClient method buildCompoundKey.

private static CompoundKey buildCompoundKey(int memberID, int groupID) {
    CompoundKey compoundKey = new CompoundKey();
    compoundKey.append("memberID", memberID);
    compoundKey.append("groupID", groupID);
    return compoundKey;
}
Also used : CompoundKey(com.linkedin.restli.common.CompoundKey)

Example 8 with CompoundKey

use of com.linkedin.restli.common.CompoundKey in project rest.li by linkedin.

the class ArgumentUtils method parseCompoundKey.

/**
   * The method parses out runtime-typesafe simple keys for the compound key based on the
   * provided key set for the resource.
   *
   *
   * @param urlString a string representation of the compound key.
   * @param keys a set of {@link com.linkedin.restli.server.Key} objects specifying
   *          names and types of the constituent simple keys
   * @return a runtime-typesafe CompoundKey
   * @throws IllegalArgumentException if there are unexpected key parts in the urlString that are not in keys,
   *         or any error in {@link ProtocolVersion} 1.0
   * @throws PathSegmentSyntaxException if the given string is not a valid encoded compound key
   */
public static CompoundKey parseCompoundKey(final String urlString, final Collection<Key> keys, final ProtocolVersion version) throws IllegalArgumentException, PathSegmentSyntaxException {
    if (urlString == null || urlString.trim().isEmpty()) {
        return null;
    }
    if (version.compareTo(AllProtocolVersions.RESTLI_PROTOCOL_2_0_0.getProtocolVersion()) >= 0) {
        return parseCompoundKeyV2(urlString, keys);
    } else {
        //There are two compound key syntaxes potentially in use by clients, depending on the version
        //of rest.li being used.  The syntaxes use different delimiters: ";" and ":" for the legacy
        //syntax, and "&" and "=" for the newer syntax.  When parsing compound keys, we do not
        //know which syntax the client used, and we cannot rely on correct percent-encoding of
        //delimiter characters for both syntaxes.  Therefore we simulate parsing using each syntax in
        //turn, and choose the best match.
        StringBuilder legacyParseError = new StringBuilder();
        StringBuilder currentParseError = new StringBuilder();
        CompoundKey legacyParsedKey = parseCompoundKey(urlString, keys, legacyParseError, LEGACY_SIMPLE_KEY_DELIMETER_PATTERN, LEGACY_KEY_VALUE_DELIMETER_PATTERN);
        CompoundKey currentParsedKey = parseCompoundKey(urlString, keys, currentParseError, SIMPLE_KEY_DELIMETER_PATTERN, KEY_VALUE_DELIMETER_PATTERN);
        if (legacyParsedKey != null && currentParsedKey != null) {
            boolean legacy = legacyParsedKey.getNumParts() > currentParsedKey.getNumParts();
            _log.warn("Ambiguous compound key syntax, using heuristic decision for '{}', legacy: {}", urlString, String.valueOf(legacy));
            return legacy ? legacyParsedKey : currentParsedKey;
        } else if (legacyParsedKey == null && currentParsedKey == null) {
            throw new IllegalArgumentException(currentParseError.toString());
        } else {
            return currentParsedKey == null ? legacyParsedKey : currentParsedKey;
        }
    }
}
Also used : CompoundKey(com.linkedin.restli.common.CompoundKey)

Example 9 with CompoundKey

use of com.linkedin.restli.common.CompoundKey in project rest.li by linkedin.

the class ArgumentUtils method parseCompoundKey.

/**
   * Parse {@link CompoundKey} from its String representation.
   *
   * @param urlString {@link CompoundKey} string representation
   * @param keys {@link CompoundKey} constituent keys' classes keyed on their names
   * @param errorMessageBuilder {@link StringBuilder} to build error message if necessary
   * @param simpleKeyDelimiterPattern delimiter of constituent keys in the compound key
   * @param keyValueDelimiterPattern delimiter of key and value in a constituent key
   * @return {@link CompoundKey} parsed from the input string
   */
public static CompoundKey parseCompoundKey(final String urlString, final Collection<Key> keys, final StringBuilder errorMessageBuilder, final Pattern simpleKeyDelimiterPattern, final Pattern keyValueDelimiterPattern) throws RoutingException {
    String[] simpleKeys = simpleKeyDelimiterPattern.split(urlString.trim());
    CompoundKey compoundKey = new CompoundKey();
    for (String simpleKey : simpleKeys) {
        String[] nameValuePair = keyValueDelimiterPattern.split(simpleKey.trim());
        if (simpleKey.trim().length() == 0 || nameValuePair.length != 2) {
            errorMessageBuilder.append("Bad key format '");
            errorMessageBuilder.append(urlString);
            errorMessageBuilder.append("'");
            return null;
        }
        // Simple key names and values are URL-encoded prior to being included in the URL on
        // the client, to prevent collision with any of the delimiter characters (bulk,
        // compound key and simple key-value). So, must decode them
        String name;
        try {
            name = URLDecoder.decode(nameValuePair[0], RestConstants.DEFAULT_CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            //should not happen, since we are using "UTF-8" as the encoding
            throw new RestLiInternalException(e);
        }
        // Key is not found in the set defined for the resource
        Key currentKey = getKeyWithName(keys, name);
        if (currentKey == null) {
            errorMessageBuilder.append("Unknown key part named '");
            errorMessageBuilder.append(name);
            errorMessageBuilder.append("'");
            return null;
        }
        String decodedStringValue;
        try {
            decodedStringValue = URLDecoder.decode(nameValuePair[1], RestConstants.DEFAULT_CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            //should not happen, since we are using "UTF-8" as the encoding
            throw new RestLiInternalException(e);
        }
        compoundKey.append(name, convertSimpleValue(decodedStringValue, currentKey.getDataSchema(), currentKey.getType()));
    }
    return compoundKey;
}
Also used : CompoundKey(com.linkedin.restli.common.CompoundKey) RestLiInternalException(com.linkedin.restli.internal.server.RestLiInternalException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) ComplexResourceKey(com.linkedin.restli.common.ComplexResourceKey) AlternativeKey(com.linkedin.restli.server.AlternativeKey) Key(com.linkedin.restli.server.Key) CompoundKey(com.linkedin.restli.common.CompoundKey)

Example 10 with CompoundKey

use of com.linkedin.restli.common.CompoundKey in project rest.li by linkedin.

the class TestRestLiMethodInvocation method testAsyncPut.

@SuppressWarnings("unchecked")
@Test
public void testAsyncPut() throws Exception {
    Map<String, ResourceModel> resourceModelMap = buildResourceModels(AsyncStatusCollectionResource.class, AsyncLocationResource.class, AsyncDiscoveredItemsResource.class);
    ResourceModel statusResourceModel = resourceModelMap.get("/asyncstatuses");
    ResourceModel locationResourceModel = statusResourceModel.getSubResource("asynclocation");
    ResourceModel followsAssociationResourceModel = buildResourceModel(AsyncFollowsAssociativeResource.class);
    ResourceModel discoveredItemsResourceModel = resourceModelMap.get("/asyncdiscovereditems");
    RestLiCallback<?> callback = getCallback();
    ResourceMethodDescriptor methodDescriptor;
    AsyncStatusCollectionResource statusResource;
    AsyncFollowsAssociativeResource followsResource;
    AsyncLocationResource locationResource;
    AsyncDiscoveredItemsResource discoveredItemsResource;
    // #1 Update on collection resource
    methodDescriptor = statusResourceModel.findMethod(ResourceMethod.UPDATE);
    statusResource = getMockResource(AsyncStatusCollectionResource.class);
    long id = eq(1L);
    Status status = (Status) EasyMock.anyObject();
    statusResource.update(id, status, EasyMock.<Callback<UpdateResponse>>anyObject());
    EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {

        @Override
        public Object answer() throws Throwable {
            @SuppressWarnings("unchecked") Callback<UpdateResponse> callback = (Callback<UpdateResponse>) EasyMock.getCurrentArguments()[2];
            callback.onSuccess(null);
            return null;
        }
    });
    EasyMock.replay(statusResource);
    checkAsyncInvocation(statusResource, callback, methodDescriptor, "PUT", version, "/asyncstatuses/1", "{}", buildPathKeys("statusID", 1L));
    // #2 Update on association resource
    methodDescriptor = followsAssociationResourceModel.findMethod(ResourceMethod.UPDATE);
    followsResource = getMockResource(AsyncFollowsAssociativeResource.class);
    CompoundKey rawKey = new CompoundKey();
    rawKey.append("followerID", 1L);
    rawKey.append("followeeID", 2L);
    CompoundKey key = eq(rawKey);
    Followed followed = (Followed) EasyMock.anyObject();
    followsResource.update(key, followed, (Callback<UpdateResponse>) EasyMock.anyObject());
    EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {

        @Override
        public Object answer() throws Throwable {
            Callback<UpdateResponse> callback = (Callback<UpdateResponse>) EasyMock.getCurrentArguments()[2];
            callback.onSuccess(null);
            return null;
        }
    });
    EasyMock.replay(followsResource);
    checkAsyncInvocation(followsResource, callback, methodDescriptor, "PUT", version, "/asyncfollows/(followerID:1,followeeID:2)", "{}", buildPathKeys("followerID", 1L, "followeeID", 2L, followsAssociationResourceModel.getKeyName(), rawKey));
    // #3 Update on simple resource
    methodDescriptor = locationResourceModel.findMethod(ResourceMethod.UPDATE);
    locationResource = getMockResource(AsyncLocationResource.class);
    Location location = (Location) EasyMock.anyObject();
    locationResource.update(location, EasyMock.<Callback<UpdateResponse>>anyObject());
    EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {

        @Override
        public Object answer() throws Throwable {
            @SuppressWarnings("unchecked") Callback<UpdateResponse> callback = (Callback<UpdateResponse>) EasyMock.getCurrentArguments()[1];
            callback.onSuccess(null);
            return null;
        }
    });
    EasyMock.replay(locationResource);
    checkAsyncInvocation(locationResource, callback, methodDescriptor, "PUT", version, "/asyncstatuses/1/asynclocation", "{}", buildPathKeys("statusID", 1L));
    // #4 Update on complex-key resource
    methodDescriptor = discoveredItemsResourceModel.findMethod(ResourceMethod.UPDATE);
    discoveredItemsResource = getMockResource(AsyncDiscoveredItemsResource.class);
    ComplexResourceKey<DiscoveredItemKey, DiscoveredItemKeyParams> complexKey = getDiscoveredItemComplexKey(1L, 2, 3L);
    discoveredItemsResource.update(eq(complexKey), (DiscoveredItem) EasyMock.anyObject(), EasyMock.<Callback<UpdateResponse>>anyObject());
    EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {

        @Override
        public Object answer() throws Throwable {
            @SuppressWarnings("unchecked") Callback<UpdateResponse> callback = (Callback<UpdateResponse>) EasyMock.getCurrentArguments()[2];
            callback.onSuccess(null);
            return null;
        }
    });
    EasyMock.replay(discoveredItemsResource);
    checkAsyncInvocation(discoveredItemsResource, callback, methodDescriptor, "PUT", version, "/asyncdiscovereditems/(itemId:1,type:2,userId:3)", "{}", buildPathKeys("asyncDiscoveredItemId", complexKey));
}
Also used : AsyncLocationResource(com.linkedin.restli.server.twitter.AsyncLocationResource) Status(com.linkedin.restli.server.twitter.TwitterTestDataModels.Status) HttpStatus(com.linkedin.restli.common.HttpStatus) AsyncDiscoveredItemsResource(com.linkedin.restli.server.twitter.AsyncDiscoveredItemsResource) CompoundKey(com.linkedin.restli.common.CompoundKey) ResourceMethodDescriptor(com.linkedin.restli.internal.server.model.ResourceMethodDescriptor) Followed(com.linkedin.restli.server.twitter.TwitterTestDataModels.Followed) ByteString(com.linkedin.data.ByteString) CustomString(com.linkedin.restli.server.custom.types.CustomString) AsyncFollowsAssociativeResource(com.linkedin.restli.server.twitter.AsyncFollowsAssociativeResource) AsyncStatusCollectionResource(com.linkedin.restli.server.twitter.AsyncStatusCollectionResource) UpdateResponse(com.linkedin.restli.server.UpdateResponse) Callback(com.linkedin.common.callback.Callback) RestLiCallback(com.linkedin.restli.internal.server.RestLiCallback) FilterChainCallback(com.linkedin.restli.internal.server.filter.FilterChainCallback) RequestExecutionCallback(com.linkedin.restli.server.RequestExecutionCallback) DiscoveredItemKeyParams(com.linkedin.restli.server.twitter.TwitterTestDataModels.DiscoveredItemKeyParams) ResourceModel(com.linkedin.restli.internal.server.model.ResourceModel) RestLiTestHelper.buildResourceModel(com.linkedin.restli.server.test.RestLiTestHelper.buildResourceModel) EasyMock.anyObject(org.easymock.EasyMock.anyObject) DiscoveredItemKey(com.linkedin.restli.server.twitter.TwitterTestDataModels.DiscoveredItemKey) Location(com.linkedin.restli.server.twitter.TwitterTestDataModels.Location) Test(org.testng.annotations.Test) AfterTest(org.testng.annotations.AfterTest) BeforeTest(org.testng.annotations.BeforeTest)

Aggregations

CompoundKey (com.linkedin.restli.common.CompoundKey)94 Test (org.testng.annotations.Test)48 HashMap (java.util.HashMap)26 DataProvider (org.testng.annotations.DataProvider)20 ComplexResourceKey (com.linkedin.restli.common.ComplexResourceKey)17 ResourceMethodDescriptor (com.linkedin.restli.internal.server.model.ResourceMethodDescriptor)16 GroupMembership (com.linkedin.restli.examples.groups.api.GroupMembership)15 ResourceModel (com.linkedin.restli.internal.server.model.ResourceModel)14 AfterTest (org.testng.annotations.AfterTest)13 BeforeTest (org.testng.annotations.BeforeTest)13 DataMap (com.linkedin.data.DataMap)12 RestLiTestHelper.buildResourceModel (com.linkedin.restli.server.test.RestLiTestHelper.buildResourceModel)12 Key (com.linkedin.restli.server.Key)11 Followed (com.linkedin.restli.server.twitter.TwitterTestDataModels.Followed)10 HashSet (java.util.HashSet)10 BatchKVResponse (com.linkedin.restli.client.response.BatchKVResponse)9 TestRecord (com.linkedin.restli.client.test.TestRecord)9 BatchUpdateResult (com.linkedin.restli.server.BatchUpdateResult)9 AsyncFollowsAssociativeResource (com.linkedin.restli.server.twitter.AsyncFollowsAssociativeResource)9 EmptyRecord (com.linkedin.restli.common.EmptyRecord)8