001: /*
002: * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions
006: * are met:
007: *
008: * - Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.getc
010: *
011: * - Redistribution in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in
013: * the documentation and/or other materials provided with thesuffix
014: * distribution.
015: *
016: * Neither the name of Sun Microsystems, Inc. or the names of
017: * contributors may be used to endorse or promote products derived
018: * from this software without specific prior written permission.
019: *
020: * This software is provided "AS IS," without a warranty of any
021: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
022: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
023: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
024: * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
025: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
026: * DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
027: * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
028: * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
029: * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
030: * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE,
031: * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
032: *
033: * You acknowledge that Software is not designed, licensed or intended
034: * any nuclear facility.
035: */
036:
037: package com.sun.portal.community.impl;
038:
039: import java.util.Set;
040: import java.util.Map;
041: import java.util.Properties;
042: import java.util.List;
043: import java.util.ArrayList;
044: import java.util.logging.Logger;
045: import java.util.logging.Level;
046: import java.util.logging.LogRecord;
047:
048: import javax.servlet.http.HttpServletRequest;
049: import javax.servlet.http.HttpServletResponse;
050:
051: import com.iplanet.sso.SSOTokenManager;
052: import com.iplanet.sso.SSOToken;
053: import com.iplanet.sso.SSOException;
054:
055: import com.sun.portal.log.common.PortalLogger;
056:
057: import com.sun.portal.community.mc.CMCFactory;
058: import com.sun.portal.community.mc.CMCException;
059: import com.sun.portal.community.mc.CMCPrincipal;
060: import com.sun.portal.community.mc.CMCNode;
061: import com.sun.portal.community.mc.CMCNodeManager;
062: import com.sun.portal.community.mc.CMCNodeManager;
063: import com.sun.portal.community.mc.CMCUser;
064: import com.sun.portal.community.mc.CMCRolePrincipal;
065: import com.sun.portal.community.mc.ConfigTable;
066: import com.sun.portal.community.mc.ConfigTable.ConfigKey;
067: import com.sun.portal.community.mc.CMCExistsException;
068:
069: import com.sun.portal.desktop.context.AdminDPContext;
070: import com.sun.portal.desktop.context.ContextError;
071: import com.sun.portal.desktop.dp.DPRoot;
072: import com.sun.portal.desktop.dp.DPNode;
073: import com.sun.portal.desktop.dp.DPChannel;
074: import com.sun.portal.desktop.dp.DPContainerChannel;
075: import com.sun.portal.desktop.dp.DPError;
076: import com.sun.portal.desktop.dp.xml.XMLDPFactory;
077:
078: import com.sun.portal.community.CommunityManager;
079: import com.sun.portal.community.CommunityId;
080: import com.sun.portal.community.CommunityServiceException;
081: import com.sun.portal.community.CommunityException;
082: import com.sun.portal.community.CommunityFactory;
083:
084: import com.sun.portal.service.serviceregistry.ServiceRegistryFactory;
085: import com.sun.portal.service.serviceregistry.ServiceRegistry;
086: import com.sun.portal.service.serviceregistry.ServiceRegistryException;
087: import com.sun.portal.service.Service;
088: import com.sun.portal.service.ServiceException;
089: import com.sun.portal.service.ProvisionRequest;
090: import com.sun.portal.service.ProvisionResponse;
091: import com.sun.portal.service.MembershipRequest;
092: import com.sun.portal.service.MembershipResponse;
093: import com.sun.portal.service.ProvisionRoles;
094: import com.sun.portal.search.soif.*;
095: import com.sun.portal.search.demo.*;
096: import netscape.ldap.LDAPDN;
097:
098: import com.sun.portal.util.ResourceLoader;
099: import java.util.regex.Pattern;
100:
101: public class CommunityManagerImpl implements CommunityManager {
102: private static CMCFactory cmcFactory = null;
103: private static Properties configProperties = null;
104:
105: static {
106: try {
107: cmcFactory = CMCFactory.getInstance();
108: } catch (CMCException ce) {
109: throw new RuntimeException(
110: "failed to get CMC factory instance", ce);
111: }
112: }
113:
114: private HttpServletRequest _request = null;
115: private HttpServletResponse _response = null;
116: private SSOToken _ssoToken = null;
117: private String portalId = ResourceLoader.getInstance(
118: System.getProperties()).getPortalId();
119:
120: private static Logger logger = PortalLogger
121: .getLogger(CommunityManagerImpl.class);
122:
123: /**
124: * Initialize CommunityManager from a servlet environment where it's assumed
125: * that there is only one portal accessible in the JVM.
126: *
127: * @param request
128: * @param response
129: * @param ssoToken
130: * @throws com.sun.portal.community.mgmt.CommunityException
131: */
132: public CommunityManagerImpl(HttpServletRequest request,
133: HttpServletResponse response, SSOToken ssoToken)
134: throws CommunityException {
135: _request = request;
136: _response = response;
137: _ssoToken = ssoToken;
138: }
139:
140: public void createCommunity(CommunityId cid, String templateId,
141: String category, String description,
142: boolean isMembershipRestricted, boolean isSecure,
143: boolean isListed) throws CommunityServiceException,
144: CommunityException {
145:
146: String userId = null;
147: try {
148: userId = LDAPDN.normalize(_ssoToken.getPrincipal()
149: .getName().toLowerCase());
150: } catch (SSOException se) {
151: throw new CommunityException(
152: "CommunityManagerImpl.createCommunity(): failed to retrieve userID. ",
153: se);
154: }
155:
156: createCommunity(cid, userId, templateId, category, description,
157: isMembershipRestricted, isSecure, isListed);
158:
159: }
160:
161: /**
162: * Create a new community. Here are high-level tasks:
163: * 1. Initialize a new Membership Node
164: * 2. Retrieve template for each role
165: * 3. Walk down the template for each role and collect (absolute) channel names
166: * - this would be the union set of channel names gathered from the templates.
167: * 4. Create merged dpRoot for each role: (role_template_DP + global_DP)
168: * 5. Provision service corresponding to each channel in the set
169: * 6. Set community DP for each role
170: * 7. Add a new classification into search DB
171: * 8. Creator of the community joins the community
172: *
173: * @param name name of the community
174: * @param description description of the community
175: * @param category category where the community is to be inserted
176: * @param templateId ID of the template to represent the layout of the community
177: */
178:
179: public void createCommunity(CommunityId cid, String ownerId,
180: String templateId, String category, String description,
181: boolean isMembershipRestricted, boolean isSecure,
182: boolean isListed) throws CommunityServiceException,
183: CommunityException {
184:
185: //
186: // sanity check
187: //
188: if (cid == null) {
189: throw new CommunityException(
190: "null community ID is not allowed");
191: }
192:
193: //
194: // create community node
195: //
196: CMCNode cNode = createCommunityNode(cid);
197:
198: try {
199: cNode.setCategory(category);
200:
201: cNode.setDescription(description);
202:
203: cNode.setMembershipRestricted(isMembershipRestricted);
204:
205: cNode.setSecure(isSecure);
206:
207: cNode.setListed(isListed);
208: } catch (CMCException ex) {
209: throw new CommunityException(ex);
210: }
211:
212: //
213: // provision services
214: //
215: CommunityImpl community = (CommunityImpl) CommunityFactory
216: .getInstance().getCommunity(_request, _response,
217: _ssoToken, cid);
218: CommunityServiceException serviceError = null;
219:
220: TokenMapping tm = new TokenMapping();
221:
222: tm.setPortalId(getPortalId());
223: tm.setCommunityId(cid);
224: tm.setCommunitySearchUrl(getSearchUrl());
225: tm.setCommunityDpBasePriority(getDpBasePriority());
226: tm.setCommunityDescription(description);
227: tm.setCommunityContentsSearchDb(getContentsSearchDb(cid));
228: tm.setCommunityDiscussionsSearchDb(getDiscussionsSearchDb(cid));
229: tm.setCommunitySearchDbPrefix(getSearchDbPrefix());
230:
231: Map tokenMapping = tm.get();
232:
233: try {
234: community.provisionServices(templateId, tokenMapping);
235: } catch (CommunityServiceException cse) {
236: // save the error
237: serviceError = cse;
238: }
239:
240: //
241: // handle membership
242: //
243: String owneruid = LDAPDN.normalize(ownerId.toLowerCase());
244: try {
245: community.addOwner(owneruid);
246: } catch (CommunityServiceException cse) {
247: // add user service errors
248: if (serviceError == null) {
249: serviceError = cse;
250: } else {
251: serviceError.addEntries(cse.getEntries());
252: }
253: }
254:
255: try {
256: community.addMember(owneruid);
257: } catch (CommunityServiceException cse) {
258: // add user service errors
259: if (serviceError == null) {
260: serviceError = cse;
261: } else {
262: serviceError.addEntries(cse.getEntries());
263: }
264: }
265:
266: String ownerFullName = owneruid;
267: try {
268: DSAMEUserInfo userInfo = new DSAMEUserInfo(owneruid);
269: ownerFullName = userInfo
270: .getUserStringAttribute(DSAMEUserInfo.ATTTR_FULLNAME);
271: } catch (Exception e) {
272: //ignore the exception
273: }
274:
275: if (isListed) {
276: community.addSearchIndex(category, description,
277: ownerFullName);
278: }
279:
280: //
281: // throw CommunityServiceException if any
282: //
283: if (serviceError != null) {
284: throw serviceError;
285: }
286: }
287:
288: /**
289: * Undo whatever createCommunity() has done.
290: *
291: * @param CommunityId ID of the community to remove
292: */
293: public void destroyCommunity(CommunityId cid)
294: throws CommunityServiceException, CommunityException {
295: destroyCommunity(cid, false);
296: }
297:
298: /**
299: * Undo whatever createCommunity() has done.
300: *
301: * @param CommunityId ID of the community to remove
302: * @param cont flag indicating whether remove process should continue on when any of its subprocess fails
303: */
304: public void destroyCommunity(CommunityId cid, boolean cont)
305: throws CommunityServiceException, CommunityException {
306: //
307: // sanity check
308: //
309: if (cid == null) {
310: throw new CommunityException(
311: "null community ID is not allowed");
312: }
313:
314: //
315: // unprovision services
316: //
317: CommunityImpl c = (CommunityImpl) CommunityFactory
318: .getInstance().getCommunity(_request, _response,
319: _ssoToken, cid);
320: CommunityServiceException serviceError = null;
321: try {
322: c.unprovisionServices();
323: } catch (CommunityServiceException cse) {
324: // save the error
325: serviceError = cse;
326: }
327:
328: //
329: // remove community from search DB
330: //
331: try {
332: c.removeSearchIndexForCommunity();
333: c.removeSearchIndexForCommunityContent();
334: } catch (Exception e) {
335: if (cont) {
336: // continue on
337: logRecord(logger, Level.INFO, "PSCPM_CSPCI00000", e,
338: new Object[] { cid, getSearchDb(),
339: getSearchUrl() });
340: } else {
341: // rethrow the exception
342: throw new CommunityException(e);
343: }
344: }
345:
346: //
347: // remove community node
348: //
349: try {
350: removeCommunityNode(getCommunityNode(cid));
351: } catch (Exception e) {
352: if (cont) {
353: // continue on
354: logRecord(logger, Level.INFO, "PSCPM_CSPCI00001", e,
355: cid);
356: } else {
357: // rethrow the exception
358: throw new CommunityException(e);
359: }
360: }
361:
362: //
363: // throw CommunityServiceException if any
364: //
365: if (serviceError != null) {
366: throw serviceError;
367: }
368: }
369:
370: private CMCNode getCommunityNode(CommunityId cid)
371: throws CommunityException {
372: CMCNode cmcNode;
373: try {
374: cmcNode = cmcFactory.getCMCNode(TypeConverter
375: .communityIdToPrincipal(cid));
376: } catch (CMCException cmce) {
377: throw new CommunityException(cmce);
378: }
379: return cmcNode;
380: }
381:
382: private CMCNodeManager getCommunityNodeManager()
383: throws CommunityException {
384: CMCNodeManager cmcnm;
385: try {
386: cmcnm = cmcFactory.getCMCNodeManager();
387: } catch (CMCException cmce) {
388: throw new CommunityException(cmce);
389: }
390: return cmcnm;
391: }
392:
393: /**
394: * Does the community exist?
395: *
396: * @param communityName Name of the community
397: */
398: public boolean existsCommunity(CommunityId cid)
399: throws CommunityException {
400:
401: // make community name case-insensitive
402: Pattern p = Pattern.compile("(?i)" + cid.getName());
403: Set matches = null;
404: try {
405: matches = getCommunityNodeManager().match(p, true);
406: } catch (CMCException ce) {
407: throw new CommunityException(ce);
408: }
409:
410: return matches.size() > 0;
411: }
412:
413: /**
414: * Create a new community node if it's supported. An exception is thrown
415: * if it's not a supported operation.
416: *
417: * @param name name of the community to be created
418: * @throws com.sun.portal.community.mgmt.CommunityException
419: * @return a newly created <code>CommunityNode</code>
420: */
421: protected CMCNode createCommunityNode(CommunityId cid)
422: throws CommunityException {
423: CMCPrincipal cPrincipal = TypeConverter
424: .communityIdToPrincipal(cid);
425: CMCNode cmcNode;
426:
427: try {
428: //
429: // get cmc node
430: //
431: cmcNode = getCommunityNode(cid);
432:
433: //
434: // check if this operation is supported
435: //
436: boolean supportsCreate = cmcNode.supportsCreate();
437: if (!supportsCreate) {
438: throw new CommunityException(
439: "Creating community is not supported, cid="
440: + cid);
441: }
442:
443: //
444: // create node
445: //
446:
447: cmcNode.create();
448: } catch (CMCExistsException cee) {
449: throw new CommunityException(
450: "community already exists, cid=" + cid, cee);
451: } catch (CMCException ce) {
452: throw new CommunityException(
453: "error creating community node, cid=" + cid, ce);
454: }
455:
456: return cmcNode;
457: }
458:
459: /**
460: * Remove community node if it's supported. An exception is thrown
461: * if it's not a supported operation.
462: *
463: * @param cNode <code>CommunityNode</code> to remove
464: * @throws com.sun.portal.community.mgmt.CommunityException
465: */
466: protected void removeCommunityNode(CMCNode cNode)
467: throws CommunityException {
468: //
469: // check if this operation is supported
470: //
471: boolean supportsRemove = false;
472: try {
473: supportsRemove = cNode.supportsRemove();
474: } catch (CMCException ce) {
475: throw new CommunityException(
476: "CommunityManagerImpl.removeCommunityNode(): cNode="
477: + cNode, ce);
478: }
479:
480: if (!supportsRemove) {
481: throw new CommunityException(
482: "CommunityManagerImpl.removeCommunityNode(): Removing community is not supported. cNode="
483: + cNode);
484: }
485:
486: //
487: // remove node
488: //
489: try {
490: cNode.remove();
491: } catch (CMCException ce) {
492: throw new CommunityException(
493: "CommunityManagerImpl.removeCommunityNode(): cNode="
494: + cNode, ce);
495: }
496: }
497:
498: public Map getUserCounts(Set communityIds)
499: throws CommunityException {
500: Map userCounts;
501:
502: Set communityPrincipals = TypeConverter
503: .communityIdsToPrincipals(communityIds);
504: CMCNodeManager cmcnm = getCommunityNodeManager();
505: try {
506: userCounts = cmcnm.getUserCounts(communityPrincipals);
507: } catch (CMCException cmce) {
508: throw new CommunityException(cmce);
509: }
510: userCounts = TypeConverter
511: .communityPrincipalKeysToIds(userCounts);
512:
513: return userCounts;
514: }
515:
516: public void logRecord(Logger logger, Level level, String msgKey,
517: Throwable th, Object parameter) {
518: LogRecord logRecord = new LogRecord(level, msgKey);
519: logRecord.setLoggerName(logger.getName());
520: logRecord.setThrown(th);
521: logRecord.setParameters(new Object[] { parameter });
522: logger.log(logRecord);
523: }
524:
525: public void logRecord(Logger logger, Level level, String msgKey,
526: Throwable th, Object[] parameters) {
527: LogRecord logRecord = new LogRecord(level, msgKey);
528: logRecord.setLoggerName(logger.getName());
529: logRecord.setThrown(th);
530: logRecord.setParameters(parameters);
531: logger.log(logRecord);
532: }
533:
534: public String getSearchUrl() {
535: return CommunityProperties.getInstance().getSearchUrl();
536: }
537:
538: /**
539: * Get the portal ID.
540: *
541: * The system will use the default portal ID system property, or the
542: * portalId field, if it is set. Clients that do not wish to use
543: * the portal ID system property should call setPortalId() before
544: * using this object.
545: */
546: String getPortalId() {
547: if (portalId == null || portalId.length() == 0) {
548: throw new NullPointerException(
549: "portal id was null or empty");
550: }
551:
552: return portalId;
553: }
554:
555: /**
556: * Set portal ID to use in this object.
557: *
558: * If set, this portal ID overrides the default portal ID system
559: * property.
560: */
561: public void setPortalId(String portalId) {
562: this .portalId = portalId;
563: }
564:
565: public int getDpBasePriority() {
566: return CommunityProperties.getInstance().getDpBasePriority();
567: }
568:
569: public String getSearchDbPrefix() {
570: return CommunityProperties.getInstance().getSearchDbPrefix();
571: }
572:
573: public String getSearchDb() {
574: String pre = getSearchDbPrefix();
575: return pre + "_communities_" + getPortalId();
576: }
577:
578: public String getSearchTaxonomyRoot() {
579: return CommunityProperties.getInstance()
580: .getSearchTaxonomyRoot();
581: }
582:
583: public String getContentsSearchDb(CommunityId cid) {
584: String pre = getSearchDbPrefix();
585: return pre + "_contents_" + getPortalId() + "." + cid;
586: }
587:
588: public String getDiscussionsSearchDb(CommunityId cid) {
589: String pre = getSearchDbPrefix();
590: return pre + "_discussions_" + getPortalId() + "." + cid;
591: }
592:
593: /* return the dbname of <community_prefix>_dbname_<portalId>
594: */
595: private String getCommunityDBNamespace(String dbname) {
596: if (dbname.startsWith(getSearchDbPrefix() + "_")
597: && dbname.endsWith("_" + getPortalId())) {
598: int s = dbname.indexOf('_');
599: int e = dbname.lastIndexOf('_');
600: if (e > s) {
601: return dbname.substring(s + 1, e);
602: }
603: }
604: return null;
605: }
606:
607: /**
608: *
609: * @return List of Strings -- name of community content databases
610: */
611: public List getContentsSearchDbs(CommunityId cid)
612: throws CommunityException {
613: ArrayList cdbs = new ArrayList();
614: try {
615: List dbs = SearchDatabase.getDatabaseList(this
616: .getSearchUrl());
617: for (int i = 0; i < dbs.size(); i++) {
618: SOIF dbsoif = (SOIF) dbs.get(i);
619: String cdbname = dbsoif.getURL();
620: String dbname = getCommunityDBNamespace(cdbname);
621: if (dbname != null
622: && !dbname.equalsIgnoreCase("communities")) {
623: cdbs.add(cid == null ? cdbname : cdbname + "."
624: + cid);
625: }
626: }
627: } catch (Exception e) {
628: throw new CommunityException(
629: "CommunityManagerImpl.getContentsSearchDbs()", e);
630: }
631: return cdbs;
632: }
633:
634: public Set match(Pattern p, boolean nameOnly)
635: throws CommunityException {
636: try {
637: CMCNodeManager cmcnm = getCommunityNodeManager();
638: Set principals = cmcnm.match(p, nameOnly);
639:
640: Set ids = TypeConverter
641: .communityPrincipalsToIds(principals);
642:
643: return ids;
644: } catch (CMCException cmce) {
645: throw new CommunityException(cmce);
646: }
647: }
648:
649: }
|