/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/kernel/trunk/kernel-impl/src/main/java/org/sakaiproject/user/impl/BasePreferencesService.java $
* $Id: BasePreferencesService.java 106070 2012-03-20 14:43:32Z matthew.buckett@oucs.ox.ac.uk $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2008 Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.user.impl;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.FunctionManager;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.entity.api.Edit;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.HttpAccess;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.api.ResourcePropertiesEdit;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.event.api.NotificationService;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.IdUsedException;
import org.sakaiproject.exception.InUseException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.memory.api.Cache;
import org.sakaiproject.memory.api.MemoryService;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.user.api.Preferences;
import org.sakaiproject.user.api.PreferencesEdit;
import org.sakaiproject.user.api.PreferencesService;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.util.BaseResourceProperties;
import org.sakaiproject.util.BaseResourcePropertiesEdit;
import org.sakaiproject.util.SingleStorageUser;
import org.sakaiproject.util.StringUtil;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.api.SessionBindingEvent;
import org.sakaiproject.tool.api.SessionBindingListener;
import org.sakaiproject.tool.api.SessionManager;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* <p>
* BasePreferencesService is a Sakai Preferences implementation.
* </p>
*/
public abstract class BasePreferencesService implements PreferencesService, SingleStorageUser
{
/** Our log (commons). */
private static Log M_log = LogFactory.getLog(BasePreferencesService.class);
/** Storage manager for this service. */
protected Storage m_storage = null;
/** The initial portion of a relative access point URL. */
protected String m_relativeAccessPoint = null;
/** The session cache variable for current user's preferences */
protected String ATTR_PREFERENCE = "attr_preference";
/** The session cache variable for indicating whether the current user's preference was null when last looked */
protected String ATTR_PREFERENCE_IS_NULL = "attr_preference_is_null";
/**
* Key used to store the locale preferences
*/
private static final String LOCALE_PREFERENCE_KEY = "sakai:resourceloader";
/** the cache for Preference objects **/
private Cache m_cache;
/**********************************************************************************************************************************************************************************************************************************************************
* Abstractions, etc.
*********************************************************************************************************************************************************************************************************************************************************/
/**
* Construct storage for this service.
*/
protected abstract Storage newStorage();
/**
* Access the partial URL that forms the root of resource URLs.
*
* @param relative
* if true, form within the access path only (i.e. starting with /content)
* @return the partial URL that forms the root of resource URLs.
*/
protected String getAccessPoint(boolean relative)
{
return (relative ? "" : serverConfigurationService().getAccessUrl()) + m_relativeAccessPoint;
}
/**
* @inheritDoc
*/
public String preferencesReference(String id)
{
return getAccessPoint(true) + Entity.SEPARATOR + id;
}
/**
* Access the preferences id extracted from a preferences reference.
*
* @param ref
* The preferences reference string.
* @return The the preferences id extracted from a preferences reference.
*/
protected String preferencesId(String ref)
{
String start = getAccessPoint(true) + Entity.SEPARATOR;
int i = ref.indexOf(start);
if (i == -1) return ref;
String id = ref.substring(i + start.length());
return id;
}
/**
* Check security permission.
*
* @param lock
* The lock id string.
* @param resource
* The resource reference string, or null if no resource is involved.
* @return true if allowd, false if not
*/
protected boolean unlockCheck(String lock, String resource)
{
if (!securityService().unlock(lock, resource))
{
return false;
}
return true;
}
/**
* Check security permission.
*
* @param lock
* The lock id string.
* @param resource
* The resource reference string, or null if no resource is involved.
* @exception PermissionException
* Thrown if the user does not have access
*/
protected void unlock(String lock, String resource) throws PermissionException
{
if (!unlockCheck(lock, resource))
{
throw new PermissionException(sessionManager().getCurrentSessionUserId(), lock, resource);
}
}
/**********************************************************************************************************************************************************************************************************************************************************
* Dependencies
*********************************************************************************************************************************************************************************************************************************************************/
/**
* @return the MemoryService collaborator.
*/
protected abstract MemoryService memoryService();
/**
* @return the ServerConfigurationService collaborator.
*/
protected abstract ServerConfigurationService serverConfigurationService();
/**
* @return the EntityManager collaborator.
*/
protected abstract EntityManager entityManager();
/**
* @return the SecurityService collaborator.
*/
protected abstract SecurityService securityService();
/**
* @return the FunctionManager collaborator.
*/
protected abstract FunctionManager functionManager();
/**
* @return the SessionManager collaborator.
*/
protected abstract SessionManager sessionManager();
/**
* @return the EventTrackingService collaborator.
*/
protected abstract EventTrackingService eventTrackingService();
/**
* @return the UserDirectoryService collaborator.
*/
protected abstract UserDirectoryService userDirectoryService();
/**********************************************************************************************************************************************************************************************************************************************************
* Init and Destroy
*********************************************************************************************************************************************************************************************************************************************************/
/**
* Final initialization, once all dependencies are set.
*/
public void init()
{
try
{
m_relativeAccessPoint = REFERENCE_ROOT;
// construct storage and read
m_storage = newStorage();
m_storage.open();
// register as an entity producer
entityManager().registerEntityProducer(this, REFERENCE_ROOT);
// register functions
functionManager().registerFunction(SECURE_ADD_PREFS);
functionManager().registerFunction(SECURE_EDIT_PREFS);
functionManager().registerFunction(SECURE_REMOVE_PREFS);
//register a cache
m_cache = memoryService().newCache(BasePreferencesService.class.getName() +".preferences");
M_log.info("init()");
}
catch (Exception t)
{
M_log.warn("init(): ", t);
}
}
/**
* Returns to uninitialized state.
*/
public void destroy()
{
m_storage.close();
m_storage = null;
M_log.info("destroy()");
}
/**********************************************************************************************************************************************************************************************************************************************************
* PreferencesService implementation
*********************************************************************************************************************************************************************************************************************************************************/
/**
* @inheritDoc
*/
public Preferences getPreferences(String id)
{
Preferences prefs = findPreferences(id);
// if not found at all
if (prefs == null)
{
// throwaway empty preferences %%%
prefs = new BasePreferences(id);
}
return prefs;
}
/**
* @inheritDoc
*/
public PreferencesEdit edit(String id) throws PermissionException, InUseException, IdUnusedException
{
// security
unlock(SECURE_EDIT_PREFS, preferencesReference(id));
// check for existance
if (!m_storage.check(id))
{
throw new IdUnusedException(id);
}
// ignore the cache - get the user with a lock from the info store
PreferencesEdit edit = m_storage.edit(id);
if (edit == null) throw new InUseException(id);
((BasePreferences) edit).setEvent(SECURE_EDIT_PREFS);
return edit;
}
/**
* @inheritDoc
*/
public void commit(PreferencesEdit edit)
{
if (edit != null)
{
// check for closed edit
if (!edit.isActiveEdit())
{
try
{
throw new Exception();
}
catch (Exception e)
{
M_log.warn("commit(): closed PreferencesEdit", e);
}
return;
}
// update the properties
// addLiveUpdateProperties(user.getPropertiesEdit());
//invalidate the cache
m_cache.remove(edit.getId());
// complete the edit
m_storage.commit(edit);
SessionManager sManager = sessionManager();
Session s = sManager.getCurrentSession();
// update the session cache if the preference is for current session user
if (sManager.getCurrentSessionUserId().equals(edit.getId()))
{
s.setAttribute(ATTR_PREFERENCE, new BasePreferences((BasePreferences) edit));
s.setAttribute(ATTR_PREFERENCE_IS_NULL, Boolean.FALSE);
}
// track it
eventTrackingService()
.post(eventTrackingService().newEvent(((BasePreferences) edit).getEvent(), edit.getReference(), true));
// close the edit object
((BasePreferences) edit).closeEdit();
}
}
/**
* @inheritDoc
*/
public void cancel(PreferencesEdit edit)
{
if (edit != null)
{
// if this was an add, remove it
if (SECURE_ADD_PREFS.equals(((BasePreferences) edit).m_event))
{
remove(edit);
}
else
{
// check for closed edit
if (!edit.isActiveEdit())
{
try
{
throw new Exception();
}
catch (Exception e)
{
M_log.warn("cancel(): closed PreferencesEdit", e);
}
return;
}
// release the edit lock
m_storage.cancel(edit);
// close the edit object
((BasePreferences) edit).closeEdit();
}
}
}
/**
* @inheritDoc
*/
public void remove(PreferencesEdit edit)
{
// check for closed edit
if (!edit.isActiveEdit())
{
try
{
throw new Exception();
}
catch (Exception e)
{
M_log.warn("remove(): closed PreferencesEdit", e);
}
return;
}
// complete the edit
m_storage.remove(edit);
m_cache.remove(edit.getId());
// track it
eventTrackingService().post(eventTrackingService().newEvent(SECURE_REMOVE_PREFS, edit.getReference(), true));
// close the edit object
((BasePreferences) edit).closeEdit();
}
/**
* Find the preferences object, in cache or storage.
*
* @param id
* The preferences id.
* @return The preferences object found in cache or storage, or null if not found.
*/
protected BasePreferences findPreferences(String id)
{
BasePreferences prefs = null;
if (id != null)
{
Session session = sessionManager().getCurrentSession();
if (id.equals(sessionManager().getCurrentSessionUserId()))
{
// if the preference is for current user
if (session.getAttribute(ATTR_PREFERENCE_IS_NULL)!=null)
{
if (!((Boolean) session.getAttribute(ATTR_PREFERENCE_IS_NULL)).booleanValue())
{
// if the session cache indicate the preference is not null, get the preferences from cache
prefs = new BasePreferences((BasePreferences) session.getAttribute(ATTR_PREFERENCE));
}
}
else
{
//is the preference in the cache?
if (m_cache.containsKey(id))
{
prefs = (BasePreferences) m_cache.get(id);
}
else
//otherwise, get preferences from storage and update caches
{
prefs = (BasePreferences) m_storage.get(id);
}
//its possible either call above returned null if the user has the default preferences
if (prefs != null)
{
session.setAttribute(ATTR_PREFERENCE_IS_NULL, Boolean.FALSE);
session.setAttribute(ATTR_PREFERENCE, new BasePreferences(prefs));
m_cache.put(id, prefs);
}
else
{
session.setAttribute(ATTR_PREFERENCE_IS_NULL, Boolean.TRUE);
session.removeAttribute(ATTR_PREFERENCE);
m_cache.put(id, null);
}
}
}
else
{
//is the preference in the cache
if (m_cache.containsKey(id))
{
prefs = (BasePreferences) m_cache.get(id);
}
else
{
// uf the preference is not for current user, ignore sessioncache completely
prefs = (BasePreferences) m_storage.get(id);
}
m_cache.put(id, prefs);
}
}
return prefs;
}
/**
** Get user's preferred locale (or null if not set)
***/
public Locale getLocale(String userId)
{
Locale loc = null;
Preferences prefs = getPreferences(userId);
ResourceProperties locProps = prefs.getProperties(LOCALE_PREFERENCE_KEY);
String localeString = locProps.getProperty(Preferences.FIELD_LOCALE);
// Parse user locale preference if set
if (localeString != null)
{
String[] locValues = localeString.split("_");
if (locValues.length > 2)
loc = new Locale(locValues[0], locValues[1], locValues[2]); // language, country, variant
else if (locValues.length == 2)
loc = new Locale(locValues[0], locValues[1]); // language, country
else if (locValues.length == 1)
loc = new Locale(locValues[0]); // just language
}
return loc;
}
/**
* @inheritDoc
*/
public boolean allowUpdate(String id)
{
return unlockCheck(SECURE_EDIT_PREFS, preferencesReference(id));
}
/**
* @inheritDoc
*/
public PreferencesEdit add(String id) throws PermissionException, IdUsedException
{
// check security (throws if not permitted)
unlock(SECURE_ADD_PREFS, preferencesReference(id));
// reserve a user with this id from the info store - if it's in use, this will return null
PreferencesEdit edit = m_storage.put(id);
if (edit == null)
{
throw new IdUsedException(id);
}
((BasePreferences) edit).setEvent(SECURE_ADD_PREFS);
return edit;
}
/**********************************************************************************************************************************************************************************************************************************************************
* EntityProducer implementation
*********************************************************************************************************************************************************************************************************************************************************/
/**
* @inheritDoc
*/
public String getLabel()
{
return "preferences";
}
/**
* @inheritDoc
*/
public boolean willArchiveMerge()
{
return false;
}
/**
* @inheritDoc
*/
public HttpAccess getHttpAccess()
{
return null;
}
/**
* @inheritDoc
*/
public boolean parseEntityReference(String reference, Reference ref)
{
// for preferences access
if (reference.startsWith(REFERENCE_ROOT))
{
String id = null;
// we will get null, service, user/preferences Id
String[] parts = StringUtil.split(reference, Entity.SEPARATOR);
if (parts.length > 2)
{
id = parts[2];
}
ref.set(APPLICATION_ID, null, id, null, null);
return true;
}
return false;
}
/**
* @inheritDoc
*/
public String getEntityDescription(Reference ref)
{
return null;
}
/**
* @inheritDoc
*/
public ResourceProperties getEntityResourceProperties(Reference ref)
{
return null;
}
/**
* @inheritDoc
*/
public Entity getEntity(Reference ref)
{
return null;
}
/**
* @inheritDoc
*/
public Collection getEntityAuthzGroups(Reference ref, String userId)
{
// double check that it's mine
if (!APPLICATION_ID.equals(ref.getType())) return null;
Collection rv = new Vector();
// for preferences access: no additional role realms
try
{
rv.add(userDirectoryService().userReference(ref.getId()));
ref.addUserTemplateAuthzGroup(rv, userId);
}
catch (NullPointerException e)
{
M_log.warn("getEntityAuthzGroups(): " + e);
}
return rv;
}
/**
* @inheritDoc
*/
public String getEntityUrl(Reference ref)
{
return null;
}
/**
* @inheritDoc
*/
public String archive(String siteId, Document doc, Stack stack, String archivePath, List attachments)
{
return "";
}
/**
* @inheritDoc
*/
public String merge(String siteId, Element root, String archivePath, String fromSiteId, Map attachmentNames, Map userIdTrans,
Set userListAllowImport)
{
return "";
}
/**********************************************************************************************************************************************************************************************************************************************************
* Preferences implementation
*********************************************************************************************************************************************************************************************************************************************************/
public class BasePreferences implements PreferencesEdit, SessionBindingListener
{
/** The user id. */
protected String m_id = null;
/** The properties. */
protected ResourcePropertiesEdit m_properties = null;
/** The sets of keyed ResourceProperties. */
protected Map m_props = null;
/**
* Construct.
*
* @param id
* The user id.
*/
public BasePreferences(String id)
{
m_id = id;
// setup for properties
ResourcePropertiesEdit props = new BaseResourcePropertiesEdit();
m_properties = props;
m_props = new Hashtable();
// if the id is not null (a new user, rather than a reconstruction)
// and not the anon (id == "") user,
// add the automatic (live) properties
// %%% if ((m_id != null) && (m_id.length() > 0)) addLiveProperties(props);
}
/**
* Construct from another Preferences object.
*
* @param user
* The user object to use for values.
*/
public BasePreferences(Preferences prefs)
{
setAll(prefs);
}
/**
* Construct from information in XML.
*
* @param el
* The XML DOM Element definining the user.
*/
public BasePreferences(Element el)
{
// setup for properties
m_properties = new BaseResourcePropertiesEdit();
m_props = new Hashtable();
m_id = el.getAttribute("id");
// the children (properties)
NodeList children = el.getChildNodes();
final int length = children.getLength();
for (int i = 0; i < length; i++)
{
Node child = children.item(i);
if (child.getNodeType() != Node.ELEMENT_NODE) continue;
Element element = (Element) child;
// look for properties
if (element.getTagName().equals("properties"))
{
// re-create properties
m_properties = new BaseResourcePropertiesEdit(element);
}
// look for a set of preferences
else if (element.getTagName().equals("prefs"))
{
String key = element.getAttribute("key");
// convert old pre Sakai 2.2 keys to new values (copied here to avoid build dependencies - WATCH OUT! -ggolden)
if (key.startsWith(NotificationService.PREFS_TYPE))
{
if (key.endsWith("AnnouncementService"))
{
// matches AnnouncementService.APPLICATION_ID
key = NotificationService.PREFS_TYPE + "sakai:announcement";
}
else if (key.endsWith("ContentHostingService"))
{
// matches ContentHostingService.APPLICATION_ID
key = NotificationService.PREFS_TYPE + "sakai:content";
}
else if (key.endsWith("MailArchiveService"))
{
// matches MailArchiveService.APPLICATION_ID
key = NotificationService.PREFS_TYPE + "sakai:mailarchive";
}
else if (key.endsWith("SyllabusService"))
{
// matches SyllabusService.APPLICATION_ID
key = NotificationService.PREFS_TYPE + "sakai:syllabus";
}
}
else if (key.endsWith("TimeService"))
{
// matches TimeService.APPLICATION_ID
key = "sakai:time";
}
else if (key.endsWith("sitenav"))
{
// matches Charon portal's value
key = "sakai:portal:sitenav";
}
else if (key.endsWith("ResourceLoader"))
{
// matches ResourceLoader.APPLICATION_ID
key = LOCALE_PREFERENCE_KEY;
}
BaseResourcePropertiesEdit props = null;
// the children (properties)
NodeList kids = element.getChildNodes();
final int len = kids.getLength();
for (int i2 = 0; i2 < len; i2++)
{
Node kid = kids.item(i2);
if (kid.getNodeType() != Node.ELEMENT_NODE) continue;
Element k = (Element) kid;
// look for properties
if (k.getTagName().equals("properties"))
{
props = new BaseResourcePropertiesEdit(k);
}
}
if (props != null)
{
m_props.put(key, props);
}
}
}
}
/**
* Take all values from this object.
*
* @param user
* The user object to take values from.
*/
protected void setAll(Preferences prefs)
{
m_id = prefs.getId();
m_properties = new BaseResourcePropertiesEdit();
m_properties.addAll(prefs.getProperties());
// %%% is this deep enough? -ggolden
m_props = new Hashtable();
m_props.putAll(((BasePreferences) prefs).m_props);
}
/**
* @inheritDoc
*/
public Element toXml(Document doc, Stack stack)
{
Element prefs = doc.createElement("preferences");
if (stack.isEmpty())
{
doc.appendChild(prefs);
}
else
{
((Element) stack.peek()).appendChild(prefs);
}
stack.push(prefs);
prefs.setAttribute("id", getId());
// properties
m_properties.toXml(doc, stack);
// for each keyed property
for (Iterator it = m_props.entrySet().iterator(); it.hasNext();)
{
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
ResourceProperties properties = (ResourceProperties) entry.getValue();
// if the props are empty, skip it
if (properties.getPropertyNames().next() == null) continue;
Element props = doc.createElement("prefs");
prefs.appendChild(props);
props.setAttribute("key", key);
stack.push(props);
properties.toXml(doc, stack);
stack.pop();
}
stack.pop();
return prefs;
}
/**
* @inheritDoc
*/
public String getId()
{
if (m_id == null) return "";
return m_id;
}
/**
* @inheritDoc
*/
public String getUrl()
{
return getAccessPoint(false) + m_id;
}
/**
* @inheritDoc
*/
public String getReference()
{
return preferencesReference(m_id);
}
/**
* @inheritDoc
*/
public String getReference(String rootProperty)
{
return getReference();
}
/**
* @inheritDoc
*/
public String getUrl(String rootProperty)
{
return getUrl();
}
/**
* @inheritDoc
*/
public ResourceProperties getProperties()
{
return m_properties;
}
/**
* @inheritDoc
*/
public ResourceProperties getProperties(String key)
{
ResourceProperties rv = (ResourceProperties) m_props.get(key);
if (rv == null)
{
// new, throwaway empty one
rv = new BaseResourceProperties();
}
return rv;
}
/**
* @inheritDoc
*/
public Collection getKeys()
{
return m_props.keySet();
}
/**
* @inheritDoc
*/
public boolean equals(Object obj)
{
if (!(obj instanceof Preferences)) return false;
return ((Preferences) obj).getId().equals(getId());
}
/**
* @inheritDoc
*/
public int hashCode()
{
return getId().hashCode();
}
/**
* @inheritDoc
*/
public int compareTo(Object obj)
{
if (!(obj instanceof Preferences)) throw new ClassCastException();
// if the object are the same, say so
if (obj == this) return 0;
// sort based on (unique) id
int compare = getId().compareTo(((Preferences) obj).getId());
return compare;
}
/******************************************************************************************************************************************************************************************************************************************************
* Edit implementation
*****************************************************************************************************************************************************************************************************************************************************/
/** The event code for this edit. */
protected String m_event = null;
/** Active flag. */
protected boolean m_active = false;
/**
* @inheritDoc
*/
public ResourcePropertiesEdit getPropertiesEdit(String key)
{
synchronized (m_props)
{
ResourcePropertiesEdit rv = (ResourcePropertiesEdit) m_props.get(key);
if (rv == null)
{
// new one saved in the map
rv = new BaseResourcePropertiesEdit();
m_props.put(key, rv);
}
return rv;
}
}
/**
* Clean up.
*/
protected void finalize()
{
// catch the case where an edit was made but never resolved
if (m_active)
{
cancel(this);
}
}
/**
* Take all values from this object.
*
* @param user
* The user object to take values from.
*/
protected void set(Preferences prefs)
{
setAll(prefs);
}
/**
* Access the event code for this edit.
*
* @return The event code for this edit.
*/
protected String getEvent()
{
return m_event;
}
/**
* Set the event code for this edit.
*
* @param event
* The event code for this edit.
*/
protected void setEvent(String event)
{
m_event = event;
}
/**
* @inheritDoc
*/
public ResourcePropertiesEdit getPropertiesEdit()
{
return m_properties;
}
/**
* Enable editing.
*/
protected void activate()
{
m_active = true;
}
/**
* @inheritDoc
*/
public boolean isActiveEdit()
{
return m_active;
}
/**
* Close the edit object - it cannot be used after this.
*/
protected void closeEdit()
{
m_active = false;
}
/******************************************************************************************************************************************************************************************************************************************************
* SessionBindingListener implementation
*****************************************************************************************************************************************************************************************************************************************************/
/**
* @inheritDoc
*/
public void valueBound(SessionBindingEvent event)
{
}
/**
* @inheritDoc
*/
public void valueUnbound(SessionBindingEvent event)
{
if (M_log.isDebugEnabled()) M_log.debug("valueUnbound()");
// catch the case where an edit was made but never resolved
if (m_active)
{
cancel(this);
}
}
}
/**********************************************************************************************************************************************************************************************************************************************************
* Storage
*********************************************************************************************************************************************************************************************************************************************************/
protected interface Storage
{
/**
* Open.
*/
public void open();
/**
* Close.
*/
public void close();
/**
* Check if a preferences by this id exists.
*
* @param id
* The user id.
* @return true if a preferences for this id exists, false if not.
*/
public boolean check(String id);
/**
* Get the preferences with this id, or null if not found.
*
* @param id
* The preferences id.
* @return The preferences with this id, or null if not found.
*/
public Preferences get(String id);
/**
* Add a new preferences with this id.
*
* @param id
* The preferences id.
* @return The locked Preferences object with this id, or null if the id is in use.
*/
public PreferencesEdit put(String id);
/**
* Get a lock on the preferences with this id, or null if a lock cannot be gotten.
*
* @param id
* The preferences id.
* @return The locked Preferences with this id, or null if this records cannot be locked.
*/
public PreferencesEdit edit(String id);
/**
* Commit the changes and release the lock.
*
* @param user
* The edit to commit.
*/
public void commit(PreferencesEdit edit);
/**
* Cancel the changes and release the lock.
*
* @param user
* The edit to commit.
*/
public void cancel(PreferencesEdit edit);
/**
* Remove this edit and release the lock.
*
* @param user
* The edit to remove.
*/
public void remove(PreferencesEdit edit);
}
/**********************************************************************************************************************************************************************************************************************************************************
* StorageUser implementation (no container)
*********************************************************************************************************************************************************************************************************************************************************/
/**
* @inheritDoc
*/
public Entity newResource(Entity container, String id, Object[] others)
{
return new BasePreferences(id);
}
/**
* @inheritDoc
*/
public Entity newResource(Entity container, Element element)
{
return new BasePreferences(element);
}
/**
* @inheritDoc
*/
public Entity newResource(Entity container, Entity other)
{
return new BasePreferences((Preferences) other);
}
/**
* @inheritDoc
*/
public Edit newResourceEdit(Entity container, String id, Object[] others)
{
BasePreferences e = new BasePreferences(id);
e.activate();
return e;
}
/**
* @inheritDoc
*/
public Edit newResourceEdit(Entity container, Element element)
{
BasePreferences e = new BasePreferences(element);
e.activate();
return e;
}
/**
* @inheritDoc
*/
public Edit newResourceEdit(Entity container, Entity other)
{
BasePreferences e = new BasePreferences((Preferences) other);
e.activate();
return e;
}
/**
* @inheritDoc
*/
public Object[] storageFields(Entity r)
{
return null;
}
}