Coverage Report - org.apache.shindig.social.opensocial.service.AppDataHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
AppDataHandler
97%
30/31
68%
19/28
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements. See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership. The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License. You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied. See the License for the
 16  
  * specific language governing permissions and limitations under the License.
 17  
  */
 18  
 package org.apache.shindig.social.opensocial.service;
 19  
 
 20  
 import org.apache.shindig.social.ResponseError;
 21  
 import org.apache.shindig.social.opensocial.spi.AppDataService;
 22  
 import org.apache.shindig.social.opensocial.spi.SocialSpiException;
 23  
 import org.apache.shindig.social.opensocial.spi.UserId;
 24  
 
 25  
 import com.google.inject.Inject;
 26  
 
 27  
 import java.util.HashMap;
 28  
 import java.util.Map;
 29  
 import java.util.Set;
 30  
 import java.util.concurrent.Future;
 31  
 
 32  
 public class AppDataHandler extends DataRequestHandler {
 33  
 
 34  
   private final AppDataService service;
 35  
 
 36  
   private static final String APP_DATA_PATH = "/appdata/{userId}+/{groupId}/{appId}";
 37  
 
 38  
   @Inject
 39  34
   public AppDataHandler(AppDataService service) {
 40  34
     this.service = service;
 41  34
   }
 42  
 
 43  
   /**
 44  
    * Allowed endpoints /appdata/{userId}/{groupId}/{appId} - fields={field1, field2}
 45  
    *
 46  
    * examples: /appdata/john.doe/@friends/app?fields=count /appdata/john.doe/@self/app
 47  
    *
 48  
    * The post data should be a regular json object. All of the fields vars will be pulled from the
 49  
    * values and set on the person object. If there are no fields vars then all of the data will be
 50  
    * overridden.
 51  
    */
 52  
   @Override
 53  
   protected Future<?> handleDelete(RequestItem request)
 54  
       throws SocialSpiException {
 55  5
     request.applyUrlTemplate(APP_DATA_PATH);
 56  
 
 57  5
     Set<UserId> userIds = request.getUsers();
 58  
 
 59  5
     Preconditions.requireNotEmpty(userIds, "No userId specified");
 60  5
     Preconditions.requireSingular(userIds, "Multiple userIds not supported");
 61  
 
 62  5
     return service.deletePersonData(userIds.iterator().next(), request.getGroup(),
 63  
         request.getAppId(), request.getFields(), request.getToken());
 64  
   }
 65  
 
 66  
   /**
 67  
    * Allowed endpoints /appdata/{userId}/{groupId}/{appId} - fields={field1, field2}
 68  
    *
 69  
    * examples: /appdata/john.doe/@friends/app?fields=count /appdata/john.doe/@self/app
 70  
    *
 71  
    * The post data should be a regular json object. All of the fields vars will be pulled from the
 72  
    * values and set on the person object. If there are no fields vars then all of the data will be
 73  
    * overridden.
 74  
    */
 75  
   @Override
 76  
   protected Future<?> handlePut(RequestItem request) throws SocialSpiException {
 77  1
     return handlePost(request);
 78  
   }
 79  
 
 80  
   /**
 81  
    * /appdata/{userId}/{groupId}/{appId} - fields={field1, field2}
 82  
    *
 83  
    * examples: /appdata/john.doe/@friends/app?fields=count /appdata/john.doe/@self/app
 84  
    *
 85  
    * The post data should be a regular json object. All of the fields vars will be pulled from the
 86  
    * values and set. If there are no fields vars then all of the data will be overridden.
 87  
    */
 88  
   @Override
 89  
   protected Future<?> handlePost(RequestItem request) throws SocialSpiException {
 90  6
     request.applyUrlTemplate(APP_DATA_PATH);
 91  
 
 92  6
     Set<UserId> userIds = request.getUsers();
 93  
 
 94  6
     Preconditions.requireNotEmpty(userIds, "No userId specified");
 95  6
     Preconditions.requireSingular(userIds, "Multiple userIds not supported");
 96  
 
 97  6
     Map<String, String> values = request.getTypedParameter("data", HashMap.class);
 98  6
     for (String key : values.keySet()) {
 99  5
       if (!isValidKey(key)) {
 100  2
         throw new SocialSpiException(ResponseError.BAD_REQUEST,
 101  
             "One or more of the app data keys are invalid: " + key);
 102  
       }
 103  3
     }
 104  
 
 105  4
     return service.updatePersonData(userIds.iterator().next(), request.getGroup(),
 106  
         request.getAppId(), request.getFields(), values, request.getToken());
 107  
   }
 108  
 
 109  
   /**
 110  
    * /appdata/{userId}+/{groupId}/{appId} - fields={field1, field2}
 111  
    *
 112  
    * examples: /appdata/john.doe/@friends/app?fields=count /appdata/john.doe/@self/app
 113  
    */
 114  
   @Override
 115  
   protected Future<?> handleGet(RequestItem request) throws SocialSpiException {
 116  23
     request.applyUrlTemplate(APP_DATA_PATH);
 117  
 
 118  23
     Set<UserId> userIds = request.getUsers();
 119  
 
 120  
     // Preconditions
 121  23
     Preconditions.requireNotEmpty(userIds, "No userId specified");
 122  
 
 123  23
     return service.getPersonData(userIds, request.getGroup(),
 124  
         request.getAppId(), request.getFields(), request.getToken());
 125  
   }
 126  
 
 127  
   /**
 128  
    * Determines whether the input is a valid key. Valid keys match the regular expression [\w\-\.]+.
 129  
    * The logic is not done using java.util.regex.* as that is 20X slower.
 130  
    *
 131  
    * @param key the key to validate.
 132  
    * @return true if the key is a valid appdata key, false otherwise.
 133  
    */
 134  
   public static boolean isValidKey(String key) {
 135  5
     if (key == null || key.length() == 0) {
 136  1
       return false;
 137  
     }
 138  21
     for (int i = 0; i < key.length(); ++i) {
 139  18
       char c = key.charAt(i);
 140  18
       if ((c >= 'a' && c <= 'z') ||
 141  
           (c >= 'A' && c <= 'Z') ||
 142  
           (c >= '0' && c <= '9') ||
 143  
           (c == '-') ||
 144  
           (c == '_') ||
 145  
           (c == '.')) {
 146  0
         continue;
 147  
       }
 148  1
       return false;
 149  
     }
 150  3
     return true;
 151  
   }
 152  
 
 153  
 }
 154