2003-06-19 22:55:45 +00:00

1200 lines
46 KiB
Java

/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.community;
import java.security.Principal;
import java.security.acl.AclNotFoundException;
import java.util.*;
import org.apache.commons.collections.*;
import org.apache.log4j.Logger;
import com.silverwrist.dynamo.db.NamespaceCache;
import com.silverwrist.dynamo.db.UserManagement;
import com.silverwrist.dynamo.iface.*;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.security.SecurityReferenceMonitor;
import com.silverwrist.dynamo.util.*;
import com.silverwrist.venice.CommunityVisibility;
import com.silverwrist.venice.VeniceNamespaces;
import com.silverwrist.venice.event.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.iface.*;
/**
* Concrete implementation of the {@link com.silverwrist.venice.iface.VeniceCommunity VeniceCommunity} interface,
* which provides all the basic community functions.
*
* @author Eric J. Bowersox &lt;erbo@silcom.com&gt;
* @version X
*/
class CommunityImpl implements VeniceCommunity
{
/*--------------------------------------------------------------------------------
* Internal join cleanup task class.
*--------------------------------------------------------------------------------
*/
private class JoinCleanupTask
{
/*====================================================================
* Attributes
*====================================================================
*/
private int m_ugid;
private boolean m_is_group;
/*====================================================================
* Constructor
*====================================================================
*/
JoinCleanupTask(int ugid, boolean is_group)
{
m_ugid = ugid;
m_is_group = is_group;
} // end constructor
/*====================================================================
* External operations
*====================================================================
*/
void run() throws DatabaseException
{
m_ops.deleteSingleUseAuthData(m_id,m_ugid,m_is_group);
} // end run
} // end class JoinCleanupTask
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
private static Logger logger = Logger.getLogger(CommunityImpl.class);
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private CommunityManager m_base; // base object
private CommunityOps m_ops; // community operations object
private NamespaceCache m_nscache; // namespace cache object
private SecurityReferenceMonitor m_srm; // security reference monitor
private UserManagement m_users; // user management object
private AuthenticatorLookup m_alook; // authenticator lookup object
private PostDynamicUpdate m_post; // where we post dynamic update events
private CategoryService m_cats; // category service object
private int m_id; // community ID
private int m_member_gid; // member group ID
private int m_host_gid; // hosts group ID
private int m_host_uid; // primary host UID
private int m_aclid; // ID of the community ACL
private int m_catid; // category ID for the community
private CommunityVisibility m_visibility; // community visibility
private String m_name; // community name
private String m_alias; // community alias
private java.util.Date m_created; // date created
private java.util.Date m_lastaccessed; // date last accessed
private java.util.Date m_lastupdate; // date last updated
private ReferenceMap m_properties; // properties cache
private List m_service_list = null; // cached service list
/*--------------------------------------------------------------------------------
* Constructors
*--------------------------------------------------------------------------------
*/
/**
* Constructs a new concrete community implementation.
*
* @param ops The {@link com.silverwrist.venice.community.CommunityOps CommunityOps} object providing access to the
* database.
* @param nscache The {@link com.silverwrist.dynamo.db.NamespaceCache NamespaceCache} object providing conversion
* between namespace URIs and integer namespace identifiers.
* @param srm The {@link com.silverwrist.dynamo.security.SecurityReferenceMonitor SecurityReferenceMonitor} object
* through which security is tested.
* @param users The {@link com.silverwrist.dynamo.db.UserManagement UserManagetment} object used to retrieve user
* and group objects.
* @param alook The {@link com.silverwrist.dynamo.iface.AuthenticatorLookup AuthenticatorLookup} interface used
* to find registered {@link com.silverwrist.dynamo.iface.Authenticator Authenticator} objects.
* @param post The {@link com.silverwrist.dynamo.iface.PostDynamicUpdate PostDynamicUpdate} interface used
* to post dynamic update events.
* @param cats The {@link com.silverwrist.venice.community.CategoryService CategoryService} interface used to
* retrieve category objects.
* @param data A {@link java.util.Map Map} object containing the initial data for the community, with keys
* corresponding to static fields of the
* {@link com.silverwrist.venice.community.CommunityManagerOps CommunityManagerOps} object.
*/
CommunityImpl(CommunityManager base, CommunityOps ops, NamespaceCache nscache, SecurityReferenceMonitor srm,
UserManagement users, AuthenticatorLookup alook, PostDynamicUpdate post, CategoryService cats,
Map data)
{
m_base = base;
m_ops = ops;
m_nscache = nscache;
m_srm = srm;
m_users = users;
m_alook = alook;
m_post = post;
m_cats = cats;
m_id = ((Integer)(data.get(CommunityManagerOps.KEY_CID))).intValue();
m_member_gid = ((Integer)(data.get(CommunityManagerOps.KEY_MEMBER_GID))).intValue();
m_host_gid = ((Integer)(data.get(CommunityManagerOps.KEY_HOST_GID))).intValue();
m_host_uid = ((Integer)(data.get(CommunityManagerOps.KEY_HOST_UID))).intValue();
m_aclid = ((Integer)(data.get(CommunityManagerOps.KEY_ACLID))).intValue();
m_catid = ((Integer)(data.get(CommunityManagerOps.KEY_CATID))).intValue();
m_visibility = (CommunityVisibility)(data.get(CommunityManagerOps.KEY_VISIBILITY));
m_name = (String)(data.get(CommunityManagerOps.KEY_NAME));
m_alias = (String)(data.get(CommunityManagerOps.KEY_ALIAS));
m_created = (java.util.Date)(data.get(CommunityManagerOps.KEY_CREATE));
m_lastaccessed = (java.util.Date)(data.get(CommunityManagerOps.KEY_ACCESS));
m_lastupdate = (java.util.Date)(data.get(CommunityManagerOps.KEY_UPDATE));
m_properties = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT);
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
/**
* Performs a permission check on the community's ACL, as well as the global ACL. Returns without
* incident if the permission check succeeds; throws a
* {@link com.silverwrist.dynamo.except.DynamoSecurityException DynamoSecurityException} if it fails.
*
* @param caller The user makingt he call, to test the permission.
* @param perm_namespace The namespace of the permission to be tested.
* @param perm_name The name of the permission to be tested.
* @param fail_message The message to be thrown as a <CODE>DynamoSecurityException</CODE> if the test fails.
* Interpreted as a message identifier within the <CODE>CommunityMessages</CODE> resource
* bundle, with one parameter: the name of the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was a database failure testing the permission.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the permission test failed.
*/
private final void testPermission(DynamoUser caller, String perm_namespace, String perm_name,
String fail_message) throws DatabaseException, DynamoSecurityException
{
try
{ // perform security tests...
if (caller.equals(m_srm.getAdminUser()))
return; // Administrator can do anything
if (m_srm.getAcl(m_aclid).testPermission(caller,perm_namespace,perm_name))
return; // we have the right permission in the community ACL
if (m_srm.getGlobalAcl().testPermission(caller,perm_namespace,perm_name))
return; // or we can be authorized by the global ACL
} // end try
catch (AclNotFoundException e)
{ // just fall through and throw the exception
} // end catch
// throw the DynamoSecurityException
DynamoSecurityException d = new DynamoSecurityException(CommunityImpl.class,"CommunityMessages",fail_message);
d.setParameter(0,m_name);
throw d;
} // end testPermission
/*--------------------------------------------------------------------------------
* Overrides from class Object
*--------------------------------------------------------------------------------
*/
/**
* Indicates whether some other object is "equal to" this one.
*
* @param o The reference object with which to compare.
* @return <CODE>true</CODE> if this object is the same as the <CODE>o</CODE> argument; <CODE>false</CODE> otherwise.
*/
public boolean equals(Object o)
{
if (o==null)
return false;
if (o instanceof VeniceCommunity)
return (((VeniceCommunity)o).getCID()==m_id);
return false;
} // end equals
/**
* Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those
* provided by {@link java.util.Hashtable Hashtable}.
*
* @return A hash code value for this object.
*/
public int hashCode()
{
return m_id;
} // end hashCode
/**
* Returns a string representation of the object. In general, the <CODE>toString</CODE> method returns a string
* that "textually represents" this object.
*
* @return A string representation of the object.
*/
public String toString()
{
return "Community \"" + m_name + "\"";
} // end toString
/*--------------------------------------------------------------------------------
* Implementations from interface NamedObject
*--------------------------------------------------------------------------------
*/
/**
* Returns the name of this community.
*
* @return The name of this community.
*/
public String getName()
{
return m_name;
} // end getName
/*--------------------------------------------------------------------------------
* Implementations from interface ObjectProvider
*--------------------------------------------------------------------------------
*/
/**
* Retrieves an object from the community's properties.
*
* @param namespace The namespace to interpret the name relative to.
* @param name The name of the object to be retrieved.
* @return The object reference specified.
*/
public Object getObject(String namespace, String name)
{
if (logger.isDebugEnabled())
logger.debug("CommunityImpl.getObject: namespace = " + namespace + ", name = " + name);
try
{ // convert the namespace name to an ID here
PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name);
Object rc = null;
synchronized (this)
{ // start by looking in the properties map
rc = m_properties.get(key);
if (rc==null)
{ // no use - need to try the database
rc = m_ops.getProperty(m_id,key);
if (rc!=null)
{ // found in the database
m_properties.put(key,rc);
logger.debug("value found in database");
} // end if
} // end if
else
logger.debug("value found in cache");
} // end synchronized block
if (rc==null)
{ // the object was not found
logger.debug("value not found");
throw new NoSuchObjectException(this.toString(),namespace,name);
} // end if
return rc;
} // end try
catch (DatabaseException e)
{ // translate into our NoSuchObjectException but retain the DatabaseException
logger.debug("Database exception while doing find",e);
throw new NoSuchObjectException(this.toString(),namespace,name,e);
} // end catch
} // end getObject
/*--------------------------------------------------------------------------------
* Implementations from interface SecureObjectStore
*--------------------------------------------------------------------------------
*/
/**
* Sets an object into the community's properties.
*
* @param caller The user performing the operation.
* @param namespace The namespace to interpret the name relative to.
* @param name The name of the object to be set.
* @param value The object to set into the community's properties.
* @return The previous object that was set into the community's properties under this namespace and name, or
* <CODE>null</CODE> if there was no such object.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error setting the object value.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* set this object value into this community's properties.
*/
public Object setObject(DynamoUser caller, String namespace, String name, Object value)
throws DatabaseException, DynamoSecurityException
{
testPermission(caller,namespace,"set.property","auth.setProperty");
DateObjectPair rc = null;
// convert the namespace name to an ID here
PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name);
synchronized (this)
{ // start by setting the database value
rc = m_ops.setProperty(m_id,key,value);
// and cache it, too
m_properties.put(key,value);
// and save off the update date/time
m_lastaccessed = m_lastupdate = rc.getDate();
} // end synchronized block
m_post.postUpdate(new CommunityPropertyUpdateEvent(this,namespace,name));
return rc.getObject();
} // end setObject
/**
* Removes an object from this community's properties.
*
* @param caller The user performing the operation.
* @param namespace The namespace to interpret the name relative to.
* @param name The name of the object to be removed.
* @return The previous object that was set into the community's properties under this namespace and name, or
* <CODE>null</CODE> if there was no such object.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error removing the object value.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* remove this object value from this community's properties.
*/
public Object removeObject(DynamoUser caller, String namespace, String name)
throws DatabaseException, DynamoSecurityException
{
testPermission(caller,namespace,"remove.property","sec.removeGlobalProperty");
DateObjectPair rc = null;
// convert the namespace name to an ID here
PropertyKey key = new PropertyKey(m_nscache.namespaceNameToId(namespace),name);
synchronized (this)
{ // start by killing the database value
rc = m_ops.removeProperty(m_id,key);
// and remove the cached value, too
m_properties.remove(key);
if (rc!=null) // save off update date.time
m_lastaccessed = m_lastupdate = rc.getDate();
} // end synchronized block
m_post.postUpdate(new CommunityPropertyUpdateEvent(this,namespace,name));
return (rc==null) ? null : rc.getObject();
} // end removeObject
/**
* Returns a collection of all object namespaces that have been set into this community's properties.
*
* @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects specifying
* all the object namespaces.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the namespace list.
*/
public Collection getNamespaces() throws DatabaseException
{
// call through to the database to get the list of namespace IDs
int[] ids = m_ops.getPropertyNamespaceIDs(m_id);
ArrayList rc = new ArrayList(ids.length);
for (int i=0; i<ids.length; i++)
rc.add(m_nscache.namespaceIdToName(ids[i]));
return Collections.unmodifiableList(rc);
} // end getNamespaces
/**
* Returns a collection of all object names that have been set into this community's properties under
* a given namespace.
*
* @param namespace The namespace to look for names under.
* @return A {@link java.util.Collection Collection} containing {@link java.lang.String String} objects
* specifying all the object names for this namespace.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the object name list.
*/
public Collection getNamesForNamespace(String namespace) throws DatabaseException
{
// call through to the database to get the data for this namespace
int nsid = m_nscache.namespaceNameToId(namespace);
Map data = m_ops.getAllProperties(m_id,nsid);
// we both create the return value and cache the data values
ArrayList rc = new ArrayList(data.size());
synchronized (this)
{ // do the transfer...
Iterator it = data.entrySet().iterator();
while (it.hasNext())
{ // copy one entry at a time
Map.Entry ntry = (Map.Entry)(it.next());
rc.add(ntry.getKey().toString());
m_properties.put(new PropertyKey(nsid,ntry.getKey().toString()),ntry.getValue());
} // end while
} // end synchronized block
return Collections.unmodifiableList(rc);
} // end getNamesForNamespace
/*--------------------------------------------------------------------------------
* Implementations from interface VeniceCommunity
*--------------------------------------------------------------------------------
*/
/**
* Returns the community ID of this community. The community ID is set when the community is created and may
* not be altered.
*
* @return The community ID of this community.
*/
public int getCID()
{
return m_id;
} // end getCID
/**
* Returns the GID of the <EM>member group</EM> of this community. The member group specifies all
* members of the community.
*
* @return The GID of the member group for this community.
*/
public int getMemberGID()
{
return m_member_gid;
} // end getMemberGID
/**
* Returns a reference to the <EM>member group</EM> of this community. The member group specifies all
* members of the community.
*
* @return A reference to the member group of this community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the member group.
*/
public DynamoGroup getMemberGroup() throws DatabaseException
{
return m_users.getGroup(m_member_gid);
} // end getMemberGroup
/**
* Returns the GID of the <EM>host group</EM> of this community. The host group specifies all
* hosts of the community, who generally have power to change most attributes of a community.
*
* @return The GID of the host group for this community.
*/
public int getHostGID()
{
return m_host_gid;
} // end getHostGID
/**
* Returns a reference to the <EM>host group</EM> of this community. The host group specifies all
* hosts of the community, who generally have power to change most attributes of a community.
*
* @return A reference to the host group of this community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the host group.
*/
public DynamoGroup getHostGroup() throws DatabaseException
{
return m_users.getGroup(m_host_gid);
} // end getHostGroup
/**
* Returns the UID of the <EM>host user</EM> of this community. The host user is the primary host of the
* community, who is the only one who has power to add or remove additional hosts.
*
* @return The UID of the host user of the community.
*/
public int getHostUID()
{
return m_host_uid;
} // end getHostUID
/**
* Returns a reference to the <EM>host user</EM> of this community. The host user is the primary host of the
* community, who is the only one who has power to add or remove additional hosts.
*
* @return A reference to the host user of the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the host user.
*/
public DynamoUser getHostUser() throws DatabaseException
{
return m_users.getUser(m_host_uid);
} // end getHostUser
/**
* Returns a reference to the community's access control list.
*
* @return A reference to the community's access control list.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the ACL.
* @exception java.security.acl.AclNotFoundException If the community ACL could not be found.
*/
public DynamoAcl getAcl() throws DatabaseException, AclNotFoundException
{
return m_srm.getAcl(m_aclid);
} // end getAcl
/**
* Returns the category ID of the community, specifying its location in the community directory.
*
* @return The category ID of the community.
*/
public int getCategoryID()
{
return m_catid;
} // end getCategoryID
/**
* Returns the category of the community, specifying its location in the community directory.
*
* @return The category of the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the category object.
*/
public VeniceCategory getCategory() throws DatabaseException
{
return m_cats.getCategory(m_catid);
} // end getCategory
/**
* Changes the category ID of the community, specifying its location in the community directory.
*
* @param caller The user attempting to change the category ID.
* @param catid The new category ID for the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the category.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* change the category ID.
*/
public synchronized void setCategoryID(DynamoUser caller, int catid)
throws DatabaseException, DynamoSecurityException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PROFILE_NAMESPACE,"set.category","auth.setCategory");
java.util.Date update = m_ops.setCategoryID(m_id,catid);
m_catid = catid;
m_lastaccessed = m_lastupdate = update;
m_post.postUpdate(new CommunityBaseUpdateEvent(this,"category"));
} // end setCategoryID
/**
* Changes the category of the community, specifying its location in the community directory.
*
* @param caller The user attempting to change the category.
* @param catid The new category for the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the category.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* change the category.
*/
public void setCategory(DynamoUser caller, VeniceCategory cat) throws DatabaseException, DynamoSecurityException
{
this.setCategoryID(caller,cat.getCategoryID());
} // end setCategory
/**
* Returns the current {@link com.silverwrist.venice.CommunityVisibility visibility} of the community.
*
* @return The current visibility of the community.
*/
public CommunityVisibility getVisibility()
{
return m_visibility;
} // end getVisibility
/**
* Sets the current {@link com.silverwrist.venice.CommunityVisibility visibility} of the community.
*
* @param caller The user attempting to change the community's visibility.
* @param vis The new visibility for the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the visibility.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* change the community visibility.
*/
public synchronized void setVisibility(DynamoUser caller, CommunityVisibility vis)
throws DatabaseException, DynamoSecurityException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PROFILE_NAMESPACE,"set.visibility","auth.setVisibility");
java.util.Date update = m_ops.setVisibility(m_id,vis);
m_visibility = vis;
m_lastaccessed = m_lastupdate = update;
m_post.postUpdate(new CommunityBaseUpdateEvent(this,"visibility"));
} // end setVisibility
/**
* Sets the name of the community.
*
* @param caller The user attempting to change the community's name.
* @param name The new name for the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the name.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* change the community name.
*/
public synchronized void setName(DynamoUser caller, String name) throws DatabaseException, DynamoSecurityException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PROFILE_NAMESPACE,"set.name","auth.setName");
java.util.Date update = m_ops.setName(m_id,name);
m_name = name;
m_lastaccessed = m_lastupdate = update;
m_post.postUpdate(new CommunityBaseUpdateEvent(this,"name"));
} // end setName
/**
* Returns the <EM>alias</EM> of the community. The alias is a unique identifier for the community that must
* conform to the rules for Dynamo identifiers.
*
* @return The alias for the community.
*/
public String getAlias()
{
return m_alias;
} // end getAlias
/**
* Sets the <EM>alias</EM> of the community. The alias is a unique identifier for the community that must
* conform to the rules for Dynamo identifiers.
*
* @param caller The user attempting to change the community's alias.
* @param alias The new alias for the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the alias.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* change the community alias.
*/
public synchronized void setAlias(DynamoUser caller, String alias) throws DatabaseException, DynamoSecurityException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PROFILE_NAMESPACE,"set.alias","auth.setAlias");
java.util.Date update = m_ops.setAlias(m_id,alias);
m_alias = alias;
m_lastaccessed = m_lastupdate = update;
m_post.postUpdate(new CommunityBaseUpdateEvent(this,"alias"));
} // end setAlias
/**
* Returns the date and time at which this community was created.
*
* @return The creation date and time for this community.
*/
public java.util.Date getCreationDate()
{
return m_created;
} // end getCreationDate
/**
* Returns the date and time at which this community was last accessed.
*
* @return The last access date and time for this community.
*/
public java.util.Date getLastAccessDate()
{
return m_lastaccessed;
} // end getLastAccessDate
/**
* Sets the date and time at which this community was last accessed.
*
* @param caller The user attempting to change the community's access date/time.
* @param date The new access date/time for the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the access date/time.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* change the community access date/time.
*/
public synchronized void setLastAccessDate(DynamoUser caller, java.util.Date date) throws DatabaseException
{
m_ops.setLastAccessDate(m_id,date);
m_lastaccessed = date;
} // end setLastAccessedDate
/**
* Returns the date and time at which this community was last updated.
*
* @return The last update date and time for this community.
*/
public java.util.Date getLastUpdateDate()
{
return m_lastupdate;
} // end getLastUpdateDate
/**
* Sets the date and time at which this community was last updated.
*
* @param caller The user attempting to change the community's update date/time.
* @param date The new update date/time for the community.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error resetting the update date/time.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to
* change the community update date/time.
*/
public synchronized void setLastUpdateDate(DynamoUser caller, java.util.Date date) throws DatabaseException
{
m_ops.setLastUpdateDate(m_id,date);
m_lastaccessed = m_lastupdate = date;
} // end setLastUpdateDate
/**
* Grants permission to join the community to a specific user or group. This permission may be contingent upon
* the user authenticating with the community in some fashion, and it may also be single-use, meaning the permission
* is automatically revoked whenever a user uses it to join the community.
*
* @param caller The person attempting to grant access to the community.
* @param subject The {@link com.silverwrist.dynamo.iface.DynamoUser user} or
* {@link com.silverwrist.dynamo.iface.DynamoGroup group} that we want to grant access to.
* @param auth_namespace The namespace of the authenticator to use to grant access. If both this parameter and
* <EM>auth_name</EM> are <CODE>null</CODE>, no authentication is required.
* @param auth_name The name of the authenticator to use to grant access. If both this parameter and
* <EM>auth_namespace</EM> are <CODE>null</CODE>, no authentication is required.
* @param source_info The source information for the authenticator. If <EM>auth_namespace</EM> and
* <EM>auth_name</EM> are <CODE>null</CODE>, this parameter is ignored.
* @param auth_info The authentication information (such as a password) for the authenticator. If
* <EM>auth_namespace</EM> and <EM>auth_name</EM> are <CODE>null</CODE>, this parameter is ignored.
* @param single_use If this parameter is <CODE>true</CODE>, the permission will automatically be revoked after the
* first time it is successfully used by a user to join the community.
* @exception com.silverwrist.dynamo.except.AuthenticationException If the named authenticator is not a valid one.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error registering the access grant.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to grant
* access to this community.
*/
public void grantAccess(DynamoUser caller, Principal subject, String auth_namespace, String auth_name,
String source_info, String auth_info, boolean single_use)
throws AuthenticationException, DatabaseException, DynamoSecurityException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"grant.revoke.access","auth.grantAccess");
// Translate the subject into an ID and group flag.
int ugid = -1;
boolean is_group = false;
if (subject instanceof DynamoUser)
ugid = ((DynamoUser)subject).getUID();
else if (subject instanceof DynamoGroup)
{ // it's a group
ugid = ((DynamoGroup)subject).getGID();
is_group = true;
} // end else if
else
throw new IllegalArgumentException("invalid subject");
// Make sure the authenticator is valid.
int auth_nsid = 0;
Authenticator auth = null;
if ((auth_namespace!=null) || (auth_name!=null))
{ // look up the authenticator to make sure it's registered
auth = m_alook.findAuthenticator(auth_namespace,auth_name);
if (auth==null)
throw new IllegalArgumentException("invalid authenticator");
auth_nsid = m_nscache.namespaceNameToId(auth_namespace);
} // end if
else // force-map source info and auth info to null
source_info = auth_info = null;
// Preprocess the authentication information through the authenticator.
String real_auth_info = auth_info;
if ((auth_info!=null) && (auth!=null))
real_auth_info = auth.processInputData(auth_info);
synchronized (this)
{ // update the access table and touch the community
java.util.Date update = m_ops.grantAccess(m_id,ugid,is_group,single_use,auth_nsid,auth_name,source_info,
real_auth_info);
m_lastaccessed = m_lastupdate = update;
} // end synchronized block
} // end grantAccess
/**
* Revokes permission to join the community from a specific user or group. This does not affect any user who
* has already joined the community.
*
* @param caller The person attempting to revoke access to the community.
* @param subject The {@link com.silverwrist.dynamo.iface.DynamoUser user} or
* {@link com.silverwrist.dynamo.iface.DynamoGroup group} that we want to revoke access from.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error registering the access revoke.
* @exception com.silverwrist.dynamo.except.DynamoSecurityException If the specified user is not permitted to revoke
* access to this community.
*/
public void revokeAccess(DynamoUser caller, Principal subject) throws DatabaseException, DynamoSecurityException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"grant.revoke.access","auth.revokeAccess");
// Translate the subject into an ID and group flag.
int ugid = -1;
boolean is_group = false;
if (subject instanceof DynamoUser)
ugid = ((DynamoUser)subject).getUID();
else if (subject instanceof DynamoGroup)
{ // it's a group
ugid = ((DynamoGroup)subject).getGID();
is_group = true;
} // end else if
else
throw new IllegalArgumentException("invalid subject");
synchronized (this)
{ // update the access table and touch the community
java.util.Date update = m_ops.revokeAccess(m_id,ugid,is_group);
if (update!=null)
m_lastaccessed = m_lastupdate = update;
} // end synchronized block
} // end revokeAccess
/**
* Tests to see what requirements must be fulfilled by a user to join this community. Returns values as follows:
* <UL>
* <LI>If the user is not permitted to join the community under any circumstances, this method returns
* <CODE>null</CODE>.</LI>
* <LI>If the user is already a member of the community, this method returns <CODE>Boolean.FALSE</CODE>.</LI>
* <LI>If the user may join the community without any authentication, this method returns
* <CODE>Boolean.TRUE</CODE>.</LI>
* <LI>Otherwise, the method returns a {@link java.util.Set Set} of
* {@link com.silverwrist.dynamo.util.QualifiedNameKey QualifiedNameKey} objects, each of which specifies the
* namespace and name of an authenticator which can be used to authenticate the user in order to join this
* community.</LI>
* </UL>
*
* @param joiner The user to test atainst the current community.
* @return See above.
* @exception com.silverwrist.dynamo.except.DatabaseException If there was an error getting the authenticator
* information for this user.
*/
public Object getJoinRequirement(DynamoUser joiner) throws DatabaseException
{
if (logger.isDebugEnabled())
logger.debug("CommunityImpl.getJoinRequirement: " + joiner.getName() + " wants to join " + m_name);
// If the user is already a member, return the value that dictates that we are already a member.
if (m_users.getGroup(m_member_gid).isMember(joiner))
return Boolean.FALSE;
// The Admin user is Superman and can do anything.
if (joiner.equals(m_srm.getAdminUser()))
return Boolean.TRUE;
// Anyone with the global "join any" permission can join without authorization.
if (m_srm.getGlobalAcl().testPermission(joiner,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"join.any"))
return Boolean.TRUE;
// Get the database's verdict. The return value from the low-level operation will either be a null,
// a Boolean object, or a Set of PropertyKey objects.
Object rc = m_ops.getJoinRequirement(m_id,joiner.getUID());
if (rc==null)
return null;
else if (rc instanceof Boolean)
return rc;
assert (rc instanceof Set);
// The output must be translated to a Set of QualifiedNameKeys by resolving the namespace IDs.
Set rcin = (Set)rc;
HashSet rcout = new HashSet();
Iterator it = rcin.iterator();
while (it.hasNext())
{ // convert each PropertyKey to a QualifiedNameKey
PropertyKey k = (PropertyKey)(it.next());
rcout.add(new QualifiedNameKey(m_nscache.namespaceIdToName(k.getNamespaceID()),k.getName()));
} // end while
return Collections.unmodifiableSet(rcout);
} // end getJoinRequirement
public synchronized boolean join(DynamoUser joiner, String auth_namespace, String auth_name, String source_info,
String auth_info) throws DatabaseException, DynamoSecurityException
{
if (logger.isDebugEnabled())
logger.debug("CommunityImpl.join: " + joiner.getName() + " joining " + m_name);
// If the user is already a member, return the value that dictates that we are already a member.
DynamoGroup mbr_group = m_users.getGroup(m_member_gid);
if (mbr_group.isMember(joiner))
return false;
boolean ok_to_join = false;
JoinCleanupTask task = null;
if (joiner.equals(m_srm.getAdminUser()))
ok_to_join = true;
else if (m_srm.getGlobalAcl().testPermission(joiner,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"join.any"))
ok_to_join = true;
else
{ // Look to see if we can find the right entry to let the user in with.
boolean need_auth = false;
Object which = m_ops.getJoinEntryNull(m_id,joiner.getUID());
if ((which==null) && (auth_namespace!=null) && (auth_name!=null))
{ // OK, we may need to authenticate
need_auth = true;
which = m_ops.getJoinEntry(m_id,joiner.getUID(),m_nscache.namespaceNameToId(auth_namespace),auth_name,
source_info);
} // end which
if (which!=null)
{ // We can get in...see if we need to check authentication.
if (need_auth)
{ // Pull in the authentication data.
String stored_auth_data;
if (which instanceof Boolean)
stored_auth_data = m_ops.getAuthData(m_id,joiner.getUID(),false);
else
stored_auth_data = m_ops.getAuthData(m_id,((Integer)which).intValue(),true);
// Get the authenticator.
Authenticator auth = m_alook.findAuthenticator(auth_namespace,auth_name);
if (auth==null)
throw new IllegalArgumentException("invalid authenticator");
// Checkitout checkitout checkitout checkitout checkitout checkitout checkitout....
try
{ // attempt to authenticate
ok_to_join = auth.authenticate(stored_auth_data,auth_info);
} // end try
catch (AuthenticationException e)
{ // something went wrong...
DynamoSecurityException de = new DynamoSecurityException(CommunityImpl.class,"CommunityMessages",
"join.authFail",e);
de.setParameter(0,m_name);
throw de;
} // end catch
if (!ok_to_join)
{ // authentication failed - throw an error
DynamoSecurityException de = new DynamoSecurityException(CommunityImpl.class,"CommunityMessages",
"join.authFail");
de.setParameter(0,m_name);
throw de;
} // end if
} // end if
else // we're automatically OK to join
ok_to_join = true;
// Create the cleanup task.
if (which instanceof Boolean)
task = new JoinCleanupTask(joiner.getUID(),false);
else
task = new JoinCleanupTask(((Integer)which).intValue(),true);
} // end if
// else we can't join the group - fall through and eventually throw a DynamoSecurityException
} // end else
if (ok_to_join)
{ // we're OK to join this group!
mbr_group.addMember(m_users.getUser(m_host_uid),joiner);
if (task!=null)
task.run();
return true;
} // end if
// We cannot join - throw an exception.
DynamoSecurityException de = new DynamoSecurityException(CommunityImpl.class,"CommunityMessages",
"join.disallowed");
de.setParameter(0,m_name);
throw de;
} // end join
public boolean join(DynamoUser joiner) throws DatabaseException, DynamoSecurityException
{
return this.join(joiner,null,null,null,null);
} // end join
public void unjoin(DynamoUser unjoiner) throws DatabaseException, DynamoSecurityException
{
DynamoGroup mbr_group = m_users.getGroup(m_member_gid);
if (!(mbr_group.isMember(unjoiner)))
return; // if you're not a member, unjoining is a no-op
testPermission(unjoiner,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"unjoin","auth.unjoin");
mbr_group.removeMember(m_users.getUser(m_host_uid),unjoiner);
} // end unjoin
public boolean isAdministrator(DynamoUser user)
{
try
{ // must be either the host UID or a member of the admin group
if (user.getUID()==m_host_uid)
return true;
return m_users.getGroup(m_host_gid).isMember(user);
} // end try
catch (DatabaseException e)
{ // gotta catch it, even if we can't do anything with it
logger.warn("CommunityImpl.isAdministrator caught DatabaseException",e);
return false;
} // end catch
} // end isAdministrator
public List getServices() throws DatabaseException
{
if (m_service_list==null)
{ // need to fake up the service list
int[] svcids = m_ops.getServiceIDs(m_id);
if (svcids.length>0)
{ // convert this to a list of ServiceDescriptors
ArrayList rc = new ArrayList(svcids.length);
for (int i=0; i<svcids.length; i++)
rc.add(m_base.getServiceForID(svcids[i]));
Collections.sort(rc,new Comparator()
{
public int compare(Object o1, Object o2)
{
String s1 = ((CommunityServiceDescriptor)o1).getDescription();
String s2 = ((CommunityServiceDescriptor)o2).getDescription();
return s1.compareTo(s2);
} // end compare
public boolean equals(Object obj)
{
return false;
} // end equals
}); // end Comparator object
m_service_list = Collections.unmodifiableList(rc);
} // end if
else // just use the empty list as a return value
m_service_list = Collections.EMPTY_LIST;
} // end if
return m_service_list;
} // end getServices
public boolean isUsingService(String namespace, String name) throws DatabaseException
{
return m_ops.isUsingService(m_id,m_nscache.namespaceNameToId(namespace),name);
} // end isUsingService
public synchronized void addService(DynamoUser caller, Request req, String namespace, String name)
throws DatabaseException, DynamoSecurityException, CommunityServiceException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"manage.services","auth.addService");
int nsid = m_nscache.namespaceNameToId(namespace);
if (m_ops.isUsingService(m_id,nsid,name))
{ // we're already using this service - throw an exception
CommunityServiceException cse = new CommunityServiceException(CommunityImpl.class,"CommunityMessages",
"svc.already.using");
cse.setParameter(0,namespace);
cse.setParameter(1,name);
throw cse;
} // end if
CommunityServiceDescriptor descr = m_base.getServiceForName(namespace,name);
if (descr==null)
{ // this service is not defined - throw an exception
CommunityServiceException cse = new CommunityServiceException(CommunityImpl.class,"CommunityMessages",
"svc.notFound");
cse.setParameter(0,namespace);
cse.setParameter(1,name);
throw cse;
} // end if
descr.getController().addServiceToCommunity(req,this);
m_ops.addService(m_id,nsid,name);
m_service_list = null;
} // end addService
public void removeService(DynamoUser caller, Request req, String namespace, String name)
throws DatabaseException, DynamoSecurityException, CommunityServiceException
{
testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,"manage.services","auth.removeService");
int nsid = m_nscache.namespaceNameToId(namespace);
synchronized (this)
{ // see if we're using this service
if (!(m_ops.isUsingService(m_id,nsid,name)))
{ // we're not using this service - throw an exception
CommunityServiceException cse = new CommunityServiceException(CommunityImpl.class,"CommunityMessages",
"svc.not.using");
cse.setParameter(0,namespace);
cse.setParameter(1,name);
throw cse;
} // end if
CommunityServiceDescriptor descr = m_base.getServiceForName(namespace,name);
if (descr==null)
{ // this service is not defined - throw an exception
CommunityServiceException cse = new CommunityServiceException(CommunityImpl.class,"CommunityMessages",
"svc.notFound");
cse.setParameter(0,namespace);
cse.setParameter(1,name);
throw cse;
} // end if
descr.getController().removeServiceFromCommunity(req,this);
m_ops.removeService(m_id,nsid,name);
m_service_list = null;
} // end synchronized block
} // end removeService
} // end class CommunityImpl