/*
* Copyright (C) 2005-2013 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.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
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.repo.security.permissions.AccessDeniedException;
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.util.ISO8601DateFormat;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Preference Service Implementation
*
* @author Roy Wetherall
*/
public class PreferenceServiceImpl implements PreferenceService
{
private static final Log log = LogFactory.getLog(PreferenceServiceImpl.class);
private static final String SHARE_SITES_PREFERENCE_KEY = "org.alfresco.share.sites.favourites.";
private static final int SHARE_SITES_PREFERENCE_KEY_LEN = SHARE_SITES_PREFERENCE_KEY.length();
private static final String EXT_SITES_PREFERENCE_KEY = "org.alfresco.ext.sites.favourites.";
/** Node service */
private NodeService nodeService;
private ContentService contentService;
private PersonService personService;
private PermissionService permissionService;
/** Authentication Service */
private AuthenticationContext authenticationContext;
private AuthorityService authorityService;
/**
* Set the node service
*
* @param nodeService the node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* Set the person service
*
* @param personService the person service
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setAuthenticationContext(AuthenticationContext authenticationContext)
{
this.authenticationContext = authenticationContext;
}
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);
}
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("Cannot get preferences for " + userName
+ " because he/she does not exist.");
}
String currentUserName = AuthenticationUtil.getFullyAuthenticatedUser();
boolean isSystem = AuthenticationUtil.isRunAsUserTheSystemUser() || authenticationContext.isSystemUserName(currentUserName);
if (isSystem || userName.equals(currentUserName)
|| personService.getUserIdentifier(userName).equals(personService.getUserIdentifier(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 AccessDeniedException("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;
}
/**
* @see org.alfresco.repo.person.PersonService#getPreferences(java.lang.String, java.lang.String)
*/
@SuppressWarnings({ "unchecked" })
public Map getPreferences(String userName, String preferenceFilter)
{
if (log.isTraceEnabled()) { log.trace("getPreferences(" + userName + ", " + 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();
Serializable value = (Serializable)jsonPrefs.get(key);
if(key.startsWith(SHARE_SITES_PREFERENCE_KEY))
{
// CLOUD-1518: convert site preferences on the fly
// convert keys as follows:
// ..favourited -> .
// ..createdAt -> ..createdAt
if(key.endsWith(".favourited"))
{
int idx = key.indexOf(".favourited");
String siteId = key.substring(SHARE_SITES_PREFERENCE_KEY_LEN, idx);
StringBuilder sb = new StringBuilder(SHARE_SITES_PREFERENCE_KEY);
sb.append(siteId);
key = sb.toString();
}
else if(key.endsWith(".createdAt"))
{
int idx = key.indexOf(".createdAt");
String siteId = key.substring(SHARE_SITES_PREFERENCE_KEY_LEN, idx);
StringBuilder sb = new StringBuilder(EXT_SITES_PREFERENCE_KEY);
sb.append(siteId);
sb.append(".createdAt");
key = sb.toString();
}
else if(preferences.containsKey(key))
{
// Ensure that the values of the following form (the only other important form in this case) does not
// override those on the lhs from above:
// .
continue;
}
}
if (preferenceFilter == null ||
preferenceFilter.length() == 0 ||
matchPreferenceNames(key, preferenceFilter))
{
preferences.put(key, value);
}
}
}
}
catch (JSONException exception)
{
throw new AlfrescoRuntimeException("Can not get preferences for " + userName + " because there was an error parsing the JSON data.", exception);
}
if (log.isTraceEnabled()) { log.trace("result = " + preferences); }
return preferences;
}
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("\\+");
if(matchToArr.length > nameArr.length)
{
return false;
}
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("Cannot update preferences for " + userName
+ " because he/she does not exist.");
}
if (userCanWritePreferences(userName, personNodeRef))
{
AuthenticationUtil.runAs(new RunAsWork