001: /* Copyright 2001 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal;
007:
008: import java.util.Date;
009: import java.util.Iterator;
010:
011: import javax.xml.parsers.ParserConfigurationException;
012: import javax.xml.xpath.XPath;
013: import javax.xml.xpath.XPathConstants;
014: import javax.xml.xpath.XPathExpressionException;
015: import javax.xml.xpath.XPathFactory;
016:
017: import org.jasig.portal.events.EventPublisherLocator;
018: import org.jasig.portal.events.support.ModifiedChannelDefinitionPortalEvent;
019: import org.jasig.portal.events.support.PublishedChannelDefinitionPortalEvent;
020: import org.jasig.portal.events.support.RemovedChannelDefinitionPortalEvent;
021: import org.jasig.portal.groups.IEntity;
022: import org.jasig.portal.groups.IEntityGroup;
023: import org.jasig.portal.groups.IGroupMember;
024: import org.jasig.portal.properties.PropertiesManager;
025: import org.jasig.portal.security.IAuthorizationPrincipal;
026: import org.jasig.portal.security.IPermission;
027: import org.jasig.portal.security.IPerson;
028: import org.jasig.portal.security.IUpdatingPermissionManager;
029: import org.jasig.portal.services.AuthorizationService;
030: import org.jasig.portal.services.GroupService;
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.jasig.portal.utils.CommonUtils;
034: import org.jasig.portal.utils.DocumentFactory;
035: import org.jasig.portal.utils.ResourceLoader;
036: import org.jasig.portal.utils.SmartCache;
037: import org.w3c.dom.Document;
038: import org.w3c.dom.Element;
039: import org.w3c.dom.NamedNodeMap;
040: import org.w3c.dom.Node;
041: import org.w3c.dom.NodeList;
042: import org.w3c.dom.Text;
043:
044: /**
045: * Manages the channel registry which is a listing of published channels
046: * that one can subscribe to (add to their layout).
047: * Also currently manages the channel types data and CPD documents.
048: * (maybe these should be managed by another class -Ken)
049: * @author Ken Weiner, kweiner@unicon.net
050: * @version $Revision: 36546 $
051: */
052: public class ChannelRegistryManager {
053:
054: private static final Log log = LogFactory
055: .getLog(ChannelRegistryManager.class);
056:
057: protected static final IChannelRegistryStore crs = ChannelRegistryStoreFactory
058: .getChannelRegistryStoreImpl();
059:
060: /**
061: * Default value for registryCacheTimeout.
062: * This value will be used when the corresponding property cannot be loaded.
063: */
064: private static final int DEFAULT_REGISTRY_CACHE_TIMEOUT = 900;
065:
066: /**
067: * Default value for chanTypesCacheTimeout.
068: * This value will be used when the corresponding property cannot be loaded.
069: */
070: private static final int DEFAULT_CHAN_TYPES_CACHE_TIMEOUT = 900;
071:
072: /**
073: * Default value for cpdCacheTimeout.
074: * This value will be used when the corresponding property cannot be loaded.
075: */
076: private static final int DEFAULT_CPD_CACHE_TIMEOUT = 900;
077:
078: /**
079: * Default value for localeAware.
080: * This value will be used when the corresponding property cannot be loaded.
081: */
082: private static final boolean DEFAULT_LOCALE_AWARE = false;
083:
084: // Cache timeout properties
085: /**
086: * Timeout, in seconds, of the cache of the registry of channels.
087: */
088: protected static final int registryCacheTimeout = PropertiesManager
089: .getPropertyAsInt(
090: "org.jasig.portal.ChannelRegistryManager.channel_registry_cache_timeout",
091: DEFAULT_REGISTRY_CACHE_TIMEOUT);
092:
093: /**
094: * Timeout, in seconds, of the cache of channel types.
095: */
096: protected static final int chanTypesCacheTimeout = PropertiesManager
097: .getPropertyAsInt(
098: "org.jasig.portal.ChannelRegistryManager.channel_types_cache_timeout",
099: DEFAULT_CHAN_TYPES_CACHE_TIMEOUT);
100:
101: /**
102: * Timeout, in seconds, of the cache of channel publishing documents.
103: */
104: protected static final int cpdCacheTimeout = PropertiesManager
105: .getPropertyAsInt(
106: "org.jasig.portal.ChannelRegistryManager.cpd_cache_timeout",
107: DEFAULT_CPD_CACHE_TIMEOUT);
108:
109: // i18n properties
110:
111: /**
112: * Boolean indicating whether internationalization will be used.
113: */
114: protected static final boolean localeAware = PropertiesManager
115: .getPropertyAsBoolean(
116: "org.jasig.portal.i18n.LocaleManager.locale_aware",
117: DEFAULT_LOCALE_AWARE);
118:
119: // Caches
120: protected static final SmartCache channelRegistryCache = new SmartCache(
121: registryCacheTimeout);
122: protected static final SmartCache channelTypesCache = new SmartCache(
123: chanTypesCacheTimeout);
124: protected static final SmartCache cpdCache = new SmartCache(
125: cpdCacheTimeout);
126:
127: // Cache keys
128: private static final String CHANNEL_REGISTRY_CACHE_KEY = "channelRegistryCacheKey";
129: private static final String CHANNEL_TYPES_CACHE_KEY = "channelTypesCacheKey";
130: private static final String CPD_CACHE_KEY = "cpdCacheKey";
131:
132: // Permission constants
133: private static final String FRAMEWORK_OWNER = "UP_FRAMEWORK";
134: private static final String SUBSCRIBER_ACTIVITY = "SUBSCRIBE";
135: private static final String GRANT_PERMISSION_TYPE = "GRANT";
136:
137: /**
138: * Returns a copy of the channel registry as a Document.
139: * This document is not filtered according to a user's channel permissions.
140: * For a filtered list, see <code>getChannelRegistry(IPerson person)</code>
141: * @return a copy of the channel registry as a Document
142: */
143: public static Document getChannelRegistry() throws PortalException {
144: Document channelRegistry = (Document) channelRegistryCache
145: .get(CHANNEL_REGISTRY_CACHE_KEY);
146: if (channelRegistry == null) {
147: // Channel registry has expired, so get it and cache it
148: try {
149: channelRegistry = getChannelRegistryXML();
150: } catch (Exception e) {
151: throw new PortalException(e);
152: }
153:
154: if (channelRegistry != null) {
155: channelRegistryCache.put(CHANNEL_REGISTRY_CACHE_KEY,
156: channelRegistry);
157: log.info("Caching channel registry.");
158: }
159: }
160:
161: // Clone the original registry document so that it doesn't get modified
162: return (Document) channelRegistry.cloneNode(true);
163: }
164:
165: /**
166: * Returns the channel registry as a Document. This document is filtered
167: * according to a user's channel permissions.
168: * @return the filtered channel registry as a Document
169: */
170: public static Document getChannelRegistry(IPerson person)
171: throws PortalException {
172: Document channelRegistry = getChannelRegistry();
173:
174: // Filter the channel registry according to permissions
175: EntityIdentifier ei = person.getEntityIdentifier();
176: IAuthorizationPrincipal ap = AuthorizationService.instance()
177: .newPrincipal(ei.getKey(), ei.getType());
178:
179: // Cycle through all the channels, looking for restricted channels
180: NodeList nl = channelRegistry.getElementsByTagName("channel");
181: for (int i = (nl.getLength() - 1); i >= 0; i--) {
182: Element channel = (Element) nl.item(i);
183: String channelPublishId = channel.getAttribute("chanID");
184: channelPublishId = channelPublishId.startsWith("chan") ? channelPublishId
185: .substring(4)
186: : channelPublishId;
187:
188: // Take out channels which user doesn't have access to
189: if (!ap.canSubscribe(Integer.parseInt(channelPublishId)))
190: channel.getParentNode().removeChild(channel);
191: }
192:
193: return channelRegistry;
194: }
195:
196: /**
197: * Returns an XML document which describes the channel registry.
198: * See uPortal's <code>channelRegistry.dtd</code>
199: * @return doc the channel registry document
200: * @throws java.lang.Exception
201: */
202: public static Document getChannelRegistryXML() throws Exception {
203: Document doc = DocumentFactory.getNewDocument();
204: Element registry = doc.createElement("registry");
205: doc.appendChild(registry);
206:
207: IEntityGroup channelCategoriesGroup = GroupService
208: .getDistinguishedGroup(GroupService.CHANNEL_CATEGORIES);
209: processGroupsRecursively(channelCategoriesGroup, doc, registry);
210:
211: return doc;
212: }
213:
214: private static void processGroupsRecursively(IEntityGroup group,
215: Document owner, Element parentGroup) throws Exception {
216: Date now = new Date();
217: Iterator iter = group.getMembers();
218: while (iter.hasNext()) {
219: IGroupMember member = (IGroupMember) iter.next();
220: if (member.isGroup()) {
221: IEntityGroup memberGroup = (IEntityGroup) member;
222: String key = memberGroup.getKey();
223: String name = memberGroup.getName();
224: String description = memberGroup.getDescription();
225:
226: // Create category element and append it to its parent
227: Element categoryE = owner.createElement("category");
228: categoryE.setAttribute("ID", "cat" + key);
229: categoryE.setIdAttribute("ID", true);
230: categoryE.setAttribute("name", name);
231: categoryE.setAttribute("description", description);
232: parentGroup.appendChild(categoryE);
233: processGroupsRecursively(memberGroup, owner, categoryE);
234: } else {
235: IEntity channelDefMember = (IEntity) member;
236: int channelPublishId = CommonUtils
237: .parseInt(channelDefMember.getKey());
238: if (channelPublishId > 0) {
239: ChannelDefinition channelDef = crs
240: .getChannelDefinition(channelPublishId);
241: if (channelDef != null) {
242: // Make sure channel is approved
243: Date approvalDate = channelDef
244: .getApprovalDate();
245: if (approvalDate != null
246: && approvalDate.before(now)) {
247: Element channelDefE = channelDef
248: .getDocument(owner, "chan"
249: + channelPublishId);
250: channelDefE = (Element) owner.importNode(
251: channelDefE, true);
252:
253: if (channelDefE.getAttribute("ID") != null)
254: channelDefE.setIdAttribute("ID", true);
255:
256: parentGroup.appendChild(channelDefE);
257: }
258: }
259: }
260: }
261: }
262: }
263:
264: /**
265: * Looks in channel registry for a channel element matching the
266: * given channel ID.
267: * @param channelPublishId the channel publish id
268: * @return the channel element matching specified channel publish id
269: * @throws PortalException
270: */
271: public static Element getChannel(String channelPublishId)
272: throws PortalException {
273: Document channelRegistry = getChannelRegistry();
274: Element channelE = null;
275: try {
276: String expression = "(//channel[@ID = '" + channelPublishId
277: + "'])[1]";
278: XPathFactory fac = XPathFactory.newInstance();
279: XPath xpath = fac.newXPath();
280: channelE = (Element) xpath.evaluate(expression,
281: channelRegistry, XPathConstants.NODE);
282: } catch (XPathExpressionException e) {
283: throw new GeneralRenderingException(
284: "Not able to find channel " + channelPublishId
285: + " within channel registry.", e);
286: }
287: return channelE;
288: }
289:
290: /**
291: * Create XML representing this channel definition.
292: * I don't think this method really belongs in the
293: * ChannelRegistryManager since this XML fragment is
294: * related more to a channel instance, but we'll hold
295: * it here for now and find a better place for it later :)
296: * @param subscribeId the channel subscibe ID, formerly called instance ID
297: * @param channelDef a channel definition
298: * @return the XML representing this channel definition
299: */
300: public static Element getChannelXML(String subscribeId,
301: ChannelDefinition channelDef) {
302: Document doc = DocumentFactory.getNewDocument();
303: Element channelE = doc.createElement("channel");
304: channelE.setAttribute("ID", subscribeId);
305: channelE.setAttribute("chanID", String.valueOf(channelDef
306: .getId()));
307: channelE.setAttribute("timeout", String.valueOf(channelDef
308: .getTimeout()));
309: // I18n
310: if (localeAware) {
311: String locale = channelDef.getLocale();
312: channelE.setAttribute("name", channelDef.getName(locale));
313: channelE.setAttribute("title", channelDef.getTitle(locale));
314: channelE.setAttribute("locale", locale);
315: if (log.isDebugEnabled())
316: log
317: .debug("ChannelRegistryManager::getChannelXML: locale="
318: + locale);
319: } else {
320: channelE.setAttribute("name", channelDef.getName());
321: channelE.setAttribute("title", channelDef.getTitle());
322: }
323: channelE.setAttribute("fname", channelDef.getFName());
324: channelE.setAttribute("class", channelDef.getJavaClass());
325: channelE.setAttribute("typeID", String.valueOf(channelDef
326: .getTypeId()));
327: channelE.setAttribute("editable",
328: channelDef.isEditable() ? "true" : "false");
329: channelE.setAttribute("hasHelp", channelDef.hasHelp() ? "true"
330: : "false");
331: channelE.setAttribute("hasAbout",
332: channelDef.hasAbout() ? "true" : "false");
333: channelE.setAttribute("secure", channelDef.isSecure() ? "true"
334: : "false");
335: channelE.setAttribute("isPortlet",
336: channelDef.isPortlet() ? "true" : "false");
337:
338: // Add any parameters
339: ChannelParameter[] parameters = channelDef.getParameters();
340: for (int i = 0; i < parameters.length; i++) {
341: ChannelParameter cp = parameters[i];
342: Element parameterE = doc.createElement("parameter");
343: parameterE.setAttribute("name", cp.getName());
344: parameterE.setAttribute("value", cp.getValue());
345: if (cp.getOverride()) {
346: parameterE.setAttribute("override", "yes");
347: }
348: channelE.appendChild(parameterE);
349: }
350:
351: return channelE;
352: }
353:
354: /**
355: * Update a channel definition with data from a channel XML
356: * element. I don't think this method really belongs in the
357: * ChannelRegistryManager since this XML fragment contains
358: * a channel subscribe ID, but we'll hold it here for now
359: * and find a better place for it later :)
360: * Note that this method does not set the ID, publisher ID,
361: * approver ID, pubish date, or approval date.
362: * @param channelE an XML element representing a channel definition
363: * @param channelDef the channel definition to update
364: */
365: public static void setChannelXML(Element channelE,
366: ChannelDefinition channelDef) {
367: channelDef.setFName(channelE.getAttribute("fname"));
368: channelDef.setName(channelE.getAttribute("name"));
369: channelDef.setDescription(channelE.getAttribute("description"));
370: channelDef.setTitle(channelE.getAttribute("title"));
371: channelDef.setJavaClass(channelE.getAttribute("class"));
372:
373: String timeout = channelE.getAttribute("timeout");
374: if (timeout != null && timeout.trim().length() != 0) {
375: channelDef.setTimeout(Integer.parseInt(timeout));
376: }
377:
378: String secure = channelE.getAttribute("secure");
379: channelDef
380: .setIsSecure(secure != null && secure.equals("true") ? true
381: : false);
382:
383: channelDef.setTypeId(Integer.parseInt(channelE
384: .getAttribute("typeID")));
385: String chanEditable = channelE.getAttribute("editable");
386: String chanHasHelp = channelE.getAttribute("hasHelp");
387: String chanHasAbout = channelE.getAttribute("hasAbout");
388: channelDef.setEditable(chanEditable != null
389: && chanEditable.equals("true") ? true : false);
390: channelDef.setHasHelp(chanHasHelp != null
391: && chanHasHelp.equals("true") ? true : false);
392: channelDef.setHasAbout(chanHasAbout != null
393: && chanHasAbout.equals("true") ? true : false);
394: // I18n
395: if (localeAware) {
396: channelDef.setLocale(channelE.getAttribute("locale"));
397: }
398:
399: // Now set the channel parameters
400: channelDef.clearParameters();
401: NodeList channelChildren = channelE.getChildNodes();
402: if (channelChildren != null) {
403: for (int i = 0; i < channelChildren.getLength(); i++) {
404: if (channelChildren.item(i).getNodeName().equals(
405: "parameter")) {
406: Element parameterE = (Element) channelChildren
407: .item(i);
408: NamedNodeMap parameterAtts = parameterE
409: .getAttributes();
410: String paramName = null;
411: String paramValue = null;
412: String paramOverride = "NULL";
413:
414: for (int j = 0; j < parameterAtts.getLength(); j++) {
415: Node parameterAtt = parameterAtts.item(j);
416: String parameterAttName = parameterAtt
417: .getNodeName();
418: String parameterAttValue = parameterAtt
419: .getNodeValue();
420:
421: if (parameterAttName.equals("name")) {
422: paramName = parameterAttValue;
423: } else if (parameterAttName.equals("value")) {
424: paramValue = parameterAttValue;
425: } else if (parameterAttName.equals("override")
426: && parameterAttValue.equals("yes")) {
427: paramOverride = "Y";
428: }
429: }
430:
431: if (paramName == null && paramValue == null) {
432: throw new RuntimeException(
433: "Invalid parameter node");
434: }
435:
436: channelDef.addParameter(paramName, paramValue,
437: paramOverride);
438: }
439: }
440: }
441: }
442:
443: /**
444: * Create XML representing the channel types.
445: * It will look something like this:
446: * <p><code>
447: *
448: *<channelTypes>
449: * <channelType ID="0">
450: * <class>org.jasig.portal.channels.CImage</class>
451: * <name>Image</name>
452: * <description>Simple channel to display an image with optional
453: * caption and subcaption</description>
454: * <cpd-uri>webpages/media/org/jasig/portal/channels/CImage/CImage.cpd</cpd-uri>
455: * </channelType>
456: * <channelType ID="1">
457: * <class>org.jasig.portal.channels.CWebProxy</class>
458: * <name>Web Proxy</name>
459: * <description>Incorporate a dynamic HTML or XML application</description>
460: * <cpd-uri>webpages/media/org/jasig/portal/channels/CWebProxy/CWebProxy.cpd</cpd-uri>
461: * </channelType>
462: *</channelTypes>
463: *
464: * </code></p>
465: * @return channelTypesXML, the XML representing the channel types
466: * @throws java.lang.Exception
467: */
468: public static Document getChannelTypesXML() throws Exception {
469: Document doc = DocumentFactory.getNewDocument();
470: Element channelTypesE = doc.createElement("channelTypes");
471:
472: ChannelType[] channelTypes = crs.getChannelTypes();
473: for (int i = 0; i < channelTypes.length; i++) {
474: int channelTypeId = channelTypes[i].getId();
475: String javaClass = channelTypes[i].getJavaClass();
476: String name = channelTypes[i].getName();
477: String descr = channelTypes[i].getDescription();
478: String cpdUri = channelTypes[i].getCpdUri();
479:
480: // <channelType>
481: Element channelTypeE = doc.createElement("channelType");
482: channelTypeE.setAttribute("ID", String
483: .valueOf(channelTypeId));
484:
485: // <class>
486: Element classE = doc.createElement("class");
487: classE.appendChild(doc.createTextNode(javaClass));
488: channelTypeE.appendChild(classE);
489:
490: // <name>
491: Element nameE = doc.createElement("name");
492: nameE.appendChild(doc.createTextNode(name));
493: channelTypeE.appendChild(nameE);
494:
495: // <description>
496: Element descriptionE = doc.createElement("description");
497: descriptionE.appendChild(doc.createTextNode(descr));
498: channelTypeE.appendChild(descriptionE);
499:
500: // <cpd-uri>
501: Element cpdUriE = doc.createElement("cpd-uri");
502: cpdUriE.appendChild(doc.createTextNode(cpdUri));
503: channelTypeE.appendChild(cpdUriE);
504:
505: channelTypesE.appendChild(channelTypeE);
506: }
507: doc.appendChild(channelTypesE);
508:
509: return doc;
510: }
511:
512: /**
513: * Looks in channel registry for a channel element matching the
514: * given channel ID.
515: * @param channelPublishId the channel publish ID
516: * @return the channel element matching chanID
517: * @throws org.jasig.portal.PortalException
518: */
519: public static NodeList getCategories(String channelPublishId)
520: throws PortalException {
521: Document channelRegistry = (Document) channelRegistryCache
522: .get(CHANNEL_REGISTRY_CACHE_KEY);
523: NodeList categories = null;
524: try {
525: String expression = "//category[channel/@ID = '"
526: + channelPublishId + "']";
527: XPathFactory fac = XPathFactory.newInstance();
528: XPath xpath = fac.newXPath();
529: categories = (NodeList) xpath.evaluate(expression,
530: channelRegistry, XPathConstants.NODESET);
531:
532: } catch (XPathExpressionException e) {
533: throw new GeneralRenderingException(
534: "Not able to find channel " + channelPublishId
535: + " within channel registry.", e);
536: }
537: return categories;
538: }
539:
540: /**
541: * Publishes a channel.
542: * @param channel the channel XML fragment
543: * @param categoryIDs a list of categories that the channel belongs to
544: * @param groupMembers a list of groups and/or people that are permitted to subscribe to and view the channel
545: * @param publisher the user ID of the channel publisher
546: * @throws java.lang.Exception
547: */
548: public static void publishChannel(Element channel,
549: String[] categoryIDs, IGroupMember[] groupMembers,
550: IPerson publisher) throws Exception {
551: // Reset the channel registry cache
552: channelRegistryCache.remove(CHANNEL_REGISTRY_CACHE_KEY);
553:
554: ChannelDefinition channelDef = null;
555:
556: // Use current channel ID if modifying previously published channel, otherwise get a new ID
557: boolean newChannel = true;
558: int ID = 0;
559: String channelPublishId = channel.getAttribute("ID");
560: if (channelPublishId != null
561: && channelPublishId.trim().length() > 0) {
562: newChannel = false;
563: ID = Integer
564: .parseInt(channelPublishId.startsWith("chan") ? channelPublishId
565: .substring(4)
566: : channelPublishId);
567: channelDef = crs.getChannelDefinition(ID);
568: if (log.isDebugEnabled())
569: log.debug("Attempting to modify channel " + ID + "...");
570: } else {
571: channelDef = crs.newChannelDefinition();
572: ID = channelDef.getId();
573: if (log.isDebugEnabled())
574: log.debug("Attempting to publish new channel " + ID
575: + "...");
576: }
577:
578: // Add channel
579: setChannelXML(channel, channelDef);
580: Date now = new Date();
581: channelDef.setPublisherId(publisher.getID());
582: channelDef.setPublishDate(now);
583: channelDef.setApproverId(publisher.getID());
584: channelDef.setApprovalDate(now);
585: crs.saveChannelDefinition(channelDef);
586:
587: // Delete existing category memberships for this channel
588: String chanKey = String.valueOf(channelDef.getId());
589: IEntity channelDefEntity = GroupService.getEntity(chanKey,
590: ChannelDefinition.class);
591: Iterator iter = channelDefEntity.getAllContainingGroups();
592: while (iter.hasNext()) {
593: IEntityGroup group = (IEntityGroup) iter.next();
594: group.removeMember(channelDefEntity);
595: group.update();
596: }
597:
598: // For each category ID, add channel to category
599: for (int i = 0; i < categoryIDs.length; i++) {
600: categoryIDs[i] = categoryIDs[i].startsWith("cat") ? categoryIDs[i]
601: .substring(3)
602: : categoryIDs[i];
603: String iCatID = categoryIDs[i];
604: ChannelCategory category = crs.getChannelCategory(iCatID);
605: crs.addChannelToCategory(channelDef, category);
606: }
607:
608: // Set groups
609: AuthorizationService authService = AuthorizationService
610: .instance();
611: String target = "CHAN_ID." + ID;
612: IUpdatingPermissionManager upm = authService
613: .newUpdatingPermissionManager(FRAMEWORK_OWNER);
614: IPermission[] permissions = new IPermission[groupMembers.length];
615: for (int i = 0; i < groupMembers.length; i++) {
616: IAuthorizationPrincipal authPrincipal = authService
617: .newPrincipal(groupMembers[i]);
618: permissions[i] = upm.newPermission(authPrincipal);
619: permissions[i].setType(GRANT_PERMISSION_TYPE);
620: permissions[i].setActivity(SUBSCRIBER_ACTIVITY);
621: permissions[i].setTarget(target);
622: }
623:
624: // If modifying the channel, remove the existing permissions before adding the new ones
625: if (!newChannel) {
626: IPermission[] oldPermissions = upm.getPermissions(
627: SUBSCRIBER_ACTIVITY, target);
628: upm.removePermissions(oldPermissions);
629: }
630: upm.addPermissions(permissions);
631:
632: if (log.isInfoEnabled())
633: log.info("Channel " + ID + " has been "
634: + (newChannel ? "published" : "modified") + ".");
635:
636: // Record that a channel has been published or modified
637: if (newChannel) {
638: EventPublisherLocator.getApplicationEventPublisher()
639: .publishEvent(
640: new PublishedChannelDefinitionPortalEvent(
641: channelDef, publisher, channelDef));
642: } else {
643: EventPublisherLocator.getApplicationEventPublisher()
644: .publishEvent(
645: new ModifiedChannelDefinitionPortalEvent(
646: channelDef, publisher, channelDef));
647: }
648: }
649:
650: /**
651: * Removes a channel from the channel registry.
652: * @param channelID the channel ID
653: * @param person the person removing the channel
654: * @throws java.lang.Exception
655: */
656: public static void removeChannel(String channelID, IPerson person)
657: throws Exception {
658: // Reset the channel registry cache
659: channelRegistryCache.remove(CHANNEL_REGISTRY_CACHE_KEY);
660: // Remove the channel
661: String sChannelPublishId = channelID.startsWith("chan") ? channelID
662: .substring(4)
663: : channelID;
664: int channelPublishId = Integer.parseInt(sChannelPublishId);
665: ChannelDefinition channelDef = crs
666: .getChannelDefinition(channelPublishId);
667: crs.disapproveChannelDefinition(channelDef);
668:
669: // Record that a channel has been deleted
670: EventPublisherLocator.getApplicationEventPublisher()
671: .publishEvent(
672: new RemovedChannelDefinitionPortalEvent(
673: channelDef, person, channelDef));
674: }
675:
676: /**
677: * Returns the publishable channel types as a Document.
678: * @return a list of channel types as a Document
679: */
680: public static Document getChannelTypes() throws PortalException {
681: Document channelTypes = (Document) channelTypesCache
682: .get(CHANNEL_TYPES_CACHE_KEY);
683: if (channelTypes == null) {
684: // Channel types doc has expired, so get it and cache it
685: try {
686: channelTypes = getChannelTypesXML();
687: } catch (Exception e) {
688: throw new PortalException(e);
689: }
690:
691: if (channelTypes != null) {
692: channelTypesCache.put(CHANNEL_TYPES_CACHE_KEY,
693: channelTypes);
694: if (log.isInfoEnabled())
695: log.info("Caching channel types.");
696: }
697: }
698:
699: // Clone the original channel types document so that it doesn't get modified
700: return (Document) channelTypes.cloneNode(true);
701: }
702:
703: /**
704: * Returns a CPD (channel publishing document) as a Document
705: * @param chanTypeID the channel type ID, "-1" if channel type is "custom"
706: * @return the CPD document matching the chanTypeID, <code>null</code> if "custom" channel
707: * @throws org.jasig.portal.PortalException
708: */
709: public static Document getCPD(String chanTypeID)
710: throws PortalException {
711: // There are no CPD docs for custom channels (chanTypeID = -1)
712: if (chanTypeID == null || chanTypeID.equals("-1"))
713: return null;
714:
715: Document cpd = (Document) cpdCache.get(CPD_CACHE_KEY
716: + chanTypeID);
717: if (cpd == null) {
718: // CPD doc has expired, so get it and cache it
719: Element channelTypes = getChannelTypes()
720: .getDocumentElement();
721:
722: // Look for channel type element matching the channel type ID
723: Element chanType = null;
724:
725: for (Node n = channelTypes.getFirstChild(); n != null; n = n
726: .getNextSibling()) {
727: if (n.getNodeType() == Node.ELEMENT_NODE
728: && n.getNodeName().equals("channelType")) {
729: chanType = (Element) n;
730: if (chanTypeID.equals(chanType.getAttribute("ID")))
731: break;
732: }
733: }
734:
735: // Find the cpd-uri within this element
736: String cpdUri = null;
737: for (Node n = chanType.getLastChild(); n != null; n = n
738: .getPreviousSibling()) {
739: if (n.getNodeType() == Node.ELEMENT_NODE
740: && n.getNodeName().equals("cpd-uri")) {
741: // Found the <cpd-uri> element, now get its value
742: for (Node m = n.getFirstChild(); m != null; m = m
743: .getNextSibling()) {
744: if (m instanceof Text)
745: cpdUri = m.getNodeValue();
746: }
747: break;
748: }
749: }
750:
751: if (cpdUri != null) {
752: try {
753: cpd = ResourceLoader.getResourceAsDocument(
754: ChannelRegistryManager.class, cpdUri);
755: } catch (java.io.IOException ioe) {
756: throw new ResourceMissingException(cpdUri,
757: "Channel publishing document", ioe);
758: } catch (org.xml.sax.SAXException se) {
759: throw new PortalException(
760: "Unable to parse CPD file: " + cpdUri, se);
761: } catch (ParserConfigurationException pce) {
762: throw new PortalException(
763: "Unable to parse CPD file: " + cpdUri, pce);
764: }
765: }
766:
767: if (cpd != null) {
768: cpdCache.put(CPD_CACHE_KEY + chanTypeID, cpd);
769: if (log.isInfoEnabled())
770: log.info("Caching CPD for channel type "
771: + chanTypeID);
772: }
773: }
774:
775: // Clone the original CPD document so that it doesn't get modified
776: return (Document) cpd.cloneNode(true);
777: }
778: }
|