/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
package org.alfresco.repo.preference;
import java.io.Serializable;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQueryPageDetails;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.preference.PreferenceService;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.util.Pair;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Preference Service Implementation
*
* @author Roy Wetherall
*/
public class PreferenceServiceImpl implements PreferenceService
{
private static final String FAVOURITE_SITES_PREFIX = "org.alfresco.share.sites.favourites.";
private static final int FAVOURITE_SITES_PREFIX_LENGTH = FAVOURITE_SITES_PREFIX.length();
/** Node service */
private NodeService nodeService;
/** Content service */
private ContentService contentService;
/** Person service */
private PersonService personService;
/** Site service */
private SiteService siteService;
/** Permission Service */
private PermissionService permissionService;
/** Authentication Service */
private AuthenticationContext authenticationContext;
/** Authority Service */
private AuthorityService authorityService;
/**
* Set the node service
*
* @param nodeService the node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Set the content service
*
* @param contentService the content service
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* Set the site service
*
* @param siteService the site service
*/
public void setSiteService(SiteService siteService)
{
this.siteService = siteService;
}
/**
* Set the person service
*
* @param personService the person service
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* Set the permission service
*
* @param permissionService the permission service
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* Set the authentication component
*
* @param authenticationContext the authentication component
*/
public void setAuthenticationContext(AuthenticationContext authenticationContext)
{
this.authenticationContext = authenticationContext;
}
/**
* @param authorityService the authorityService to set
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* @see org.alfresco.service.cmr.preference.PreferenceService#getPreferences(java.lang.String)
*/
public Map getPreferences(String userName)
{
return getPreferences(userName, null);
}
/**
* @see org.alfresco.repo.person.PersonService#getPreferences(java.lang.String, java.lang.String)
* java.lang.String)
*/
@SuppressWarnings("unchecked")
public Map getPreferences(String userName, String preferenceFilter)
{
Map preferences = new TreeMap();
try
{
JSONObject jsonPrefs = getPreferencesObject(userName);
if(jsonPrefs != null)
{
// Build hash from preferences stored in the repository
Iterator keys = jsonPrefs.keys();
while (keys.hasNext())
{
String key = (String)keys.next();
if (preferenceFilter == null ||
preferenceFilter.length() == 0 ||
matchPreferenceNames(key, preferenceFilter) == true)
{
preferences.put(key, (Serializable)jsonPrefs.get(key));
}
}
}
}
catch (JSONException exception)
{
throw new AlfrescoRuntimeException("Can not get preferences for " + userName + " because there was an error pasing the JSON data.", exception);
}
return preferences;
}
private PageDetails getPageDetails(PagingRequest pagingRequest, int totalSize)
{
int skipCount = pagingRequest.getSkipCount();
int maxItems = pagingRequest.getMaxItems();
int end = maxItems == CannedQueryPageDetails.DEFAULT_PAGE_SIZE ? totalSize : skipCount + maxItems;
int pageSize = (maxItems == CannedQueryPageDetails.DEFAULT_PAGE_SIZE ? totalSize : maxItems);
if(pageSize > totalSize - skipCount)
{
pageSize = totalSize - skipCount;
}
boolean hasMoreItems = end < totalSize;
return new PageDetails(pageSize, hasMoreItems, skipCount, maxItems, end);
}
private JSONObject getPreferencesObject(String userName) throws JSONException
{
JSONObject jsonPrefs = null;
// Get the user node reference
NodeRef personNodeRef = this.personService.getPerson(userName);
if (personNodeRef == null)
{
throw new AlfrescoRuntimeException("Could not get preferences for " + userName + " because they do not exist.");
}
String currentUserName = AuthenticationUtil.getFullyAuthenticatedUser();
if (userName.equals(currentUserName) ||
personService.getUserIdentifier(userName).equals(personService.getUserIdentifier(currentUserName)) ||
authenticationContext.isSystemUserName(currentUserName) ||
authorityService.isAdminAuthority(currentUserName))
{
// Check for preferences aspect
if (this.nodeService.hasAspect(personNodeRef, ContentModel.ASPECT_PREFERENCES) == true)
{
// Get the preferences for this user
ContentReader reader = this.contentService.getReader(personNodeRef,
ContentModel.PROP_PREFERENCE_VALUES);
if (reader != null)
{
jsonPrefs = new JSONObject(reader.getContentString());
}
}
}
else
{
// The current user does not have sufficient permissions to get
// the preferences for this user
throw new UnauthorizedAccessException("The current user " + currentUserName
+ " does not have sufficient permissions to get the preferences of the user " + userName);
}
return jsonPrefs;
}
public Serializable getPreference(String userName, String preferenceName)
{
String preferenceValue = null;
try
{
JSONObject jsonPrefs = getPreferencesObject(userName);
if(jsonPrefs != null)
{
if(jsonPrefs.has(preferenceName))
{
preferenceValue = jsonPrefs.getString(preferenceName);
}
}
}
catch (JSONException exception)
{
throw new AlfrescoRuntimeException("Can not get preferences for " + userName + " because there was an error pasing the JSON data.", exception);
}
return preferenceValue;
}
public PagingResults> getPagedPreferences(String userName, String preferenceFilter, PagingRequest pagingRequest)
{
final Map prefs = getPreferences(userName, preferenceFilter);
int totalSize = prefs.size();
int skipCount = pagingRequest.getSkipCount();
int maxItems = pagingRequest.getMaxItems();
int end = maxItems == CannedQueryPageDetails.DEFAULT_PAGE_SIZE ? totalSize : skipCount + maxItems;
int pageSize = (maxItems == CannedQueryPageDetails.DEFAULT_PAGE_SIZE ? totalSize : Math.max(maxItems, totalSize - skipCount));
final boolean hasMoreItems = end < totalSize;
final List> page = new ArrayList>(pageSize);
Iterator> it = prefs.entrySet().iterator();
for(int counter = 0; counter < end && it.hasNext(); counter++)
{
Map.Entry pref = it.next();
if(counter < skipCount)
{
continue;
}
if(counter > end - 1)
{
break;
}
page.add(new Pair(pref.getKey(), pref.getValue()));
}
return new PagingResults>()
{
@Override
public List> getPage()
{
return page;
}
@Override
public boolean hasMoreItems()
{
return hasMoreItems;
}
@Override
public Pair getTotalResultCount()
{
Integer total = Integer.valueOf(prefs.size());
return new Pair(total, total);
}
@Override
public String getQueryExecutionId()
{
return null;
}
};
}
/**
* Matches the preference name to the partial preference name provided
*
* @param name preference name
* @param matchTo match to the partial preference name provided
* @return boolean true if matches, false otherwise
*/
private boolean matchPreferenceNames(String name, String matchTo)
{
boolean result = true;
// Split strings
name = name.replace(".", "+");
String[] nameArr = name.split("\\+");
matchTo = matchTo.replace(".", "+");
String[] matchToArr = matchTo.split("\\+");
int index = 0;
for (String matchToElement : matchToArr)
{
if (matchToElement.equals(nameArr[index]) == false)
{
result = false;
break;
}
index++;
}
return result;
}
/**
* @see org.alfresco.repo.person.PersonService#setPreferences(java.lang.String,
* java.util.HashMap)
*/
public void setPreferences(final String userName, final Map preferences)
{
// Get the user node reference
final NodeRef personNodeRef = this.personService.getPerson(userName);
if (personNodeRef == null)
{
throw new AlfrescoRuntimeException("Could not update preferences for " + userName + " because they do not exist.");
}
if (userCanWritePreferences(userName, personNodeRef))
{
AuthenticationUtil.runAs(new RunAsWork