venice-dynamo-rewrite/src/venice-base/com/silverwrist/venice/community/CommunityManager.java
2003-06-19 22:55:45 +00:00

687 lines
26 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.util.*;
import org.apache.commons.collections.*;
import org.apache.log4j.Logger;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.util.xml.*;
import com.silverwrist.dynamo.db.NamespaceCache;
import com.silverwrist.dynamo.db.UserManagement;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;
import com.silverwrist.dynamo.module.ModuleOperations;
import com.silverwrist.dynamo.security.SecurityReferenceMonitor;
import com.silverwrist.dynamo.util.*;
import com.silverwrist.venice.CommunitySearchField;
import com.silverwrist.venice.SearchMode;
import com.silverwrist.venice.VeniceNamespaces;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.iface.*;
public class CommunityManager
implements NamedObject, ComponentInitialize, ComponentShutdown, CommunityService, CommunityProxyService
{
/*--------------------------------------------------------------------------------
* Internal class implementing community proxies
*--------------------------------------------------------------------------------
*/
private class MyCommunityProxy extends CommunityProxy
{
/*====================================================================
* Attributes
*====================================================================
*/
private VeniceCommunity m_real_community = null;
/*====================================================================
* Constructors
*====================================================================
*/
MyCommunityProxy(int cid)
{
super(cid);
} // end constructor
/*====================================================================
* Abstract implementations from class CommunityProxy
*====================================================================
*/
protected synchronized VeniceCommunity getRealCommunity()
{
if (m_real_community==null)
{ // need to retrieve the real community...
try
{ // get the real community...
m_real_community = CommunityManager.this.getCommunity(m_id);
} // end try
catch (DatabaseException e)
{ // wrap it in a runtime exception type
throw new ProxyException(e);
} // end catch
} // end if
return m_real_community;
} // end getRealCommunity
} // end class MyCommunityProxy
/*--------------------------------------------------------------------------------
* Internal property serializer class
*--------------------------------------------------------------------------------
*/
private class CommunitySerializer implements PropertySerializer
{
/*====================================================================
* Constructor
*====================================================================
*/
CommunitySerializer()
{ // do nothing
} // end constructor
/*====================================================================
* Implementations from interface PropertySerializer
*====================================================================
*/
public String serializeProperty(Object value)
{
if (value instanceof VeniceCommunity)
return "Community:" + String.valueOf(((VeniceCommunity)value).getCID());
return null;
} // end serializeProperty
public Object deserializeProperty(String value)
{
try
{ // look for our known prefixes
if (value.startsWith("Community:"))
return getCommunityProxy(Integer.parseInt(value.substring(10)));
return null;
} // end try
catch (NumberFormatException e)
{ // number parse blew up...
return null;
} // end catch
} // end deserializeProperty
} // end class CommunitySerializer
/*--------------------------------------------------------------------------------
* Internal class that initializes the services
*--------------------------------------------------------------------------------
*/
private class ServiceInit implements FinalStageInitHook
{
/*====================================================================
* Constructor
*====================================================================
*/
ServiceInit()
{ // do nothing
} // end constructor
/*====================================================================
* Implementations from interface FinalStageInitHook
*====================================================================
*/
public void initialize(Application application, ServiceProvider services) throws DynamoException
{
logger.info("Initializing community service list");
List svclist = m_ops.getMasterServiceList();
ModuleOperations module_ops = (ModuleOperations)(services.queryService(ModuleOperations.class));
Iterator it = svclist.iterator();
while (it.hasNext())
{ // get the Map full of data
Map item = (Map)(it.next());
// make sure we have the module
PropertyKey pk = (PropertyKey)(item.get(CommunityManagerOps.KEY_MODNAME));
Module module = module_ops.findModule(m_ns_cache.namespaceIdToName(pk.getNamespaceID()),pk.getName());
if (module==null)
{ // the module is not loaded - we have to load it
String filename = (String)(item.get(CommunityManagerOps.KEY_MODFILENAME));
module = module_ops.loadModule(filename,true);
QualifiedNameKey modid = module.getModuleID();
PropertyKey pk2 = new PropertyKey(m_ns_cache.namespaceNameToId(modid.getNamespace()),modid.getName());
if (!(pk.equals(pk2)))
{ // module name does not match what we expect - throw exception
CommunityServiceException cse = new CommunityServiceException(CommunityManager.class,"CommunityMessages",
"svc.modname.mismatch");
cse.setParameter(0,filename);
throw cse;
} // end if
} // end if
// now get the CommunityServiceController from the module
pk = (PropertyKey)(item.get(CommunityManagerOps.KEY_OBJNAME));
DynamicObject dobj = module.getProvidedObject(m_ns_cache.namespaceIdToName(pk.getNamespaceID()),pk.getName());
if (!(dobj instanceof CommunityServiceController))
{ // invalid controller object - throw exception
CommunityServiceException cse = new CommunityServiceException(CommunityManager.class,"CommunityMessages",
"svc.object.badType");
cse.setParameter(0,m_ns_cache.namespaceIdToName(pk.getNamespaceID()));
cse.setParameter(1,pk.getName());
throw cse;
} // end if
CommunityServiceController csc = (CommunityServiceController)dobj;
// preserve the descriptors
pk = (PropertyKey)(item.get(CommunityManagerOps.KEY_SVCNAME));
CommunityServiceDescriptor csdesc =
new CommunityServiceDescriptor((Integer)(item.get(CommunityManagerOps.KEY_SVCID)),
new QualifiedNameKey(m_ns_cache.namespaceIdToName(pk.getNamespaceID()),
pk.getName()),
(String)(item.get(CommunityManagerOps.KEY_SHORTVAR)),csc);
m_qname_to_service.put(csdesc.getName(),csdesc);
m_index_to_service.put(item.get(CommunityManagerOps.KEY_SVCID),csdesc);
} // end while
// Now register our ServiceShutdown class as a pre-stage shutdown hook.
FinalStageRegistration fsreg = (FinalStageRegistration)(services.queryService(FinalStageRegistration.class));
fsreg.registerPreStageShutdown(new ServiceShutdown());
} // end initialize
} // end class ServiceInit
/*--------------------------------------------------------------------------------
* Internal class that shuts down the services
*--------------------------------------------------------------------------------
*/
private class ServiceShutdown implements ComponentShutdown
{
/*====================================================================
* Constructor
*====================================================================
*/
ServiceShutdown()
{ // do nothing
} // end constructor
/*====================================================================
* Implementations from interface ComponentShutdown
*====================================================================
*/
public void shutdown()
{
LinkedList shut_list = new LinkedList(m_qname_to_service.values());
m_qname_to_service.clear();
m_index_to_service.clear();
while (shut_list.size()>0)
{ // shut down this community service
CommunityServiceController csc = ((CommunityServiceDescriptor)(shut_list.removeFirst())).getController();
csc.shutdown();
} // end while
} // end shutdown
} // end class ServiceShutdown
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
private static Logger logger = Logger.getLogger(CommunityManager.class);
/*--------------------------------------------------------------------------------
* Attributes
*--------------------------------------------------------------------------------
*/
private String m_name; // this object's name
private CommunityManagerOps m_ops; // database operations object
private NamespaceCache m_ns_cache; // namespace cache object
private SecurityReferenceMonitor m_srm; // security reference monitor
private UserManagement m_users; // user management object
private AuthenticatorLookup m_alook; // authenticator lookup
private PostDynamicUpdate m_post; // where we post dynamic updates
private CategoryService m_cats; // category service object
private ReferenceMap m_id_to_comm; // ReferenceMap of community IDs to communities
private ReferenceMap m_alias_to_comm; // ReferenceMap of community aliases to communities
private Hashtable m_qname_to_service; // maps service QualifiedNameKeys to descriptord
private Hashtable m_index_to_service; // maps service index numbers to descriptors
private ComponentShutdown m_pszreg; // property serializer registration
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public CommunityManager()
{
m_id_to_comm = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT);
m_alias_to_comm = new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT);
m_qname_to_service = new Hashtable();
m_index_to_service = new Hashtable();
} // end constructor
/*--------------------------------------------------------------------------------
* Internal operations
*--------------------------------------------------------------------------------
*/
private final List translateCIDArray(int[] array) throws DatabaseException
{
if (logger.isDebugEnabled())
logger.debug("translateCIDArray(): translating array of length " + array.length);
if (array.length==0)
return Collections.EMPTY_LIST;
ArrayList rc = new ArrayList(array.length);
for (int i=0; i<array.length; i++)
rc.add(this.getCommunity(array[i]));
return Collections.unmodifiableList(rc);
} // end translateCIDArray
private final boolean canGetMemberCommunityList(DynamoUser caller, DynamoUser user) throws DatabaseException
{
if (caller.equals(user))
return true; // a user can always get his OWN member community list
if (m_srm.getAdminUser().equals(caller))
return true; // Administrator can do anything
if (m_srm.getGlobalAcl().testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,
"see.member.community.lists"))
return true; // this user is permitted to see all member community lists
// Get the user's privacy flags and see if they're allowing others to see their member community list.
OptionSet oset = (OptionSet)(user.getObject(VeniceNamespaces.USER_PROFILE_NAMESPACE,"privacy"));
return oset.get(5);
} // end canGetMemberCommunityList
/*--------------------------------------------------------------------------------
* Implementations from interface NamedObject
*--------------------------------------------------------------------------------
*/
public String getName()
{
return m_name;
} // end getName
/*--------------------------------------------------------------------------------
* Implementations from interface ComponentInitialize
*--------------------------------------------------------------------------------
*/
/**
* Initialize the component.
*
* @param config_root Pointer to the section of the Dynamo XML configuration file that configures this
* particular component. This is to be considered "read-only" by the component.
* @param services An implementation of {@link com.silverwrist.dynamo.iface.ServiceProvider ServiceProvider}
* which provides initialization services to the component. This will include an implementation
* of {@link com.silverwrist.dynamo.iface.ObjectProvider ObjectProvider} which may be used to
* get information about other objects previously initialized by the application.
* @exception com.silverwrist.dynamo.except.ConfigException If an error is encountered in the component
* configuration.
*/
public void initialize(Element config_root, ServiceProvider services) throws ConfigException
{
logger.info("CommunityManager initializing");
XMLLoader loader = XMLLoader.get();
String name_pool = null, name_nscache = null, name_srm = null, name_users = null, name_cats = null;
try
{ // verify the right node name
loader.verifyNodeName(config_root,"object");
// get the object's name
m_name = loader.getAttribute(config_root,"name");
// get the name of the database pool and namespace cache
DOMElementHelper config_root_h = new DOMElementHelper(config_root);
Element foo = loader.getSubElement(config_root_h,"database");
name_pool = loader.getAttribute(foo,"connection");
name_nscache = loader.getAttribute(foo,"namespaces");
// get the name of the security reference monitor
foo = loader.getSubElement(config_root_h,"security");
name_srm = loader.getAttribute(foo,"object");
// get the name of the user manager
foo = loader.getSubElement(config_root_h,"user-manager");
name_users = loader.getAttribute(foo,"object");
// get the name of the categories object
foo = loader.getSubElement(config_root_h,"providers");
name_cats = loader.getAttribute(foo,"categories");
} // end try
catch (XMLLoadException e)
{ // error loading XML config data
logger.fatal("XML loader exception in CommunityManager",e);
throw new ConfigException(e);
} // end catch
// Get the database connection pool.
DBConnectionPool pool = GetObjectUtils.getDatabaseConnection(services,name_pool);
// Get the operations object.
m_ops = CommunityManagerOps.get(pool);
// Get the namespace cache.
m_ns_cache = (NamespaceCache)(GetObjectUtils.getDynamoComponent(services,NamespaceCache.class,name_nscache));
// Get the security reference monitor.
m_srm = (SecurityReferenceMonitor)(GetObjectUtils.getDynamoComponent(services,SecurityReferenceMonitor.class,
name_srm));
// Get the user management object.
m_users = (UserManagement)(GetObjectUtils.getDynamoComponent(services,UserManagement.class,name_users));
// Get the category service object.
m_cats = (CategoryService)(GetObjectUtils.getDynamoComponent(services,CategoryService.class,name_cats));
// Get the authenticator lookup service.
m_alook = (AuthenticatorLookup)(services.queryService(AuthenticatorLookup.class));
// Get the dynamic update poster.
m_post = (PostDynamicUpdate)(services.queryService(PostDynamicUpdate.class));
// Register our property serializer to let Community objects be serialized.
PropertySerializerRegistration psreg =
(PropertySerializerRegistration)(services.queryService(PropertySerializerRegistration.class));
m_pszreg = psreg.registerPropertySerializer(new CommunitySerializer());
// Register our ServiceInit class as a pre-stage init hook.
FinalStageRegistration fsreg = (FinalStageRegistration)(services.queryService(FinalStageRegistration.class));
fsreg.registerFinalStageInitHook(new ServiceInit());
} // end initialize
/*--------------------------------------------------------------------------------
* Implementations from interface ComponentShutdown
*--------------------------------------------------------------------------------
*/
public void shutdown()
{
m_pszreg.shutdown();
m_pszreg = null;
m_id_to_comm.clear();
m_alias_to_comm.clear();
m_post = null;
m_alook = null;
m_cats = null;
m_users = null;
m_srm = null;
m_ns_cache = null;
m_ops.dispose();
m_ops = null;
} // end shutdown
/*--------------------------------------------------------------------------------
* Implementations from interface CommunityService
*--------------------------------------------------------------------------------
*/
public List getMemberCommunities(DynamoUser caller, DynamoUser user)
throws DatabaseException, DynamoSecurityException
{
if (logger.isDebugEnabled())
logger.debug("CommunityManager.getMemberCommunities: " + caller.getName() + " getting community list for "
+ user.getName());
if (!(canGetMemberCommunityList(caller,user)))
{ // not permitted - bye!
logger.error("CommunityManager.getMemberCommunities: permission denied for " + caller.getName()
+ " to get community list for " + user.getName());
DynamoSecurityException dse = new DynamoSecurityException(CommunityManager.class,"CommunityMessages",
"auth.getCommList");
dse.setParameter(0,user.getName());
throw dse;
} // end if
// call down to ops object, then translate the returned CIDs into VeniceCommunity objects
return translateCIDArray(m_ops.getMemberCommunityIDs(user.getUID()));
} // end getMemberCommunities
public synchronized VeniceCommunity getCommunity(int cid) throws DatabaseException
{
if (logger.isDebugEnabled())
logger.debug("CommunityManager.getCommunity(" + cid + ")");
Integer key = new Integer(cid);
CommunityImpl rc = (CommunityImpl)(m_id_to_comm.get(key));
if (rc==null)
{ // look up the community's information in the database
Map data = m_ops.lookupCommunity(cid);
if (data==null)
{ // community not found
DatabaseException de = new DatabaseException(CommunityManager.class,"CommunityMessages","cid.notfound");
de.setParameter(0,String.valueOf(cid));
throw de;
} // end if
// The object might have been erased from the ID map but not the alias map. Check there.
rc = (CommunityImpl)(m_alias_to_comm.get(data.get(CommunityManagerOps.KEY_ALIAS)));
if (rc==null)
{ // create the CommunityImpl object
rc = new CommunityImpl(this,m_ops.getCommunityOps(),m_ns_cache,m_srm,m_users,m_alook,m_post,m_cats,data);
// poke the maps with the new object
m_id_to_comm.put(key,rc);
m_alias_to_comm.put(rc.getAlias(),rc);
} // end if
else // put it back into the ID map
m_id_to_comm.put(key,rc);
} // end if
else // put it into the "alias" map, as it might have been removed from there
m_alias_to_comm.put(rc.getAlias(),rc);
return (VeniceCommunity)rc;
} // end getCommunity
public VeniceCommunity getCommunity(String alias) throws DatabaseException
{
CommunityImpl rc = (CommunityImpl)(m_alias_to_comm.get(alias));
if (rc==null)
{ // look up the community's information in the database
Map data = m_ops.lookupCommunity(alias);
if (data==null)
{ // community not found
DatabaseException de = new DatabaseException(CommunityManager.class,"CommunityMessages","alias.notfound");
de.setParameter(0,alias);
throw de;
} // end if
// The object might have been erased from the alias map but not the ID map. Check there.
Integer key = (Integer)(data.get(CommunityManagerOps.KEY_CID));
rc = (CommunityImpl)(m_id_to_comm.get(key));
if (rc==null)
{ // create the CommunityImpl object
rc = new CommunityImpl(this,m_ops.getCommunityOps(),m_ns_cache,m_srm,m_users,m_alook,m_post,m_cats,data);
// poke the maps with the new object
m_id_to_comm.put(key,rc);
m_alias_to_comm.put(rc.getAlias(),rc);
} // end if
else // put it back into the alias map
m_alias_to_comm.put(rc.getAlias(),rc);
} // end if
else // put it into the "ID" map, as it might have been removed from there
m_id_to_comm.put(new Integer(rc.getCID()),rc);
return (VeniceCommunity)rc;
} // end getCommunity
public List searchForCommunities(DynamoUser caller, CommunitySearchField field, SearchMode mode, String term,
int offset, int count) throws DatabaseException
{
boolean show_all = m_srm.getGlobalAcl().testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,
"community.search.all");
int[] rc = null;
if (CommunitySearchField.NAME.equals(field))
rc = m_ops.searchName(mode,term,show_all,offset,count);
else if (CommunitySearchField.SYNOPSIS.equals(field))
rc = m_ops.searchProperty(m_ns_cache.namespaceNameToId(VeniceNamespaces.COMMUNITY_PROFILE_NAMESPACE),"synopsis",
mode,term,show_all,offset,count);
else
throw new IllegalArgumentException("invalid search field (shouldn't happen)");
return translateCIDArray(rc);
} // end searchForCommunities
public int getSearchCommunityCount(DynamoUser caller, CommunitySearchField field, SearchMode mode, String term)
throws DatabaseException
{
boolean show_all = m_srm.getGlobalAcl().testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,
"community.search.all");
if (CommunitySearchField.NAME.equals(field))
return m_ops.searchNameCount(mode,term,show_all);
else if (CommunitySearchField.SYNOPSIS.equals(field))
return m_ops.searchPropertyCount(m_ns_cache.namespaceNameToId(VeniceNamespaces.COMMUNITY_PROFILE_NAMESPACE),
"synopsis",mode,term,show_all);
else
throw new IllegalArgumentException("invalid search field (shouldn't happen)");
} // end getSearchCommunityCount
public List getCommunitiesInCategory(DynamoUser caller, int catid, int offset, int count) throws DatabaseException
{
boolean show_all = m_srm.getGlobalAcl().testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,
"community.directory.all");
return translateCIDArray(m_ops.getCommunityIDsInCategory(catid,show_all,offset,count));
} // end getCommunitiesInCategory
public List getCommunitiesInCategory(DynamoUser caller, VeniceCategory cat, int offset, int count)
throws DatabaseException
{
return this.getCommunitiesInCategory(caller,cat.getCategoryID(),offset,count);
} // end getCommunitiesInCategory
public int getNumCommunitiesInCategory(DynamoUser caller, int catid) throws DatabaseException
{
boolean show_all = m_srm.getGlobalAcl().testPermission(caller,VeniceNamespaces.COMMUNITY_PERMS_NAMESPACE,
"community.directory.all");
return m_ops.getNumCommunityIDsInCategory(catid,show_all);
} // end getNumCommunitiesInCategory
public int getNumCommunitiesInCategory(DynamoUser caller, VeniceCategory cat) throws DatabaseException
{
return this.getNumCommunitiesInCategory(caller,cat.getCategoryID());
} // end getNumCommunitiesInCategory
public List getAvailableServices()
{
if (m_qname_to_service.isEmpty())
return Collections.EMPTY_LIST;
ArrayList rc = new ArrayList(m_qname_to_service.values());
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
return Collections.unmodifiableList(rc);
} // end getAvailableServices
public CommunityServiceDescriptor getServiceForID(int id)
{
return (CommunityServiceDescriptor)(m_index_to_service.get(new Integer(id)));
} // end getServiceForID
public CommunityServiceDescriptor getServiceForName(String namespace, String name)
{
return (CommunityServiceDescriptor)(m_qname_to_service.get(new QualifiedNameKey(namespace,name)));
} // end getServiceForName
/*--------------------------------------------------------------------------------
* Implementations from interface CommunityProxyService
*--------------------------------------------------------------------------------
*/
public synchronized VeniceCommunity getCommunityProxy(int cid)
{
Integer key = new Integer(cid);
VeniceCommunity rc = (VeniceCommunity)(m_id_to_comm.get(key));
if (rc!=null)
m_alias_to_comm.put(rc.getAlias(),(CommunityImpl)rc);
else
rc = new MyCommunityProxy(cid);
return rc;
} // end getCommunityProxy
} // end class CommunityManager