/* * Copyright (c) 2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wso2.carbon.registry.social.impl.appdata; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.registry.core.Registry; import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.social.api.SocialDataException; import org.wso2.carbon.registry.social.api.appdata.AppDataManager; import org.wso2.carbon.registry.social.impl.SocialImplConstants; import org.wso2.carbon.registry.social.impl.internal.SocialDSComponent; import org.wso2.carbon.registry.social.impl.people.relationship.RelationshipManagerImpl; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; /** * An implementation of the {@link org.wso2.carbon.registry.social.api.appdata.AppDataManager} interface * <p> * This implementation uses the {@link org.wso2.carbon.registry.core.Registry} to store app data * </p> * <p> * The app data is stored as a {@link org.wso2.carbon.registry.core.Registry} {@link org.wso2.carbon.registry.core.Resource} * The key-value pairs are stored as resource properties * </p> * <p> * <p/> * Each AppData key-value is grouped according to the appId of it * </p> * <p> * Resource path : /{AppData}/{appId}/[key][value] * </p> */ public class AppDataManagerImpl implements AppDataManager { private static Log log = LogFactory.getLog(AppDataManagerImpl.class); private Registry registry; /* Setting the Registry object */ public void setRegistry(Registry reg) { this.registry = reg; } /* The Registry object used throughout */ public Registry getRegistry() throws RegistryException { if (this.registry != null) { return this.registry; } else { return SocialDSComponent.getRegistry(); } } /** * Retrieves app data for the specified user list and group * * @param userIds A set of userIds whose app data to be retrieved * @param groupId The group * @param appId The app * @param fields The fields to return * @return A collection of appData for the given user list and group * @throws SocialDataException */ public Map<String, Map<String, String>> getPersonData(String[] userIds, String groupId, String appId, Set<String> fields) throws SocialDataException { List<String> userIdsToFetch = new ArrayList<String>(); // Check for groupId if (SocialImplConstants.GROUP_ID_FRIENDS.equals(groupId)) { for (String id : userIds) { String[] friendsList = new RelationshipManagerImpl().getRelationshipList(id); for (String friend : friendsList) { userIdsToFetch.add(friend); } } userIds = new String[userIdsToFetch.size()]; userIds = userIdsToFetch.toArray(userIds); } Map<String, Map<String, String>> personDataMap = new HashMap<String, Map<String, String>>(); for (String id : userIds) { try { Map<String, String> data = getAppData(id, appId, fields); if (data == null) { // log.error("No data found for the user " + id); return new HashMap<String, Map<String, String>>(); } personDataMap.put(id, data); } catch (RegistryException e) { log.error(e.getMessage(), e); throw new SocialDataException( "Error while retrieving app data with id " + appId + " for user " + id, e); } } return personDataMap; } /** * Deletes data for the specified user and group * * @param userId The userId of the person whose app data to be removed * @param groupId The group * @param appId The app * @param fields The fields to delete. Empty implies all * @throws SocialDataException */ public void deletePersonData(String userId, String groupId, String appId, Set<String> fields) throws SocialDataException { try { registry = getRegistry(); Resource appDataResource; String appDataResourcePath = SocialImplConstants.APP_DATA_REGISTRY_ROOT + SocialImplConstants.SEPARATOR + appId + SocialImplConstants.SEPARATOR + userId; if (registry.resourceExists(appDataResourcePath)) { appDataResource = registry.get(appDataResourcePath); for (String key : fields) { appDataResource.removeProperty(key); } registry.put(appDataResourcePath, appDataResource); } } catch (RegistryException e) { log.error(e.getMessage(), e); throw new SocialDataException( "Error while deleting app data with id " + appId + " for user " + userId, e); } } /** * Updates app data for the specified user and group with the new values * * @param userId The userId of the person whose app data to be modified * @param groupId The group * @param appId The app * @param fields The fields to update. Empty implies all * @param values The new values to set * @throws SocialDataException */ public void updatePersonData(String userId, String groupId, String appId, Set<String> fields, Map<String, String> values) throws SocialDataException { Set<String> fieldsToDelete = new TreeSet<String>(); // If a field is in the param list but not in the map, that means it is a delete // Retrieve the fields to delete for (String field : fields) { if (!values.containsKey(field)) { fieldsToDelete.add(field); } } List<String> userIdsToFetch = new ArrayList<String>(); // Check for groupId if (SocialImplConstants.GROUP_ID_FRIENDS.equals(groupId)) { String[] friendsList = new RelationshipManagerImpl().getRelationshipList(userId); for (String friend : friendsList) { userIdsToFetch.add(friend); } } else{ userIdsToFetch.add(userId); } for (String id : userIdsToFetch) { // Update the fields savePersonAppData(userId, appId, values, true); // Deletes the fields which are not in the Map but in the param list deletePersonData(userId, groupId, appId, fieldsToDelete); } } /** * Save app data for the specified user with the given values * * @param userId The userId of the person whose app data to be modified * @param appId The app * @param values The new values to set * @throws SocialDataException */ public void savePersonData(String userId, String appId, Map<String, String> values) throws SocialDataException { savePersonAppData(userId, appId, values, false); } /** * Adds/updates the Map of key-value pairs (appData) to the registry resource * * @param appDataResource The registry resource to add properties * @param values The Map of key-value appData * @param isUpdate true- if required to update the properties * false- if required to add the properties * @return The registry resource with the appData added as properties */ private Resource getAppDataAddedRegistryResource(Resource appDataResource, Map<String, String> values, boolean isUpdate) { for (Map.Entry<String, String> e : values.entrySet()) { /* for each key in the map */ if (e.getValue() != null) { /* if (isUpdate) {*/ String oldValue = appDataResource.getProperty(e.getKey()); if (oldValue != null) { appDataResource.editPropertyValue(e.getKey(), oldValue, e.getValue()); /* edit properties to the resource */ } /* } else {*/ else { appDataResource.addProperty(e.getKey(), e.getValue()); /* add properties to the resource */ } /* }*/ } } return appDataResource; } /** * Persists/update person Appdata as registry reource * * @param userId The id of the person to whom the appData belongs to * @param appId The id of the application to which the appData belongs to * @param values The appData key-value pairs * @param isUpdate True, if required to update the properties. Else false * @throws SocialDataException */ private void savePersonAppData(String userId, String appId, Map<String, String> values, boolean isUpdate) throws SocialDataException { try { registry = getRegistry(); Resource appDataResource; String appDataResourcePath = SocialImplConstants.APP_DATA_REGISTRY_ROOT + SocialImplConstants.SEPARATOR + appId + SocialImplConstants.SEPARATOR + userId; if (registry.resourceExists(appDataResourcePath)) { appDataResource = registry.get(appDataResourcePath); } else { appDataResource = registry.newCollection(); } appDataResource = getAppDataAddedRegistryResource(appDataResource, values, isUpdate); registry.put(appDataResourcePath, appDataResource); } catch (RegistryException e) { log.error(e.getMessage(), e); throw new SocialDataException( "Error while saving app data with id " + appId + " for user " + userId, e); } } /** * Fetches AppData for the given userId,appId,fields collection * * @param userId The id of the person to fetch the AppData * @param appId The appId to of the AppData to fetch * @param fields The fields of AppData to fetch * @return A Map<String,String> of AppData values * @throws RegistryException */ private Map<String, String> getAppData(String userId, String appId, Set<String> fields) throws RegistryException { Map<String, String> appDataMap = new HashMap<String, String>(); String appDataPath = SocialImplConstants.APP_DATA_REGISTRY_ROOT + SocialImplConstants.SEPARATOR + appId + SocialImplConstants.SEPARATOR + userId; Resource appDataResource; registry = getRegistry(); if (registry.resourceExists(appDataPath)) { appDataResource = registry.get(appDataPath); if (fields != null && fields.size()>0) { for (String key : fields) { String value; if ((value = appDataResource.getProperty(key)) != null) { appDataMap.put(key, value); } } } else { //Handle when fields is null -> get All properties // TODO: refactor code Properties props = appDataResource.getProperties(); for (Enumeration propKeys = props.keys(); propKeys.hasMoreElements();) { String key = propKeys.nextElement().toString(); String propValue=props.get(key).toString(); //TODO: Re-write this code appDataMap.put(key, propValue.substring(1,propValue.length()-1)); } } } else { return null; } return appDataMap; } }