0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/site/tags/sakai_2-4-1/site-impl/impl/src/java/org/sakaiproject/site/impl/BaseSiteService.java $
0003: * $Id: BaseSiteService.java 22828 2007-03-17 19:00:21Z ggolden@umich.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.site.impl;
0021:
0022: import java.io.PrintWriter;
0023: import java.sql.Connection;
0024: import java.util.ArrayList;
0025: import java.util.Collection;
0026: import java.util.Collections;
0027: import java.util.Iterator;
0028: import java.util.List;
0029: import java.util.Map;
0030: import java.util.Observer;
0031: import java.util.Properties;
0032: import java.util.ResourceBundle;
0033: import java.util.Set;
0034: import java.util.Stack;
0035: import java.util.Vector;
0036:
0037: import javax.servlet.http.HttpServletRequest;
0038: import javax.servlet.http.HttpServletResponse;
0039:
0040: import org.apache.commons.logging.Log;
0041: import org.apache.commons.logging.LogFactory;
0042: import org.sakaiproject.authz.api.AuthzGroup;
0043: import org.sakaiproject.authz.api.AuthzGroupService;
0044: import org.sakaiproject.authz.api.AuthzPermissionException;
0045: import org.sakaiproject.authz.api.FunctionManager;
0046: import org.sakaiproject.authz.api.GroupNotDefinedException;
0047: import org.sakaiproject.authz.api.Role;
0048: import org.sakaiproject.authz.api.SecurityAdvisor;
0049: import org.sakaiproject.authz.api.SecurityService;
0050: import org.sakaiproject.component.api.ServerConfigurationService;
0051: import org.sakaiproject.entity.api.ContextObserver;
0052: import org.sakaiproject.entity.api.Edit;
0053: import org.sakaiproject.entity.api.Entity;
0054: import org.sakaiproject.entity.api.EntityAccessOverloadException;
0055: import org.sakaiproject.entity.api.EntityCopyrightException;
0056: import org.sakaiproject.entity.api.EntityManager;
0057: import org.sakaiproject.entity.api.EntityNotDefinedException;
0058: import org.sakaiproject.entity.api.EntityPermissionException;
0059: import org.sakaiproject.entity.api.EntityProducer;
0060: import org.sakaiproject.entity.api.HttpAccess;
0061: import org.sakaiproject.entity.api.Reference;
0062: import org.sakaiproject.entity.api.ResourceProperties;
0063: import org.sakaiproject.entity.api.ResourcePropertiesEdit;
0064: import org.sakaiproject.event.api.EventTrackingService;
0065: import org.sakaiproject.exception.IdInvalidException;
0066: import org.sakaiproject.exception.IdUnusedException;
0067: import org.sakaiproject.exception.IdUsedException;
0068: import org.sakaiproject.exception.PermissionException;
0069: import org.sakaiproject.javax.PagingPosition;
0070: import org.sakaiproject.memory.api.MemoryService;
0071: import org.sakaiproject.site.api.Group;
0072: import org.sakaiproject.site.api.Site;
0073: import org.sakaiproject.site.api.SiteAdvisor;
0074: import org.sakaiproject.site.api.SitePage;
0075: import org.sakaiproject.site.api.SiteService;
0076: import org.sakaiproject.site.api.ToolConfiguration;
0077: import org.sakaiproject.thread_local.api.ThreadLocalManager;
0078: import org.sakaiproject.time.api.Time;
0079: import org.sakaiproject.time.api.TimeService;
0080: import org.sakaiproject.tool.api.SessionManager;
0081: import org.sakaiproject.user.api.User;
0082: import org.sakaiproject.user.api.UserDirectoryService;
0083: import org.sakaiproject.user.api.UserNotDefinedException;
0084: import org.sakaiproject.util.StorageUser;
0085: import org.sakaiproject.util.StringUtil;
0086: import org.sakaiproject.util.Validator;
0087: import org.w3c.dom.Document;
0088: import org.w3c.dom.Element;
0089:
0090: /**
0091: * <p>
0092: * BaseSiteService is a base implementation of the SiteService.
0093: * </p>
0094: */
0095: public abstract class BaseSiteService implements SiteService,
0096: StorageUser {
0097: /** Our logger. */
0098: private static Log M_log = LogFactory.getLog(BaseSiteService.class);
0099:
0100: /** The layouts in human readable form (localized) */
0101: static ResourceBundle rb = ResourceBundle.getBundle("site-impl");
0102:
0103: /** Storage manager for this service. */
0104: protected Storage m_storage = null;
0105:
0106: /** The initial portion of a relative access point URL. */
0107: protected String m_relativeAccessPoint = null;
0108:
0109: /** A site cache. */
0110: protected SiteCacheImpl m_siteCache = null;
0111:
0112: /** A list of observers watching site save events **/
0113: protected List<SiteAdvisor> siteAdvisors;
0114:
0115: /**********************************************************************************************************************************************************************************************************************************************************
0116: * Abstractions, etc.
0117: *********************************************************************************************************************************************************************************************************************************************************/
0118:
0119: /**
0120: * Construct storage for this service.
0121: */
0122: protected abstract Storage newStorage();
0123:
0124: /**
0125: * Access the partial URL that forms the root of resource URLs.
0126: *
0127: * @param relative
0128: * if true, form within the access path only (i.e. starting with /content)
0129: * @return the partial URL that forms the root of resource URLs.
0130: */
0131: protected String getAccessPoint(boolean relative) {
0132: return (relative ? "" : serverConfigurationService()
0133: .getAccessUrl())
0134: + m_relativeAccessPoint;
0135: }
0136:
0137: /**
0138: * Access the site id extracted from a site reference.
0139: *
0140: * @param ref
0141: * The site reference string.
0142: * @return The the site id extracted from a site reference.
0143: */
0144: protected String siteId(String ref) {
0145: String start = getAccessPoint(true) + Entity.SEPARATOR;
0146: int i = ref.indexOf(start);
0147: if (i == -1)
0148: return ref;
0149: String id = ref.substring(i + start.length());
0150: return id;
0151: }
0152:
0153: /**
0154: * Check security permission.
0155: *
0156: * @param lock
0157: * The lock id string.
0158: * @param resource
0159: * The resource reference string, or null if no resource is involved.
0160: * @return true if allowd, false if not
0161: */
0162: protected boolean unlockCheck(String lock, String resource) {
0163: if (!securityService().unlock(lock, resource)) {
0164: return false;
0165: }
0166:
0167: return true;
0168: }
0169:
0170: /**
0171: * Check security permission.
0172: *
0173: * @param lock
0174: * The lock id string.
0175: * @param resource
0176: * The resource reference string, or null if no resource is involved.
0177: * @exception PermissionException
0178: * Thrown if the user does not have access
0179: */
0180: protected void unlock(String lock, String resource)
0181: throws PermissionException {
0182: if (!unlockCheck(lock, resource)) {
0183: throw new PermissionException(sessionManager()
0184: .getCurrentSessionUserId(), lock, resource);
0185: }
0186: }
0187:
0188: /**
0189: * Check security permission.
0190: *
0191: * @param lock1
0192: * The lock id string.
0193: * @param lock2
0194: * The lock id string.
0195: * @param resource
0196: * The resource reference string, or null if no resource is involved.
0197: * @return true if either allowed, false if not
0198: */
0199: protected boolean unlockCheck2(String lock1, String lock2,
0200: String resource) {
0201: if (!securityService().unlock(lock1, resource)) {
0202: if (!securityService().unlock(lock2, resource)) {
0203: return false;
0204: }
0205: }
0206:
0207: return true;
0208: }
0209:
0210: /**
0211: * Check security permission.
0212: *
0213: * @param lock1
0214: * The lock id string.
0215: * @param lock2
0216: * The lock id string.
0217: * @param resource
0218: * The resource reference string, or null if no resource is involved.
0219: * @exception PermissionException
0220: * Thrown if the user does not have access to either.
0221: */
0222: protected void unlock2(String lock1, String lock2, String resource)
0223: throws PermissionException {
0224: if (!unlockCheck2(lock1, lock2, resource)) {
0225: throw new PermissionException(sessionManager()
0226: .getCurrentSessionUserId(), lock1 + "/" + lock2,
0227: resource);
0228: }
0229: }
0230:
0231: /**
0232: * Update the live properties for a site for when modified.
0233: */
0234: protected void addLiveUpdateProperties(BaseSite site) {
0235: String current = sessionManager().getCurrentSessionUserId();
0236:
0237: site.m_lastModifiedUserId = current;
0238: site.m_lastModifiedTime = timeService().newTime();
0239: }
0240:
0241: /**
0242: * Create the live properties for the site.
0243: */
0244: protected void addLiveProperties(BaseSite site) {
0245: String current = sessionManager().getCurrentSessionUserId();
0246:
0247: site.m_createdUserId = current;
0248: site.m_lastModifiedUserId = current;
0249:
0250: Time now = timeService().newTime();
0251: site.m_createdTime = now;
0252: site.m_lastModifiedTime = (Time) now.clone();
0253: }
0254:
0255: /**
0256: * Return the url unchanged, unless it's a reference, then return the reference url
0257: */
0258: protected String convertReferenceUrl(String url) {
0259: // make a reference
0260: Reference ref = entityManager().newReference(url);
0261:
0262: // if it didn't recognize this, return it unchanged
0263: if (!ref.isKnownType())
0264: return url;
0265:
0266: // return the reference's url
0267: return ref.getUrl();
0268: }
0269:
0270: /**
0271: * Regenerate the page and tool ids for all sites.
0272: */
0273: protected void regenerateAllSiteIds() {
0274: List sites = m_storage.getAll();
0275: for (Iterator iSites = sites.iterator(); iSites.hasNext();) {
0276: Site site = (Site) iSites.next();
0277: Site edit = m_storage.get(site.getId());
0278: if (site != null) {
0279: edit.regenerateIds();
0280: m_storage.save(edit);
0281:
0282: M_log.info("regenerateAllSiteIds: site: "
0283: + site.getId());
0284: } else {
0285: M_log.warn("regenerateAllSiteIds: site: "
0286: + site.getId() + " could not be edited.");
0287: }
0288: }
0289: }
0290:
0291: /**********************************************************************************************************************************************************************************************************************************************************
0292: * Configuration
0293: *********************************************************************************************************************************************************************************************************************************************************/
0294:
0295: /** If true, run the regenerate ids pass on all sites at startup. */
0296: protected boolean m_regenerateIds = false;
0297:
0298: /**
0299: * Configuration: regenerate all site;'s page and tool ids to assure uniqueness.
0300: *
0301: * @param value
0302: * The regenerate ids value
0303: */
0304: public void setRegenerateIds(String value) {
0305: m_regenerateIds = new Boolean(value).booleanValue();
0306: }
0307:
0308: /** The # seconds to cache the site queries. 0 disables the cache. */
0309: protected int m_cacheSeconds = 3 * 60;
0310:
0311: /**
0312: * Set the # minutes to cache the site queries.
0313: *
0314: * @param time
0315: * The # minutes to cache the site queries (as an integer string).
0316: */
0317: public void setCacheMinutes(String time) {
0318: m_cacheSeconds = Integer.parseInt(time) * 60;
0319: }
0320:
0321: /** The # seconds to cache gets. 0 disables the cache. */
0322: protected int m_cacheCleanerSeconds = 15 * 60;
0323:
0324: /**
0325: * Set the # minutes between cache cleanings.
0326: *
0327: * @param time
0328: * The # minutes between cache cleanings. (as an integer string).
0329: */
0330: public void setCacheCleanerMinutes(String time) {
0331: m_cacheCleanerSeconds = Integer.parseInt(time) * 60;
0332: }
0333:
0334: /**********************************************************************************************************************************************************************************************************************************************************
0335: * Dependencies
0336: *********************************************************************************************************************************************************************************************************************************************************/
0337:
0338: /**
0339: * @return the ServerConfigurationService collaborator.
0340: */
0341: protected abstract ServerConfigurationService serverConfigurationService();
0342:
0343: /**
0344: * @return the EntityManager collaborator.
0345: */
0346: protected abstract EntityManager entityManager();
0347:
0348: /**
0349: * @return the EventTrackingService collaborator.
0350: */
0351: protected abstract EventTrackingService eventTrackingService();
0352:
0353: /**
0354: * @return the ThreadLocalManager collaborator.
0355: */
0356: protected abstract ThreadLocalManager threadLocalManager();
0357:
0358: /**
0359: * @return the SecurityService collaborator.
0360: */
0361: protected abstract SecurityService securityService();
0362:
0363: /**
0364: * @return the SessionManager collaborator.
0365: */
0366: protected abstract SessionManager sessionManager();
0367:
0368: /**
0369: * @return the TimeService collaborator.
0370: */
0371: protected abstract TimeService timeService();
0372:
0373: /**
0374: * @return the FunctionManager collaborator.
0375: */
0376: protected abstract FunctionManager functionManager();
0377:
0378: /**
0379: * @return the MemoryService collaborator.
0380: */
0381: protected abstract MemoryService memoryService();
0382:
0383: /**
0384: * @return the UserDirectoryService collaborator.
0385: */
0386: protected abstract UserDirectoryService userDirectoryService();
0387:
0388: /**
0389: * @return the AuthzGroupService collaborator.
0390: */
0391: protected abstract AuthzGroupService authzGroupService();
0392:
0393: /**********************************************************************************************************************************************************************************************************************************************************
0394: * Init and Destroy
0395: *********************************************************************************************************************************************************************************************************************************************************/
0396:
0397: /**
0398: * Final initialization, once all dependencies are set.
0399: */
0400: public void init() {
0401: siteAdvisors = new ArrayList<SiteAdvisor>();
0402:
0403: try {
0404: m_relativeAccessPoint = REFERENCE_ROOT;
0405:
0406: // construct storage and read
0407: m_storage = newStorage();
0408: m_storage.open();
0409:
0410: if (m_regenerateIds) {
0411: regenerateAllSiteIds();
0412: m_regenerateIds = false;
0413: }
0414:
0415: // <= 0 minutes indicates no caching desired
0416: if (m_cacheSeconds > 0) {
0417: // build a synchronized map for the call cache, automatiaclly checking for expiration every 15 mins.
0418: m_siteCache = new SiteCacheImpl(memoryService(),
0419: m_cacheCleanerSeconds, siteReference(""));
0420: }
0421:
0422: // register as an entity producer
0423: entityManager()
0424: .registerEntityProducer(this , REFERENCE_ROOT);
0425:
0426: // register functions
0427: functionManager().registerFunction(SITE_VISIT);
0428: functionManager().registerFunction(SITE_VISIT_UNPUBLISHED);
0429: functionManager().registerFunction(SECURE_ADD_SITE);
0430: functionManager().registerFunction(SECURE_ADD_USER_SITE);
0431: functionManager().registerFunction(SECURE_REMOVE_SITE);
0432: functionManager().registerFunction(SECURE_UPDATE_SITE);
0433: functionManager().registerFunction(SECURE_VIEW_ROSTER);
0434: functionManager().registerFunction(
0435: SECURE_UPDATE_SITE_MEMBERSHIP);
0436: functionManager().registerFunction(
0437: SECURE_UPDATE_GROUP_MEMBERSHIP);
0438:
0439: M_log.info("init() - caching minutes: " + m_cacheSeconds
0440: / 60);
0441: } catch (Throwable t) {
0442: M_log.warn(".init(): ", t);
0443: }
0444: }
0445:
0446: /**
0447: * Returns to uninitialized state.
0448: */
0449: public void destroy() {
0450: m_storage.close();
0451: m_storage = null;
0452:
0453: M_log.info("destroy()");
0454: }
0455:
0456: /**********************************************************************************************************************************************************************************************************************************************************
0457: * SiteService implementation
0458: *********************************************************************************************************************************************************************************************************************************************************/
0459:
0460: /**
0461: * @inheritDoc
0462: */
0463: public String[] getLayoutNames() {
0464: String[] rv = new String[2];
0465: rv[0] = rb.getString("sitpag.lay_sngl");
0466: rv[1] = rb.getString("sitpag.lay_dbl");
0467: return rv;
0468: }
0469:
0470: /**
0471: * @inheritDoc
0472: */
0473: public boolean allowAccessSite(String id) {
0474: boolean rv = false;
0475:
0476: try {
0477: Site site = getSite(id);
0478: if (site.isPublished()) {
0479: rv = unlockCheck(SITE_VISIT, site.getReference());
0480: }
0481:
0482: else {
0483: rv = unlockCheck(SITE_VISIT_UNPUBLISHED, site
0484: .getReference());
0485: }
0486: } catch (Exception ignore) {
0487: }
0488:
0489: return rv;
0490: }
0491:
0492: /**
0493: * Access an already defined site object.
0494: *
0495: * @param id
0496: * The site id string.
0497: * @return A site object containing the site information
0498: * @exception IdUnusedException
0499: * if not found
0500: */
0501: protected Site getDefinedSite(String id) throws IdUnusedException {
0502: if (id == null)
0503: throw new IdUnusedException("<null>");
0504:
0505: Site rv = null;
0506:
0507: // check the cache
0508: String ref = siteReference(id);
0509: if ((m_siteCache != null) && (m_siteCache.containsKey(ref))) {
0510: // some cached things are Booleans (site exists), not sites
0511: Object o = m_siteCache.get(ref);
0512: if ((o != null) && (o instanceof Site)) {
0513: rv = (Site) o;
0514:
0515: // return a copy of the site from the cache
0516: rv = new BaseSite(rv, true);
0517:
0518: return rv;
0519: }
0520: }
0521:
0522: rv = m_storage.get(id);
0523:
0524: // if not found
0525: if (rv == null)
0526: throw new IdUnusedException(id);
0527:
0528: // get all of the site loaded
0529: rv.loadAll();
0530:
0531: // track it - we don't track site access -ggolden
0532: // EventTrackingService.post(EventTrackingService.newEvent(SECURE_ACCESS_SITE, site.getReference()));
0533:
0534: // cache a copy
0535: if (m_siteCache != null) {
0536: Site copy = new BaseSite(rv, true);
0537: m_siteCache.put(ref, copy, m_cacheSeconds);
0538: }
0539:
0540: return rv;
0541: }
0542:
0543: /**
0544: * @inheritDoc
0545: */
0546: public boolean siteExists(String id) {
0547: if (id != null) {
0548: // check the cache
0549: String ref = siteReference(id);
0550: if ((m_siteCache != null) && (m_siteCache.containsKey(ref))) {
0551: Object o = m_siteCache.get(ref);
0552: if (o != null) {
0553: if (o instanceof Site) {
0554: return true;
0555: }
0556:
0557: if (o instanceof Boolean) {
0558: // misses are cached, too
0559: return o == Boolean.TRUE;
0560: }
0561: }
0562: }
0563:
0564: // check the exists cache
0565: if (m_storage.check(id)) {
0566: // cache it
0567: if (m_siteCache != null) {
0568: m_siteCache.put(siteReference(id), Boolean.TRUE,
0569: m_cacheSeconds);
0570: }
0571:
0572: return true;
0573: }
0574:
0575: else {
0576: // cache the miss
0577: if (m_siteCache != null) {
0578: m_siteCache.put(siteReference(id), Boolean.FALSE,
0579: m_cacheSeconds);
0580: }
0581: }
0582: }
0583:
0584: return false;
0585: }
0586:
0587: /**
0588: * @inheritDoc
0589: */
0590: public Site getSite(String id) throws IdUnusedException {
0591: if (id == null) {
0592: throw new IdUnusedException("null");
0593: }
0594:
0595: try {
0596: return getDefinedSite(id);
0597: } catch (IdUnusedException e) {
0598: // if this is the current user's site, we can create it
0599: if (isUserSite(id)
0600: && id.substring(1).equals(
0601: sessionManager().getCurrentSessionUserId())) {
0602: // pick a template, type based, to clone it exactly but set this as the id
0603: BaseSite template = null;
0604: try {
0605: User user = userDirectoryService().getUser(
0606: sessionManager().getCurrentSessionUserId());
0607: template = (BaseSite) getDefinedSite(USER_SITE_TEMPLATE
0608: + "." + user.getType());
0609: } catch (Throwable t) {
0610: }
0611:
0612: // if a type based template was not found, use the generic one
0613: // will throw IdUnusedException all the way out of this method if that's not defined
0614: if (template == null) {
0615: template = (BaseSite) getDefinedSite(USER_SITE_TEMPLATE);
0616: }
0617:
0618: // reserve a site with this id from the info store - if it's in use, this will return null
0619: try {
0620: // check security (throws if not permitted)
0621: unlock(SECURE_ADD_USER_SITE, siteReference(id));
0622:
0623: // reserve a site with this id from the info store - if it's in use, this will return null
0624: BaseSite site = (BaseSite) m_storage.put(id);
0625: if (site == null) {
0626: throw new IdUsedException(id);
0627: }
0628:
0629: site.setEvent(SECURE_ADD_SITE);
0630:
0631: // copy in the template
0632: site.set(template, false);
0633:
0634: doSave(site, true);
0635:
0636: return site;
0637: } catch (IdUsedException ee) {
0638: throw e;
0639: } catch (PermissionException ee) {
0640: throw e;
0641: }
0642: } else {
0643: throw e;
0644: }
0645: }
0646: }
0647:
0648: /**
0649: * @inheritDoc
0650: */
0651: public Site getSiteVisit(String id) throws IdUnusedException,
0652: PermissionException {
0653: // get the site
0654: Site rv = getSite(id);
0655:
0656: // check for visit permission
0657: if (rv.isPublished()) {
0658: unlock(SITE_VISIT, rv.getReference());
0659: } else {
0660: unlock(SITE_VISIT_UNPUBLISHED, rv.getReference());
0661: }
0662:
0663: return rv;
0664: }
0665:
0666: /**
0667: * @inheritDoc
0668: */
0669: public boolean allowUpdateSite(String id) {
0670: return unlockCheck(SECURE_UPDATE_SITE, siteReference(id));
0671: }
0672:
0673: /**
0674: * @inheritDoc
0675: */
0676: public boolean allowUpdateSiteMembership(String id) {
0677: return unlockCheck2(SECURE_UPDATE_SITE,
0678: SECURE_UPDATE_SITE_MEMBERSHIP, siteReference(id));
0679: }
0680:
0681: /**
0682: * @inheritDoc
0683: */
0684: public boolean allowUpdateGroupMembership(String id) {
0685: return unlockCheck2(SECURE_UPDATE_SITE,
0686: SECURE_UPDATE_GROUP_MEMBERSHIP, siteReference(id));
0687: }
0688:
0689: /**
0690: * @inheritDoc
0691: */
0692: public void save(Site site) throws IdUnusedException,
0693: PermissionException {
0694: if (site.getId() == null)
0695: throw new IdUnusedException("<null>");
0696:
0697: String siteRef = site.getReference();
0698:
0699: if (!unlockCheck(SECURE_UPDATE_GROUP_MEMBERSHIP, siteRef)
0700: && !unlockCheck(SECURE_UPDATE_SITE_MEMBERSHIP, siteRef)) {
0701: // check security (throws if not permitted)
0702: unlock(SECURE_UPDATE_SITE, siteRef);
0703: }
0704:
0705: // check for existance
0706: if (!m_storage.check(site.getId())) {
0707: throw new IdUnusedException(site.getId());
0708: }
0709:
0710: // Save the site
0711: doSave((BaseSite) site, false);
0712: }
0713:
0714: /**
0715: * @inheritDoc
0716: */
0717: public void saveSiteMembership(Site site) throws IdUnusedException,
0718: PermissionException {
0719: if (site.getId() == null)
0720: throw new IdUnusedException("<null>");
0721:
0722: // check security (throws if not permitted)
0723: unlock2(SECURE_UPDATE_SITE_MEMBERSHIP, SECURE_UPDATE_SITE, site
0724: .getReference());
0725:
0726: // check for existance
0727: if (!m_storage.check(site.getId())) {
0728: throw new IdUnusedException(site.getId());
0729: }
0730:
0731: enableAzgSecurityAdvisor();
0732: saveSiteAzg(site);
0733: securityService().clearAdvisors();
0734:
0735: // track it
0736: eventTrackingService().post(
0737: eventTrackingService().newEvent(
0738: SECURE_UPDATE_SITE_MEMBERSHIP,
0739: site.getReference(), true));
0740: }
0741:
0742: /**
0743: * @inheritDoc
0744: */
0745: public void saveGroupMembership(Site site)
0746: throws IdUnusedException, PermissionException {
0747: if (site.getId() == null)
0748: throw new IdUnusedException("<null>");
0749:
0750: // check security (throws if not permitted)
0751: unlock2(SECURE_UPDATE_GROUP_MEMBERSHIP, SECURE_UPDATE_SITE,
0752: site.getReference());
0753:
0754: // check for existance
0755: if (!m_storage.check(site.getId())) {
0756: throw new IdUnusedException(site.getId());
0757: }
0758:
0759: enableAzgSecurityAdvisor();
0760: saveGroupAzgs(site);
0761: securityService().clearAdvisors();
0762:
0763: // track it
0764: eventTrackingService().post(
0765: eventTrackingService().newEvent(
0766: SECURE_UPDATE_GROUP_MEMBERSHIP,
0767: site.getReference(), true));
0768: }
0769:
0770: /**
0771: * Comlete the save process.
0772: *
0773: * @param site
0774: * The site to save.
0775: */
0776: protected void doSave(BaseSite site, boolean isNew) {
0777: if (isNew) {
0778: addLiveProperties(site);
0779: }
0780:
0781: // update the properties
0782: addLiveUpdateProperties(site);
0783:
0784: // Give the site advisors, if any, a chance to make last minute changes to the site
0785: for (Iterator<SiteAdvisor> iter = siteAdvisors.iterator(); iter
0786: .hasNext();) {
0787: iter.next().update(site);
0788: }
0789:
0790: // complete the edit
0791: m_storage.save(site);
0792:
0793: // save any modified azgs
0794: enableAzgSecurityAdvisor();
0795: saveSiteAzg(site);
0796: saveGroupAzgs(site);
0797: securityService().clearAdvisors();
0798:
0799: // sync up with all other services
0800: // TODO: do this under the security advisor, too, so we don't need all the various service security on site creation? -ggolden
0801: enableRelated(site, isNew);
0802:
0803: // track it
0804: String event = site.getEvent();
0805: if (event == null)
0806: event = SECURE_UPDATE_SITE;
0807: eventTrackingService().post(
0808: eventTrackingService().newEvent(event,
0809: site.getReference(), true));
0810:
0811: // clear the event for next time
0812: site.setEvent(null);
0813: }
0814:
0815: /**
0816: * Establish a security advisor to allow the "embedded" azg work to occur with no need for additional security permissions.
0817: */
0818: protected void enableAzgSecurityAdvisor() {
0819: // put in a security advisor so we can do our azg work without need of further permissions
0820: // TODO: could make this more specific to the AuthzGroupService.SECURE_UPDATE_AUTHZ_GROUP permission -ggolden
0821: securityService().pushAdvisor(new SecurityAdvisor() {
0822: public SecurityAdvice isAllowed(String userId,
0823: String function, String reference) {
0824: return SecurityAdvice.ALLOWED;
0825: }
0826: });
0827: }
0828:
0829: /**
0830: * Save the site's azg if modified.
0831: *
0832: * @param site
0833: * The site to save.
0834: */
0835: protected void saveSiteAzg(Site site) {
0836: if (((BaseSite) site).m_azgChanged) {
0837: try {
0838: authzGroupService().save(((BaseSite) site).m_azg);
0839: } catch (Throwable t) {
0840: M_log.warn(".saveAzgs - site: " + t);
0841: }
0842: ((BaseSite) site).m_azgChanged = false;
0843: }
0844: }
0845:
0846: /**
0847: * Save group azgs that are modified.
0848: *
0849: * @param site
0850: * The site to save.
0851: */
0852: protected void saveGroupAzgs(Site site) {
0853: for (Iterator i = site.getGroups().iterator(); i.hasNext();) {
0854: BaseGroup group = (BaseGroup) i.next();
0855: if (group.m_azgChanged) {
0856: try {
0857: authzGroupService().save(group.m_azg);
0858: } catch (Throwable t) {
0859: M_log.warn(".saveAzgs - group: " + group.getTitle()
0860: + " : " + t);
0861: }
0862: group.m_azgChanged = false;
0863: }
0864: }
0865: }
0866:
0867: /**
0868: * @inheritDoc
0869: */
0870: public void saveSiteInfo(String id, String description,
0871: String infoUrl) throws IdUnusedException,
0872: PermissionException {
0873: String ref = siteReference(id);
0874:
0875: // check security (throws if not permitted)
0876: unlock(SECURE_UPDATE_SITE, ref);
0877:
0878: // check for existance
0879: if (!m_storage.check(id)) {
0880: throw new IdUnusedException(id);
0881: }
0882:
0883: m_storage.saveInfo(id, description, infoUrl);
0884: }
0885:
0886: /**
0887: * @inheritDoc
0888: */
0889: public boolean allowAddSite(String id) {
0890: // check security (throws if not permitted)
0891: if (id != null && isUserSite(id)) {
0892: return unlockCheck(SECURE_ADD_USER_SITE, siteReference(id));
0893: } else {
0894: return unlockCheck(SECURE_ADD_SITE, siteReference(id));
0895: }
0896: }
0897:
0898: /**
0899: * @inheritDoc
0900: */
0901: public Site addSite(String id, String type)
0902: throws IdInvalidException, IdUsedException,
0903: PermissionException {
0904: // check for a valid site name
0905: Validator.checkResourceId(id);
0906:
0907: id = Validator.escapeResourceName(id);
0908:
0909: // check security (throws if not permitted)
0910: unlock(SECURE_ADD_SITE, siteReference(id));
0911:
0912: // reserve a site with this id from the info store - if it's in use, this will return null
0913: Site site = m_storage.put(id);
0914: if (site == null) {
0915: throw new IdUsedException(id);
0916: }
0917:
0918: // set the type before we enable related, since the azg template for the site depends on type
0919: if (type != null) {
0920: site.setType(type);
0921: }
0922:
0923: ((BaseSite) site).setEvent(SECURE_ADD_SITE);
0924:
0925: doSave((BaseSite) site, true);
0926:
0927: return site;
0928: }
0929:
0930: /**
0931: * @inheritDoc
0932: */
0933: public Site addSite(String id, Site other)
0934: throws IdInvalidException, IdUsedException,
0935: PermissionException {
0936: // check for a valid site name
0937: Validator.checkResourceId(id);
0938:
0939: id = Validator.escapeResourceName(id);
0940:
0941: // check security (throws if not permitted)
0942: if (isUserSite(id)) {
0943: unlock(SECURE_ADD_USER_SITE, siteReference(id));
0944: } else {
0945: unlock(SECURE_ADD_SITE, siteReference(id));
0946: }
0947:
0948: // reserve a site with this id from the info store - if it's in use, this will return null
0949: Site site = m_storage.put(id);
0950: if (site == null) {
0951: throw new IdUsedException(id);
0952: }
0953:
0954: // make this site a copy of other, but with new ids (not an exact copy)
0955: ((BaseSite) site).set((BaseSite) other, false);
0956:
0957: // copy the realm (to get permissions settings)
0958: try {
0959: AuthzGroup realm = authzGroupService().getAuthzGroup(
0960: other.getReference());
0961: AuthzGroup re = authzGroupService().addAuthzGroup(
0962: site.getReference(), realm,
0963: userDirectoryService().getCurrentUser().getId());
0964:
0965: // clear the users from the copied realm, adding in the current user as a maintainer
0966: re.removeMembers();
0967: re.addMember(userDirectoryService().getCurrentUser()
0968: .getId(), re.getMaintainRole(), true, false);
0969:
0970: authzGroupService().save(re);
0971: } catch (Exception e) {
0972: M_log.warn(".addSite(): error copying realm", e);
0973: }
0974:
0975: // clear the site's notification id in properties
0976: site.getPropertiesEdit().removeProperty(
0977: ResourceProperties.PROP_SITE_EMAIL_NOTIFICATION_ID);
0978:
0979: ((BaseSite) site).setEvent(SECURE_ADD_SITE);
0980:
0981: doSave((BaseSite) site, true);
0982:
0983: return site;
0984: }
0985:
0986: /**
0987: * @inheritDoc
0988: */
0989: public boolean allowRemoveSite(String id) {
0990: return unlockCheck(SECURE_REMOVE_SITE, siteReference(id));
0991: }
0992:
0993: /**
0994: * @inheritDoc
0995: */
0996: public void removeSite(Site site) throws PermissionException {
0997: // check security (throws if not permitted)
0998: unlock(SECURE_REMOVE_SITE, site.getReference());
0999:
1000: // complete the edit
1001: m_storage.remove(site);
1002:
1003: // track it
1004: eventTrackingService().post(
1005: eventTrackingService().newEvent(SECURE_REMOVE_SITE,
1006: site.getReference(), true));
1007:
1008: // get the services related to this site setup for the site's removal
1009: disableRelated(site);
1010: }
1011:
1012: /**
1013: * @inheritDoc
1014: */
1015: public String siteReference(String id) {
1016: return getAccessPoint(true) + Entity.SEPARATOR + id;
1017: }
1018:
1019: /**
1020: * @inheritDoc
1021: */
1022: public String sitePageReference(String siteId, String pageId) {
1023: return getAccessPoint(true) + Entity.SEPARATOR + siteId
1024: + Entity.SEPARATOR + PAGE_SUBTYPE + Entity.SEPARATOR
1025: + pageId;
1026: }
1027:
1028: /**
1029: * @inheritDoc
1030: */
1031: public String siteToolReference(String siteId, String toolId) {
1032: return getAccessPoint(true) + Entity.SEPARATOR + siteId
1033: + Entity.SEPARATOR + TOOL_SUBTYPE + Entity.SEPARATOR
1034: + toolId;
1035: }
1036:
1037: /**
1038: * @inheritDoc
1039: */
1040: public String siteGroupReference(String siteId, String groupId) {
1041: return getAccessPoint(true) + Entity.SEPARATOR + siteId
1042: + Entity.SEPARATOR + GROUP_SUBTYPE + Entity.SEPARATOR
1043: + groupId;
1044: }
1045:
1046: /**
1047: * @inheritDoc
1048: */
1049: public boolean isUserSite(String site) {
1050: if (site == null)
1051: return false;
1052:
1053: // deal with a reference
1054: if (site.startsWith(siteReference("~"))
1055: && (!site.equals(siteReference("~"))))
1056: return true;
1057:
1058: // deal with an id
1059: return (site.startsWith("~") && (!site.equals("~")));
1060: }
1061:
1062: /**
1063: * @inheritDoc
1064: */
1065: public String getSiteUserId(String site) {
1066: // deal with a reference
1067: String ref = siteReference("~");
1068: if (site.startsWith(ref)) {
1069: return site.substring(ref.length());
1070: }
1071:
1072: else if (site.startsWith("~")) {
1073: return site.substring(1);
1074: }
1075:
1076: return null;
1077: }
1078:
1079: /**
1080: * @inheritDoc
1081: */
1082: public String getUserSiteId(String userId) {
1083: return "~" + userId;
1084: }
1085:
1086: /**
1087: * @inheritDoc
1088: */
1089: public boolean isSpecialSite(String site) {
1090: if (site == null)
1091: return false;
1092:
1093: // Note: ! is special except if it's !admin, not considered special
1094:
1095: // deal with a reference
1096: if (site.startsWith(siteReference("!"))
1097: && !site.equals(siteReference("!admin")))
1098: return true;
1099:
1100: // TODO: legacy code - we don't use the "~" site anymore (!user.template*) -ggolden
1101: if (site.equals(siteReference("~")))
1102: return true;
1103:
1104: // deal with an id
1105: if (site.startsWith("!") && !site.equals("!admin"))
1106: return true;
1107:
1108: // TODO: legacy code - we don't use the "~" site anymore (!user.template*) -ggolden
1109: if (site.equals("~"))
1110: return true;
1111:
1112: return false;
1113: }
1114:
1115: /**
1116: * @inheritDoc
1117: */
1118: public String getSiteSpecialId(String site) {
1119: // deal with a reference
1120: String ref = siteReference("!");
1121: if (site.startsWith(ref)) {
1122: return site.substring(ref.length());
1123: }
1124:
1125: else if (site.startsWith("!")) {
1126: return site.substring(1);
1127: }
1128:
1129: return null;
1130: }
1131:
1132: /**
1133: * @inheritDoc
1134: */
1135: public String getSpecialSiteId(String special) {
1136: return "!" + special;
1137: }
1138:
1139: /**
1140: * @inheritDoc
1141: */
1142: public String getSiteDisplay(String id) {
1143: String rv = "(" + id + ")";
1144:
1145: if (isUserSite(id)) {
1146: String userName = id;
1147: try {
1148: User user = userDirectoryService().getUser(
1149: getSiteUserId(id));
1150: userName = user.getDisplayName();
1151: } catch (UserNotDefinedException ignore) {
1152: }
1153:
1154: rv = "\"" + userName + "'s site\" " + rv;
1155: }
1156:
1157: else {
1158: Site site = null;
1159: try {
1160: site = getSite(id);
1161: rv = "\"" + site.getTitle() + "\" " + rv;
1162: } catch (IdUnusedException ignore) {
1163: }
1164: }
1165:
1166: return rv;
1167: }
1168:
1169: /**
1170: * @inheritDoc
1171: */
1172: public ToolConfiguration findTool(String id) {
1173: ToolConfiguration rv = null;
1174:
1175: // check the site cache
1176: if (m_siteCache != null) {
1177: rv = m_siteCache.getTool(id);
1178: if (rv != null) {
1179: // return a copy from the cache
1180: rv = new BaseToolConfiguration(rv, rv
1181: .getContainingPage(), true);
1182: return rv;
1183: }
1184:
1185: // if not, get the tool's site id, cache the site, and try again
1186: String siteId = m_storage.findToolSiteId(id);
1187: if (siteId != null) {
1188: // read and cache the site, pages, tools, etc.
1189: try {
1190: Site site = getDefinedSite(siteId);
1191:
1192: // return what we find from the copy we got from the cache
1193: rv = site.getTool(id);
1194:
1195: return rv;
1196: } catch (IdUnusedException e) {
1197: }
1198: }
1199:
1200: return null;
1201: }
1202:
1203: rv = m_storage.findTool(id);
1204:
1205: return rv;
1206: }
1207:
1208: /**
1209: * {@inheritDoc}
1210: */
1211: public SitePage findPage(String id) {
1212: SitePage rv = null;
1213:
1214: // check the site cache
1215: if (m_siteCache != null) {
1216: rv = m_siteCache.getPage(id);
1217: if (rv != null) {
1218: rv = new BaseSitePage(rv, rv.getContainingSite(), true);
1219: return rv;
1220: }
1221:
1222: // if not, get the page's site id, cache the site, and try again
1223: String siteId = m_storage.findPageSiteId(id);
1224: if (siteId != null) {
1225: // read and cache the site, pages, tools
1226: try {
1227: Site site = getDefinedSite(siteId);
1228:
1229: // return what we find from the site copy from the cache
1230: rv = site.getPage(id);
1231: return rv;
1232: } catch (IdUnusedException e) {
1233: }
1234: }
1235:
1236: return null;
1237: }
1238:
1239: rv = m_storage.findPage(id);
1240:
1241: return rv;
1242: }
1243:
1244: /**
1245: * @inheritDoc
1246: */
1247: public boolean allowViewRoster(String id) {
1248: return unlockCheck(SECURE_VIEW_ROSTER, siteReference(id));
1249: }
1250:
1251: /**
1252: * @inheritDoc
1253: */
1254: public void join(String id) throws IdUnusedException,
1255: PermissionException {
1256: String user = sessionManager().getCurrentSessionUserId();
1257: if (user == null)
1258: throw new PermissionException(user,
1259: AuthzGroupService.SECURE_UPDATE_OWN_AUTHZ_GROUP,
1260: siteReference(id));
1261:
1262: // get the site
1263: Site site = getDefinedSite(id);
1264:
1265: // must be joinable
1266: if (!site.isJoinable()) {
1267: throw new PermissionException(user,
1268: AuthzGroupService.SECURE_UPDATE_OWN_AUTHZ_GROUP,
1269: siteReference(id));
1270: }
1271:
1272: // the role to assign
1273: String roleId = site.getJoinerRole();
1274: if (roleId == null) {
1275: M_log
1276: .warn(".join(): null site joiner role for site: "
1277: + id);
1278: throw new PermissionException(user,
1279: AuthzGroupService.SECURE_UPDATE_OWN_AUTHZ_GROUP,
1280: siteReference(id));
1281: }
1282:
1283: // do the join
1284: try {
1285: authzGroupService().joinGroup(siteReference(id), roleId);
1286: } catch (GroupNotDefinedException e) {
1287: throw new IdUnusedException(e.getId());
1288: } catch (AuthzPermissionException e) {
1289: throw new PermissionException(e.getUser(), e.getFunction(),
1290: e.getResource());
1291: }
1292: }
1293:
1294: /**
1295: * @inheritDoc
1296: */
1297: public void unjoin(String id) throws IdUnusedException,
1298: PermissionException {
1299: try {
1300: authzGroupService().unjoinGroup(siteReference(id));
1301: } catch (GroupNotDefinedException e) {
1302: throw new IdUnusedException(e.getId());
1303: } catch (AuthzPermissionException e) {
1304: throw new PermissionException(e.getUser(), e.getFunction(),
1305: e.getResource());
1306: }
1307: }
1308:
1309: /**
1310: * @inheritDoc
1311: */
1312: public boolean allowUnjoinSite(String id) {
1313: // basic unjoin AuthzGroup test
1314: if (!authzGroupService().allowUnjoinGroup(siteReference(id)))
1315: return false;
1316:
1317: // one more check - don't let a maintain role user unjoin a non-joinable site, or
1318: // a joinable site that does not have the maintain role as the joiner role.
1319: try {
1320: // get the site
1321: Site site = getDefinedSite(id);
1322:
1323: // get the AuthGroup
1324: AuthzGroup azg = authzGroupService().getAuthzGroup(
1325: siteReference(id));
1326:
1327: String user = sessionManager().getCurrentSessionUserId();
1328: if (user == null)
1329: return false;
1330:
1331: if ((StringUtil.different(site.getJoinerRole(), azg
1332: .getMaintainRole()))
1333: || (!site.isJoinable())) {
1334: Role role = azg.getUserRole(user);
1335: if (role == null) {
1336: return false;
1337: }
1338: if (role.getId().equals(azg.getMaintainRole())) {
1339: return false;
1340: }
1341: }
1342: } catch (IdUnusedException e) {
1343: return false;
1344: } catch (GroupNotDefinedException e) {
1345: return false;
1346: }
1347:
1348: return true;
1349: }
1350:
1351: /**
1352: * @inheritDoc
1353: */
1354: public String getSiteSkin(String id) {
1355: String rv = null;
1356:
1357: // check the site cache
1358: if (m_siteCache != null) {
1359: try {
1360: // this gets the site from the cache, or reads the site / pages / tools and caches it
1361: Site s = getDefinedSite(id);
1362: String skin = adjustSkin(s.getSkin(), s.isPublished());
1363:
1364: return skin;
1365: } catch (IdUnusedException e) {
1366: }
1367:
1368: // if the site's not around, use the default
1369: return adjustSkin(null, true);
1370: }
1371:
1372: rv = m_storage.getSiteSkin(id);
1373:
1374: return rv;
1375: }
1376:
1377: /**
1378: * {@inheritDoc}
1379: */
1380: public List getSiteTypes() {
1381: return m_storage.getSiteTypes();
1382: }
1383:
1384: /**
1385: * @inheritDoc
1386: */
1387: public List getSites(SelectionType type, Object ofType,
1388: String criteria, Map propertyCriteria, SortType sort,
1389: PagingPosition page) {
1390: return m_storage.getSites(type, ofType, criteria,
1391: propertyCriteria, sort, page);
1392: }
1393:
1394: /**
1395: * @inheritDoc
1396: */
1397: public int countSites(SelectionType type, Object ofType,
1398: String criteria, Map propertyCriteria) {
1399: return m_storage.countSites(type, ofType, criteria,
1400: propertyCriteria);
1401: }
1402:
1403: /**
1404: * @inheritDoc
1405: */
1406: public void setSiteSecurity(String siteId, Set updateUsers,
1407: Set visitUnpUsers, Set visitUsers) {
1408: m_storage.setSiteSecurity(siteId, updateUsers, visitUnpUsers,
1409: visitUsers);
1410:
1411: // the site's azg may have just been updated, so enforce site group subset membership
1412: enforceGroupSubMembership(siteId);
1413: }
1414:
1415: /**
1416: * @inheritDoc
1417: */
1418: public void setUserSecurity(String userId, Set updateSites,
1419: Set visitUnpSites, Set visitSites) {
1420: m_storage.setUserSecurity(userId, updateSites, visitUnpSites,
1421: visitSites);
1422: }
1423:
1424: /**********************************************************************************************************************************************************************************************************************************************************
1425: * EntityProducer implementation
1426: *********************************************************************************************************************************************************************************************************************************************************/
1427:
1428: /**
1429: * {@inheritDoc}
1430: */
1431: public String getLabel() {
1432: return "site";
1433: }
1434:
1435: /**
1436: * {@inheritDoc}
1437: */
1438: public boolean willArchiveMerge() {
1439: return false;
1440: }
1441:
1442: /**
1443: * {@inheritDoc}
1444: */
1445: public HttpAccess getHttpAccess() {
1446: return new HttpAccess() {
1447: public void handleAccess(HttpServletRequest req,
1448: HttpServletResponse res, Reference ref,
1449: Collection copyrightAcceptedRefs)
1450: throws EntityPermissionException,
1451: EntityNotDefinedException,
1452: EntityAccessOverloadException,
1453: EntityCopyrightException {
1454: try {
1455: Site site = (Site) ref.getEntity();
1456: String skin = getSiteSkin(site.getId());
1457: String skinRepo = serverConfigurationService()
1458: .getString("skin.repo");
1459: String skinDefault = serverConfigurationService()
1460: .getString("skin.default");
1461:
1462: // make sure that it points to the default if there is no skin
1463: if (skin == null) {
1464: skin = skinDefault;
1465: }
1466:
1467: res.setContentType("text/html; charset=UTF-8");
1468: PrintWriter out = res.getWriter();
1469: out
1470: .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
1471: out
1472: .println("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
1473: out.println("<head>");
1474: out
1475: .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
1476: out
1477: .println("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />");
1478: out
1479: .println("<link href=\""
1480: + skinRepo
1481: + "/tool_base.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />");
1482: out
1483: .println("<link href=\""
1484: + skinRepo
1485: + "/"
1486: + skin
1487: + "/tool.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />");
1488: out.println("<title>");
1489: out.println(site.getTitle());
1490: out.println("</title>");
1491: out
1492: .println("</head><body><div class=\"portletBody\">");
1493: out.println("<br />");
1494:
1495: // get the description - if missing, use the site title
1496: String description = site.getDescription();
1497:
1498: if (description == null) {
1499: description = site.getTitle();
1500: }
1501:
1502: // make it safe for html
1503: description = Validator.escapeHtml(description);
1504: out.println(description);
1505: out.println("</div></body></html>");
1506: } catch (Throwable t) {
1507: throw new EntityNotDefinedException(ref
1508: .getReference());
1509: }
1510: }
1511: };
1512: }
1513:
1514: /**
1515: * {@inheritDoc}
1516: */
1517: public boolean parseEntityReference(String reference, Reference ref) {
1518: // for site access
1519: if (reference.startsWith(REFERENCE_ROOT)) {
1520: String id = null;
1521: String container = null;
1522: String subType = SITE_SUBTYPE;
1523:
1524: // we will get null, service, siteId, page | group | tool, page/group/tool id
1525: String[] parts = StringUtil.split(reference,
1526: Entity.SEPARATOR);
1527:
1528: if (parts.length > 2) {
1529: id = parts[2];
1530: container = id;
1531:
1532: if (parts.length > 4) {
1533: subType = parts[3];
1534: id = parts[4];
1535: }
1536: }
1537:
1538: ref.set(APPLICATION_ID, subType, id, container, null);
1539:
1540: return true;
1541: }
1542:
1543: return false;
1544: }
1545:
1546: /**
1547: * {@inheritDoc}
1548: */
1549: public String getEntityDescription(Reference ref) {
1550: // double check that it's mine
1551: if (APPLICATION_ID != ref.getType())
1552: return null;
1553:
1554: String rv = "Site: " + ref.getReference();
1555:
1556: try {
1557: Site site = getSite(ref.getId());
1558: rv = "Site: "
1559: + site.getTitle()
1560: + " ("
1561: + site.getId()
1562: + ")"
1563: + " Created: "
1564: + site.getCreatedTime().toStringLocalFull()
1565: + " by "
1566: + site.getCreatedBy().getDisplayName()
1567: + " ("
1568: + site.getCreatedBy().getDisplayId()
1569: + ") "
1570: + StringUtil.limit(
1571: (site.getDescription() == null ? "" : site
1572: .getDescription()), 30);
1573: } catch (IdUnusedException e) {
1574: } catch (NullPointerException e) {
1575: }
1576:
1577: return rv;
1578: }
1579:
1580: /**
1581: * {@inheritDoc}
1582: */
1583: public ResourceProperties getEntityResourceProperties(Reference ref) {
1584: return null;
1585: }
1586:
1587: /**
1588: * {@inheritDoc}
1589: */
1590: public Entity getEntity(Reference ref) {
1591: // double check that it's mine
1592: if (APPLICATION_ID != ref.getType())
1593: return null;
1594:
1595: Entity rv = null;
1596:
1597: try {
1598: rv = getSite(ref.getId());
1599: } catch (IdUnusedException e) {
1600: M_log.warn("getEntity(): " + e);
1601: } catch (NullPointerException e) {
1602: M_log.warn("getEntity(): " + e);
1603: }
1604:
1605: return rv;
1606: }
1607:
1608: /**
1609: * {@inheritDoc}
1610: */
1611: public Collection getEntityAuthzGroups(Reference ref, String userId) {
1612: // double check that it's mine
1613: if (APPLICATION_ID != ref.getType())
1614: return null;
1615:
1616: Collection rv = new Vector();
1617:
1618: try {
1619: // first, use the reference as an authzGroup (site, group, page or tool)
1620: rv.add(ref.getReference());
1621:
1622: // do NOT use the site if the reference is a group or other part
1623: // // if this is a sub-type, add the site's reference - container is site id
1624: // if (!SITE_SUBTYPE.equals(ref.getSubType()))
1625: // {
1626: // rv.add(siteReference(ref.getContainer()));
1627: // }
1628:
1629: // add the current user's realm
1630: ref.addUserAuthzGroup(rv, userId);
1631:
1632: // site helper
1633: rv.add("!site.helper");
1634: } catch (Throwable e) {
1635: M_log.warn("getEntityRealms(): " + e);
1636: }
1637:
1638: return rv;
1639: }
1640:
1641: /**
1642: * {@inheritDoc}
1643: */
1644: public String getEntityUrl(Reference ref) {
1645: return null;
1646: }
1647:
1648: /**
1649: * {@inheritDoc}
1650: */
1651: public String archive(String siteId, Document doc, Stack stack,
1652: String archivePath, List attachments) {
1653: return "";
1654: }
1655:
1656: /**
1657: * {@inheritDoc}
1658: */
1659: public String merge(String siteId, Element root,
1660: String archivePath, String fromSiteId, Map attachmentNames,
1661: Map userIdTrans, Set userListAllowImport) {
1662: return "";
1663: }
1664:
1665: /**********************************************************************************************************************************************************************************************************************************************************
1666: *********************************************************************************************************************************************************************************************************************************************************/
1667:
1668: /**
1669: * Sync up with all other services for a site that exists.
1670: *
1671: * @param site
1672: * The site.
1673: */
1674: protected void enableRelated(BaseSite site, boolean isNew) {
1675: // skip if special
1676: if (isSpecialSite(site.getId())) {
1677: return;
1678: }
1679:
1680: // take care of our AuthzGroups
1681: enableAzgSecurityAdvisor();
1682: enableAzg(site);
1683: securityService().clearAdvisors();
1684:
1685: // offer to all EntityProducers that are ContexObservers
1686: for (Iterator i = entityManager().getEntityProducers()
1687: .iterator(); i.hasNext();) {
1688: EntityProducer ep = (EntityProducer) i.next();
1689: if (ep instanceof ContextObserver) {
1690: try {
1691: ContextObserver co = (ContextObserver) ep;
1692:
1693: // is this CO's tools in the site?
1694: boolean toolPlacement = !site.getTools(
1695: co.myToolIds()).isEmpty();
1696:
1697: if (isNew) {
1698: co.contextCreated(site.getId(), toolPlacement);
1699: }
1700:
1701: else {
1702: co.contextUpdated(site.getId(), toolPlacement);
1703: }
1704: } catch (Throwable t) {
1705: M_log
1706: .warn(
1707: "Error encountered while notifying ContextObserver of Site Change",
1708: t);
1709: }
1710: }
1711: }
1712: }
1713:
1714: /**
1715: * Sync up with all other services for a site that is going away.
1716: *
1717: * @param site
1718: * The site.
1719: */
1720: protected void disableRelated(Site site) {
1721: // skip if special
1722: if (isSpecialSite(site.getId())) {
1723: return;
1724: }
1725:
1726: // send to all EntityProducers that are ContextObservers
1727: for (Iterator i = entityManager().getEntityProducers()
1728: .iterator(); i.hasNext();) {
1729: EntityProducer ep = (EntityProducer) i.next();
1730: if (ep instanceof ContextObserver) {
1731: try {
1732: ContextObserver co = (ContextObserver) ep;
1733:
1734: // is this CO's tools in the site?
1735: boolean toolPlacement = !site.getTools(
1736: co.myToolIds()).isEmpty();
1737: co.contextDeleted(site.getId(), toolPlacement);
1738: } catch (Throwable t) {
1739: M_log
1740: .warn(
1741: "Error encountered while notifying ContextObserver of Site Change",
1742: t);
1743: }
1744: }
1745: }
1746:
1747: // disable the azgs last, so permissions were in place for the above
1748: enableAzgSecurityAdvisor();
1749: disableAzg(site);
1750: securityService().clearAdvisors();
1751: }
1752:
1753: /**
1754: * Enable the site and site group AuthzGroups.
1755: *
1756: * @param site
1757: * The site.
1758: */
1759: protected void enableAzg(BaseSite site) {
1760: // figure the site authorization group template
1761: String siteAzgTemplate = siteAzgTemplate(site);
1762:
1763: // try the site created-by user for the maintain role in the site
1764: String userId = site.getCreatedBy().getId();
1765: if (userId != null) {
1766: // make sure it's valid
1767: try {
1768: userDirectoryService().getUser(userId);
1769: } catch (UserNotDefinedException e1) {
1770: userId = null;
1771: }
1772: }
1773:
1774: // use the current user if needed
1775: if (userId == null) {
1776: User user = userDirectoryService().getCurrentUser();
1777: userId = user.getId();
1778: }
1779:
1780: enableAuthorizationGroup(site.getReference(), siteAzgTemplate,
1781: userId, "!site.template");
1782:
1783: // figure the group authorization group template
1784: String groupAzgTemplate = groupAzgTemplate(site);
1785:
1786: // enable a realm for each group: use the same template as for the site, but don't assign a user maintain in the group's azg
1787: for (Iterator iGroups = site.getGroups().iterator(); iGroups
1788: .hasNext();) {
1789: Group group = (Group) iGroups.next();
1790: enableAuthorizationGroup(group.getReference(),
1791: groupAzgTemplate, null, "!group.template");
1792: }
1793:
1794: // disable the authorization groups for any groups deleted in this edit
1795: for (Iterator iGroups = site.m_deletedGroups.iterator(); iGroups
1796: .hasNext();) {
1797: Group group = (Group) iGroups.next();
1798: disableAuthorizationGroup(group.getReference());
1799: }
1800: }
1801:
1802: /**
1803: * Disable the site and site group azgs for a site that's being deleted.
1804: *
1805: * @param site
1806: * The site.
1807: */
1808: protected void disableAzg(Site site) {
1809: // disable a realm for each group
1810: for (Iterator iGroups = site.getGroups().iterator(); iGroups
1811: .hasNext();) {
1812: Group group = (Group) iGroups.next();
1813: disableAuthorizationGroup(group.getReference());
1814: }
1815:
1816: // disable realm last, to keep those permissions around
1817: disableAuthorizationGroup(site.getReference());
1818: }
1819:
1820: /**
1821: * Figure the site's authorization group template, based on type and if it's a user site.
1822: *
1823: * @param site
1824: * The site to figure the realm for.
1825: * @return the site's authorization group template, based on type and if it's a user site.
1826: */
1827: protected String siteAzgTemplate(Site site) {
1828: String azgTemplate = null;
1829: if (isUserSite(site.getId())) {
1830: azgTemplate = "!site.user";
1831: } else {
1832: // use the type's template, if defined
1833: azgTemplate = "!site.template";
1834: String type = site.getType();
1835: if (type != null) {
1836: azgTemplate = azgTemplate + "." + type;
1837: }
1838: }
1839:
1840: return azgTemplate;
1841: }
1842:
1843: /**
1844: * Figure the authorization group template for a group of this site, based on type and if it's a user site.
1845: *
1846: * @param site
1847: * The site to figure the authorization group templates for.
1848: * @return the authorization group template for a group of this site, based on type and if it's a user site.
1849: */
1850: protected String groupAzgTemplate(Site site) {
1851: String azgTemplate = null;
1852: if (isUserSite(site.getId())) {
1853: azgTemplate = "!group.user";
1854: } else {
1855: // use the type's template, if defined
1856: azgTemplate = "!group.template";
1857: String type = site.getType();
1858: if (type != null) {
1859: azgTemplate = azgTemplate + "." + type;
1860: }
1861: }
1862:
1863: return azgTemplate;
1864: }
1865:
1866: /**
1867: * Setup the realm for an active site.
1868: *
1869: * @param ref
1870: * The reference for which the realm will be created (site, user).
1871: * @param templateId
1872: * The realm id of a template to use for the new realm.
1873: * @param userId
1874: * The user to get maintain in this realm.
1875: */
1876: protected void enableAuthorizationGroup(String ref,
1877: String templateId, String userId, String fallbackTemplate) {
1878: // see if it exists already
1879: try {
1880: AuthzGroup realm = authzGroupService().getAuthzGroup(ref);
1881: } catch (GroupNotDefinedException un) {
1882: // see if there's a new site AuthzGroup template
1883: AuthzGroup template = null;
1884: try {
1885: template = authzGroupService()
1886: .getAuthzGroup(templateId);
1887: } catch (Exception e) {
1888: try {
1889: // if the template is not defined, try the fall back template
1890: template = authzGroupService().getAuthzGroup(
1891: fallbackTemplate);
1892: } catch (Exception ee) {
1893: }
1894: }
1895:
1896: // add the realm
1897: try {
1898: AuthzGroup realm = null;
1899:
1900: if (template == null) {
1901: realm = authzGroupService().addAuthzGroup(ref);
1902: } else {
1903: realm = authzGroupService().addAuthzGroup(ref,
1904: template, userId);
1905: }
1906: } catch (Exception e) {
1907: M_log.warn(".enableRealm: AuthzGroup exception: " + e);
1908: }
1909: }
1910: }
1911:
1912: /**
1913: * Remove a site's realm.
1914: *
1915: * @param site
1916: * The site.
1917: */
1918: protected void disableAuthorizationGroup(String ref) {
1919: try {
1920: authzGroupService().removeAuthzGroup(ref);
1921: } catch (Exception e) {
1922: M_log.warn(".removeSite: AuthzGroup exception: " + e);
1923: }
1924: }
1925:
1926: /**********************************************************************************************************************************************************************************************************************************************************
1927: * Storage
1928: *********************************************************************************************************************************************************************************************************************************************************/
1929:
1930: protected interface Storage {
1931: /**
1932: * Open and be ready to read / write.
1933: */
1934: public void open();
1935:
1936: /**
1937: * Close.
1938: */
1939: public void close();
1940:
1941: /**
1942: * Does the site with this id exist?
1943: *
1944: * @param id
1945: * The site id.
1946: * @return true if the site with this id exists, false if not.
1947: */
1948: public boolean check(String id);
1949:
1950: /**
1951: * Get the site with this id, or null if not found.
1952: *
1953: * @param id
1954: * The site id.
1955: * @return The site with this id, or null if not found.
1956: */
1957: public Site get(String id);
1958:
1959: /**
1960: * Get all sites.
1961: *
1962: * @return The list of all sites.
1963: */
1964: public List getAll();
1965:
1966: /**
1967: * Add a new site with this id.
1968: *
1969: * @param id
1970: * The site id.
1971: * @return The site with this id, or null if in use.
1972: */
1973: public Site put(String id);
1974:
1975: /**
1976: * Save the changes.
1977: *
1978: * @param site
1979: * The site to commit.
1980: */
1981: public void save(Site site);
1982:
1983: /**
1984: * Save the changes to the two info fields (description and infoUrl) only.
1985: *
1986: * @param siteId
1987: * The site to commit.
1988: * @param description
1989: * The new site description.
1990: * @param infoUrl
1991: * The new site infoUrl.
1992: */
1993: public void saveInfo(String siteId, String description,
1994: String infoUrl);
1995:
1996: /**
1997: * Remove this site.
1998: *
1999: * @param user
2000: * The site to remove.
2001: */
2002: public void remove(Site site);
2003:
2004: /**
2005: * Count all the sites.
2006: *
2007: * @return The count of all sites.
2008: */
2009: public int count();
2010:
2011: /**
2012: * Access a unique list of String site types for any site type defined for any site, sorted by type.
2013: *
2014: * @return A list (String) of all used site types.
2015: */
2016: public List getSiteTypes();
2017:
2018: /**
2019: * Access a list of Site objets that meet specified criteria.
2020: *
2021: * @param type
2022: * The SelectionType specifying what sort of selection is intended.
2023: * @param ofType
2024: * Site type criteria: null for any type; a String to match a single type; A String[], List or Set to match any type in the collection.
2025: * @param criteria
2026: * Additional selection criteria: sits returned will match this string somewhere in their id, title, description, or skin.
2027: * @param propertyCriteria
2028: * Additional selection criteria: sites returned will have a property named to match each key in the map, whose values match (somewhere in their value) the value in the map (may be null or empty).
2029: * @param sort
2030: * A SortType indicating the desired sort. For no sort, set to SortType.NONE.
2031: * @param page
2032: * The PagePosition subset of items to return.
2033: * @return The List (Site) of Site objets that meet specified criteria.
2034: */
2035: public List getSites(SelectionType type, Object ofType,
2036: String criteria, Map propertyCriteria, SortType sort,
2037: PagingPosition page);
2038:
2039: /**
2040: * Count the Site objets that meet specified criteria.
2041: *
2042: * @param type
2043: * The SelectionType specifying what sort of selection is intended.
2044: * @param ofType
2045: * Site type criteria: null for any type; a String to match a single type; A String[], List or Set to match any type in the collection.
2046: * @param criteria
2047: * Additional selection criteria: sits returned will match this string somewhere in their id, title, description, or skin.
2048: * @param propertyCriteria
2049: * Additional selection criteria: sites returned will have a property named to match each key in the map, whose values match (somewhere in their value) the value in the map (may be null or empty).
2050: * @return The count of Site objets that meet specified criteria.
2051: */
2052: public int countSites(SelectionType type, Object ofType,
2053: String criteria, Map propertyCriteria);
2054:
2055: /**
2056: * Access the ToolConfiguration that has this id, if one is defined, else return null. The tool may be on any SitePage in any site.
2057: *
2058: * @param id
2059: * The id of the tool.
2060: * @return The ToolConfiguration that has this id, if one is defined, else return null.
2061: */
2062: public ToolConfiguration findTool(String id);
2063:
2064: /**
2065: * Access the Site id for the tool with this id.
2066: *
2067: * @param id
2068: * The id of the tool.
2069: * @return The Site id for the tool with this id, if the tool is found, else null.
2070: */
2071: public String findToolSiteId(String id);
2072:
2073: /**
2074: * Access the Page that has this id, if one is defined, else return null. The page may be on any Site.
2075: *
2076: * @param id
2077: * The id of the page.
2078: * @return The SitePage that has this id, if one is defined, else return null.
2079: */
2080: public SitePage findPage(String id);
2081:
2082: /**
2083: * Access the Site id for the page with this id.
2084: *
2085: * @param id
2086: * The id of the page.
2087: * @return The Site id for the page with this id, if the page is found, else null.
2088: */
2089: public String findPageSiteId(String id);
2090:
2091: /**
2092: * Read site properties from storage into the site's properties.
2093: *
2094: * @param site
2095: * The site for which properties are desired.
2096: */
2097: public void readSiteProperties(Site site,
2098: ResourcePropertiesEdit props);
2099:
2100: /**
2101: * Read site properties and all page and tool properties for the site from storage.
2102: *
2103: * @param site
2104: * The site for which properties are desired.
2105: */
2106: public void readAllSiteProperties(Site site);
2107:
2108: /**
2109: * Read page properties from storage into the page's properties.
2110: *
2111: * @param page
2112: * The page for which properties are desired.
2113: */
2114: public void readPageProperties(SitePage page,
2115: ResourcePropertiesEdit props);
2116:
2117: /**
2118: * Read tool configuration from storage into the tool's configuration properties.
2119: *
2120: * @param tool
2121: * The tool for which properties are desired.
2122: */
2123: public void readToolProperties(ToolConfiguration tool,
2124: Properties props);
2125:
2126: /**
2127: * Read group properties from storage into the group's properties.
2128: *
2129: * @param groupId
2130: * The groupId for which properties are desired.
2131: */
2132: public void readGroupProperties(Group groupId, Properties props);
2133:
2134: /**
2135: * Read site pages from storage into the site's pages.
2136: *
2137: * @param site
2138: * The site for which pages are desired.
2139: */
2140: public void readSitePages(Site site, ResourceVector pages);
2141:
2142: /**
2143: * Read site page tools from storage into the page's tools.
2144: *
2145: * @param page
2146: * The page for which tools are desired.
2147: */
2148: public void readPageTools(SitePage page, ResourceVector tools);
2149:
2150: /**
2151: * Read tools for all pages from storage into the site's page's tools.
2152: *
2153: * @param site
2154: * The site for which tools are desired.
2155: */
2156: public void readSiteTools(Site site);
2157:
2158: /**
2159: * Return the skin for this site
2160: *
2161: * @param siteId
2162: * The site id.
2163: * @return the skin for this site.
2164: */
2165: public String getSiteSkin(String siteId);
2166:
2167: /**
2168: * Establish the internal security for this site. Previous security settings are replaced for this site. Assigning a user with update implies the two reads; assigning a user with unp read implies the other read.
2169: *
2170: * @param siteId
2171: * The id of the site.
2172: * @param updateUsers
2173: * The set of String User Ids who have update access.
2174: * @param visitUnpUsers
2175: * The set of String User Ids who have visit unpublished access.
2176: * @param visitUsers
2177: * The set of String User Ids who have visit access.
2178: */
2179: public void setSiteSecurity(String siteId, Set updateUsers,
2180: Set visitUnpUsers, Set visitUsers);
2181:
2182: /**
2183: * Establish the internal security for user for all sites. Previous security settings are replaced for this user. Assigning a user with update implies the two reads; assigning a user with unp read implies the other read.
2184: *
2185: * @param userId
2186: * The id of the user.
2187: * @param updateSites
2188: * The set of String site ids where the user has update access.
2189: * @param visitUnpSites
2190: * The set of String site ids where the user has visit unpublished access.
2191: * @param visitSites
2192: * The set of String site ids where the user has visit access.
2193: */
2194: public void setUserSecurity(String userId, Set updateSites,
2195: Set visitUnpSites, Set visitSites);
2196:
2197: /**
2198: * Write an updated tool configuration to the database.
2199: *
2200: * @param tool
2201: * TooConfiguration to commit.
2202: */
2203: public void saveToolConfig(ToolConfiguration tool);
2204:
2205: /**
2206: * Access the Site id for the group with this id.
2207: *
2208: * @param id
2209: * The id of the group.
2210: * @return The Site id for the group with this id, if the group is found, else null.
2211: */
2212: public String findGroupSiteId(String id);
2213:
2214: /**
2215: * Read site pages from storage into the site's pages.
2216: *
2217: * @param site
2218: * The site for which groups are desired.
2219: * @param groups
2220: * The Collection to fill in.
2221: */
2222: public void readSiteGroups(Site site, Collection groups);
2223: }
2224:
2225: /**********************************************************************************************************************************************************************************************************************************************************
2226: * StorageUser implementation
2227: *********************************************************************************************************************************************************************************************************************************************************/
2228:
2229: /**
2230: * Construct a new continer given just an id.
2231: *
2232: * @param id
2233: * The id for the new object.
2234: * @return The new containe Resource.
2235: */
2236: public Entity newContainer(String ref) {
2237: return null;
2238: }
2239:
2240: /**
2241: * Construct a new container resource, from an XML element.
2242: *
2243: * @param element
2244: * The XML.
2245: * @return The new container resource.
2246: */
2247: public Entity newContainer(Element element) {
2248: return null;
2249: }
2250:
2251: /**
2252: * Construct a new container resource, as a copy of another
2253: *
2254: * @param other
2255: * The other contianer to copy.
2256: * @return The new container resource.
2257: */
2258: public Entity newContainer(Entity other) {
2259: return null;
2260: }
2261:
2262: /**
2263: * Construct a new rsource given just an id.
2264: *
2265: * @param container
2266: * The Resource that is the container for the new resource (may be null).
2267: * @param id
2268: * The id for the new object.
2269: * @param others
2270: * (options) array of objects to load into the Resource's fields.
2271: * @return The new resource.
2272: */
2273: public Entity newResource(Entity container, String id,
2274: Object[] others) {
2275: return new BaseSite(id);
2276: }
2277:
2278: /**
2279: * Construct a new resource, from an XML element.
2280: *
2281: * @param container
2282: * The Resource that is the container for the new resource (may be null).
2283: * @param element
2284: * The XML.
2285: * @return The new resource from the XML.
2286: */
2287: public Entity newResource(Entity container, Element element) {
2288: return null;
2289: }
2290:
2291: /**
2292: * Construct a new resource from another resource of the same type.
2293: *
2294: * @param container
2295: * The Resource that is the container for the new resource (may be null).
2296: * @param other
2297: * The other resource.
2298: * @return The new resource as a copy of the other.
2299: */
2300: public Entity newResource(Entity container, Entity other) {
2301: return new BaseSite((Site) other, true);
2302: }
2303:
2304: /**
2305: * Construct a new continer given just an id.
2306: *
2307: * @param id
2308: * The id for the new object.
2309: * @return The new containe Resource.
2310: */
2311: public Edit newContainerEdit(String ref) {
2312: return null;
2313: }
2314:
2315: /**
2316: * Construct a new container resource, from an XML element.
2317: *
2318: * @param element
2319: * The XML.
2320: * @return The new container resource.
2321: */
2322: public Edit newContainerEdit(Element element) {
2323: return null;
2324: }
2325:
2326: /**
2327: * Construct a new container resource, as a copy of another
2328: *
2329: * @param other
2330: * The other contianer to copy.
2331: * @return The new container resource.
2332: */
2333: public Edit newContainerEdit(Entity other) {
2334: return null;
2335: }
2336:
2337: /**
2338: * Construct a new rsource given just an id.
2339: *
2340: * @param container
2341: * The Resource that is the container for the new resource (may be null).
2342: * @param id
2343: * The id for the new object.
2344: * @param others
2345: * (options) array of objects to load into the Resource's fields.
2346: * @return The new resource.
2347: */
2348: public Edit newResourceEdit(Entity container, String id,
2349: Object[] others) {
2350: BaseSite e = new BaseSite(id);
2351: e.activate();
2352: return e;
2353: }
2354:
2355: /**
2356: * Construct a new resource, from an XML element.
2357: *
2358: * @param container
2359: * The Resource that is the container for the new resource (may be null).
2360: * @param element
2361: * The XML.
2362: * @return The new resource from the XML.
2363: */
2364: public Edit newResourceEdit(Entity container, Element element) {
2365: return null;
2366: }
2367:
2368: /**
2369: * Construct a new resource from another resource of the same type.
2370: *
2371: * @param container
2372: * The Resource that is the container for the new resource (may be null).
2373: * @param other
2374: * The other resource.
2375: * @return The new resource as a copy of the other.
2376: */
2377: public Edit newResourceEdit(Entity container, Entity other) {
2378: BaseSite e = new BaseSite((Site) other);
2379: e.activate();
2380: return e;
2381: }
2382:
2383: /**
2384: * Collect the fields that need to be stored outside the XML (for the resource).
2385: *
2386: * @return An array of field values to store in the record outside the XML (for the resource).
2387: */
2388: public Object[] storageFields(Entity r) {
2389: return null;
2390: }
2391:
2392: /**
2393: * Check if this resource is in draft mode.
2394: *
2395: * @param r
2396: * The resource.
2397: * @return true if the resource is in draft mode, false if not.
2398: */
2399: public boolean isDraft(Entity r) {
2400: return false;
2401: }
2402:
2403: /**
2404: * Access the resource owner user id.
2405: *
2406: * @param r
2407: * The resource.
2408: * @return The resource owner user id.
2409: */
2410: public String getOwnerId(Entity r) {
2411: return null;
2412: }
2413:
2414: /**
2415: * Access the resource date.
2416: *
2417: * @param r
2418: * The resource.
2419: * @return The resource date.
2420: */
2421: public Time getDate(Entity r) {
2422: return null;
2423: }
2424:
2425: /**
2426: * Adjust a skin value to be just a (folder) name, with no extension, and if missing, be null.
2427: *
2428: * @param skin
2429: * The skin value to adjust.
2430: * @return A defaulted and adjusted skin value.
2431: */
2432: protected String adjustSkin(String skin, boolean published) {
2433: // return the skin as just a name, no ".css", and not dependent on the published status, or a null if not defined
2434: if (skin == null)
2435: return null;
2436:
2437: if (!skin.endsWith(".css"))
2438: return skin;
2439:
2440: return skin.substring(0, skin.lastIndexOf(".css"));
2441: }
2442:
2443: /**
2444: * @inheritDoc
2445: */
2446: public String merge(String siteId, Element el, String creatorId) {
2447: StringBuffer msg = new StringBuffer();
2448:
2449: try {
2450: // if the target site already exists, don't change the site attributes
2451: Site s = getSite(siteId);
2452: } catch (IdUnusedException e) {
2453: try {
2454: // reserve a site with this id from the info store - if it's in use, this will return null
2455: // check security (throws if not permitted)
2456: // TODO: why security on add_user_site? -ggolden
2457: unlock(SECURE_ADD_USER_SITE, siteReference(siteId));
2458:
2459: // reserve a site with this id from the info store - if it's in use, this will return null
2460: BaseSite site = (BaseSite) m_storage.put(siteId);
2461: if (site == null) {
2462: msg.append(this + "cannot find site: " + siteId);
2463: }
2464:
2465: site.setEvent(SECURE_ADD_SITE);
2466:
2467: if (creatorId != null) {
2468: el.setAttribute("created-id", creatorId);
2469: }
2470:
2471: // assign source site's attributes to the target site
2472: ((BaseSite) site).set(new BaseSite(el), false);
2473:
2474: try {
2475: save(site);
2476: } catch (Throwable t) {
2477: M_log.warn(".merge: " + t);
2478: }
2479: } catch (PermissionException ignore) {
2480: }
2481: }
2482:
2483: return msg.toString();
2484: }
2485:
2486: /**
2487: * @inheritDoc
2488: */
2489: public Group findGroup(String refOrId) {
2490: Group rv = null;
2491:
2492: // parse the reference or id
2493: Reference ref = entityManager().newReference(refOrId);
2494:
2495: // for ref, get the site from the cache, or cache it and get the group from the site
2496: if (APPLICATION_ID.equals(ref.getType())) {
2497: try {
2498: // here we return the group from the site, so the group's containing site is really the site that contains it.
2499: Site site = getDefinedSite(ref.getContainer());
2500: rv = site.getGroup(ref.getId());
2501: }
2502: // we can ignore a site not found exception, just returning a null Group
2503: catch (IdUnusedException e) {
2504: }
2505: }
2506:
2507: // for id, check the cache or get the site from storage, then get the group from the site
2508: else {
2509: // check the site cache
2510: if (m_siteCache != null) {
2511: // this lets us find the group from an alredy cached site directly, by group id
2512: Group group = m_siteCache.getGroup(refOrId);
2513: if (group != null) {
2514: // Here we need to make a copy of the site, and pull the group from there,
2515: // so that the group's containing site really contains the group we return.
2516: // The group we get from the siteCache is a group from the actual cached site, so it's containing site is the actual cached site.
2517:
2518: // get a copy of the site from the cache
2519: Site site = new BaseSite(group.getContainingSite(),
2520: true);
2521:
2522: // get the group from there
2523: rv = site.getGroup(refOrId);
2524: }
2525: }
2526:
2527: // if we don't have it yet, get the group's site, and the group from there
2528: if (rv == null) {
2529: String siteId = m_storage.findGroupSiteId(refOrId);
2530: if (siteId != null) {
2531: try {
2532: // read (and cache if enabled) the full site
2533: Site site = getDefinedSite(siteId);
2534:
2535: // here we return the group from the site, so the group's containing site is really the site that contains it.
2536: rv = site.getGroup(refOrId);
2537: }
2538: // we can ignore a site not found exception, just returning a null Group
2539: catch (IdUnusedException e) {
2540: }
2541: }
2542: }
2543: }
2544:
2545: return rv;
2546: }
2547:
2548: /**
2549: * Adjust any site groups for this site so that the group membership is a subset of the site's membership.
2550: *
2551: * @param siteId
2552: * The site to adjust.
2553: */
2554: protected void enforceGroupSubMembership(String siteId) {
2555: // just being paranoid, but lets make sure we don't get stuck in a loop here -ggolden
2556: if (threadLocalManager().get("enforceGroupSubMembership") != null) {
2557: M_log
2558: .warn(".enforceGroupSubMembership: recursion avoided!: "
2559: + siteId);
2560: return;
2561: }
2562: threadLocalManager().set("enforceGroupSubMembership", siteId);
2563:
2564: try {
2565: Site site = getDefinedSite(siteId);
2566: for (Iterator i = site.getGroups().iterator(); i.hasNext();) {
2567: Group group = (Group) i.next();
2568: group.keepIntersection(site);
2569: }
2570:
2571: // save any changed group azg
2572: enableAzgSecurityAdvisor();
2573: saveGroupAzgs(site);
2574: securityService().clearAdvisors();
2575: } catch (IdUnusedException e) {
2576: // site not found - will happen with site delete, no problem
2577: }
2578:
2579: threadLocalManager().set("enforceGroupSubMembership", null);
2580: }
2581:
2582: /**
2583: * @inheritDoc
2584: */
2585: public void addSiteAdvisor(SiteAdvisor siteAdvisor) {
2586: siteAdvisors.add(siteAdvisor);
2587: }
2588:
2589: /**
2590: * @inheritDoc
2591: */
2592: public List<SiteAdvisor> getSiteAdvisors() {
2593: return Collections.unmodifiableList(siteAdvisors);
2594: }
2595:
2596: /**
2597: * @inheritDoc
2598: */
2599: public boolean removeSiteAdvisor(SiteAdvisor siteAdvisor) {
2600: return siteAdvisors.remove(siteAdvisor);
2601: }
2602: }
|