001: /* Copyright 2004 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.layout.alm.channels;
007:
008: import org.jasig.portal.ChannelRegistryManager;
009: import org.jasig.portal.PortalException;
010: import org.jasig.portal.PortalControlStructures;
011: import org.jasig.portal.utils.CommonUtils;
012: import org.jasig.portal.utils.XSLT;
013: import org.jasig.portal.utils.DocumentFactory;
014: import org.jasig.portal.layout.alm.IAggregatedLayout;
015: import org.w3c.dom.DOMException;
016: import org.w3c.dom.Document;
017: import org.w3c.dom.NodeList;
018: import org.w3c.dom.Node;
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021:
022: import javax.xml.xpath.XPath;
023: import javax.xml.xpath.XPathConstants;
024: import javax.xml.xpath.XPathExpressionException;
025: import javax.xml.xpath.XPathFactory;
026:
027: import org.w3c.dom.Element;
028: import org.xml.sax.ContentHandler;
029: import java.util.Vector;
030: import java.util.Set;
031: import java.util.Iterator;
032: import java.util.Enumeration;
033: import java.util.Collection;
034:
035: /**
036: * A channel for adding new content to a layout.
037: *
038: * Prior to uPortal 2.5, this channel lived in the org.jasig.portal.layout.channels
039: * package. Since it is part of Aggregated Layouts, it was moved to its present
040: * package for uPortal 2.5.
041: *
042: * @author Michael Ivanov, mvi@immagic.com
043: * @version $Revision: 36803 $
044: * @since uPortal 2.5
045: */
046: public class CContentSubscriber extends FragmentManager {
047: private static final Log log = LogFactory
048: .getLog(CContentSubscriber.class);
049:
050: private static final String sslLocation = "/org/jasig/portal/channels/CContentSubscriber/CContentSubscriber.ssl";
051: private Document channelRegistry;
052: private Document registry;
053: private Vector expandedItems;
054: private Vector condensedItems;
055: private String searchFragment = "true";
056: private String searchChannel = "true";
057: private String searchCategory = "true";
058: private String searchQuery = null;
059: private boolean isFragment = false;
060:
061: private final static String CHANNEL = "channel";
062: private final static String FRAGMENT = "fragment";
063: private final static String CATEGORY = "category";
064:
065: private boolean initRegistry;
066:
067: private class ListItem {
068:
069: private String itemId;
070: private String name;
071: private String categoryId;
072: private String channelState;
073:
074: public ListItem(String categoryId, String itemId, String name,
075: String channelState) {
076: this .categoryId = categoryId;
077: this .itemId = itemId;
078: this .name = name;
079: this .channelState = channelState;
080: }
081:
082: public String getItemId() {
083: return itemId;
084: }
085:
086: public String getCategoryId() {
087: return categoryId;
088: }
089:
090: public String getName() {
091: return name;
092: }
093:
094: public String getChannelState() {
095: return channelState;
096: }
097:
098: public boolean equals(Object obj) {
099: if (obj == null || !(obj instanceof ListItem))
100: return false;
101: ListItem item = (ListItem) obj;
102: return (categoryId.equals(item.getCategoryId())
103: && itemId.equals(item.getItemId())
104: && name.equals(item.getName()) && channelState
105: .equals(item.getChannelState()));
106: }
107:
108: }
109:
110: public CContentSubscriber() {
111: super ();
112: expandedItems = new Vector();
113: condensedItems = new Vector();
114: initRegistry = true;
115: }
116:
117: private void expandAscendents(Node node) {
118: if (node == null || !(node instanceof Element))
119: return;
120: ((Element) node).setAttribute("search-view", "expanded");
121: expandAscendents(node.getParentNode());
122: }
123:
124: protected void analyzeParameters(XSLT xslt) throws PortalException {
125:
126: try {
127:
128: String fragmentId = CommonUtils.nvl(runtimeData
129: .getParameter("uPcCS_fragmentID"));
130: String channelId = CommonUtils.nvl(runtimeData
131: .getParameter("uPcCS_channelID"));
132: String categoryId = CommonUtils.nvl(runtimeData
133: .getParameter("uPcCS_categoryID"));
134: String action = CommonUtils.nvl(runtimeData
135: .getParameter("uPcCS_action"));
136: String channelState = CommonUtils.nvl(runtimeData
137: .getParameter("channel-state"), "browse");
138: isFragment = CommonUtils.nvl(
139: runtimeData.getParameter("isFragment"),
140: String.valueOf(isFragment)).equals("true");
141: boolean all = false, expand = action.equals("expand"), condense = action
142: .equals("condense");
143:
144: Vector tagNames = new Vector();
145:
146: if (expand || condense) {
147:
148: if (!isFragment && fragmentId.equals("all")) {
149: all = true;
150: tagNames.add(FRAGMENT);
151: }
152:
153: if (channelId.equals("all")) {
154: all = true;
155: tagNames.add(CHANNEL);
156: }
157:
158: if (categoryId.equals("all")) {
159: all = true;
160: tagNames.add(CATEGORY);
161: }
162:
163: if (!all) {
164: String itemName = CHANNEL;
165: String itemId = channelId;
166: if (fragmentId.length() > 0) {
167: itemId = fragmentId;
168: itemName = FRAGMENT;
169: } else if (categoryId.length() > 0
170: && channelId.length() == 0) {
171: itemId = categoryId;
172: itemName = CATEGORY;
173: }
174:
175: if (!isFragment
176: || (!itemName.equals(FRAGMENT) && !(itemName
177: .equals(CATEGORY) && itemId
178: .equals("Fragments")))) {
179: ListItem item = new ListItem(categoryId,
180: itemId, itemName, channelState
181: .equals("search") ? "search"
182: : "browse");
183:
184: if (expand) {
185: expandedItems.add(item);
186: condensedItems.remove(item);
187: } else {
188: condensedItems.add(item);
189: expandedItems.remove(item);
190: }
191: }
192: }
193:
194: } else if (action.equals("init")
195: || (action.length() == 0 && initRegistry)) {
196: refreshFragmentMap();
197: initRegistry();
198: if (initRegistry)
199: initRegistry = false;
200: // Reset isFragment only from the XSLT params (ignoring cached value)
201: isFragment = CommonUtils
202: .nvl(runtimeData.getParameter("isFragment"),
203: "false").equals("true");
204: } else if (action.equals("search")) {
205: searchFragment = CommonUtils.nvl(runtimeData
206: .getParameter("search-fragment"), "false");
207: searchChannel = CommonUtils.nvl(runtimeData
208: .getParameter("search-channel"), "false");
209: searchCategory = CommonUtils.nvl(runtimeData
210: .getParameter("search-category"), "false");
211: searchQuery = runtimeData.getParameter("search-query");
212: // Clear all the previous state
213: if (searchQuery != null) {
214: searchQuery = searchQuery.toLowerCase();
215: String expression = "//*";
216: XPathFactory fac = XPathFactory.newInstance();
217: XPath xpath = fac.newXPath();
218: NodeList nodeList = (NodeList) xpath.evaluate(
219: expression, registry,
220: XPathConstants.NODESET);
221: for (int k = 0; k < nodeList.getLength(); k++) {
222: Element node = (Element) nodeList.item(k);
223: node.setAttribute("search-selected", "false");
224: node.setAttribute("search-view", "condensed");
225: }
226: }
227: if (CommonUtils.nvl(searchQuery).length() > 0) {
228: String[] xPathQueries = new String[3];
229: if (searchChannel.equals("true"))
230: xPathQueries[0] = "//channel";
231: if (searchCategory.equals("true"))
232: xPathQueries[1] = "//category";
233: if (searchFragment.equals("true"))
234: xPathQueries[2] = "//fragment";
235: for (int i = 0; i < xPathQueries.length; i++) {
236: if (xPathQueries[i] != null) {
237: log.debug("xPathQueries[" + i + "]: "
238: + xPathQueries[i]);
239: XPathFactory fac = XPathFactory
240: .newInstance();
241: XPath xpath = fac.newXPath();
242: NodeList nodeList = (NodeList) xpath
243: .evaluate(xPathQueries[i],
244: registry,
245: XPathConstants.NODESET);
246: for (int k = 0; k < nodeList.getLength(); k++) {
247: Element node = (Element) nodeList
248: .item(k);
249: // check description and name attribute
250: String name = node.getAttribute("name")
251: .toLowerCase();
252: String desc = node.getAttribute(
253: "description").toLowerCase();
254: if (name.indexOf(searchQuery) >= 0
255: || desc.indexOf(searchQuery) >= 0) {
256: node.setAttribute(
257: "search-selected", "true");
258: expandAscendents(node);
259: }
260: }
261: }
262: }
263: }
264: }
265:
266: Vector removedItems = new Vector();
267: String attrName = channelState.equals("search") ? "search-view"
268: : "view";
269:
270: if (!action.equals("search")) {
271: if (!all) {
272:
273: Vector items = expandedItems;
274: for (int k = 0; k < 2; items = condensedItems, k++) {
275: for (int i = 0; i < items.size(); i++) {
276: for (Iterator iter = items.iterator(); iter
277: .hasNext();) {
278: ListItem item = (ListItem) iter.next();
279: if (channelState.equals(item
280: .getChannelState())) {
281: String xPathQuery = null;
282: if (CHANNEL.equals(item.getName()))
283: xPathQuery = "//channel[../@ID='"
284: + item.getCategoryId()
285: + "' and @ID='"
286: + item.getItemId()
287: + "']";
288: else
289: xPathQuery = "//*[@ID='"
290: + item.getItemId()
291: + "']";
292: XPathFactory fac = XPathFactory
293: .newInstance();
294: XPath xpath = fac.newXPath();
295: Element elem = (Element) xpath
296: .evaluate(xPathQuery,
297: registry,
298: XPathConstants.NODE);
299: if (elem != null)
300: elem.setAttribute(attrName,
301: (k == 0) ? "expanded"
302: : "condensed");
303: else
304: removedItems.add(item);
305: }
306: }
307: }
308: items.removeAll(removedItems);
309: }
310:
311: } else {
312:
313: for (int i = 0; i < tagNames.size(); i++) {
314: String tagName = (String) tagNames.get(i);
315: for (Iterator iter = expandedItems.iterator(); iter
316: .hasNext();) {
317: ListItem item = (ListItem) iter.next();
318: if (tagName.equals(item.getName())
319: && channelState.equals(item
320: .getChannelState()))
321: removedItems.add(item);
322: }
323: expandedItems.removeAll(removedItems);
324: for (Iterator iter = condensedItems.iterator(); iter
325: .hasNext();) {
326: ListItem item = (ListItem) iter.next();
327: if (tagName.equals(item.getName())
328: && channelState.equals(item
329: .getChannelState()))
330: removedItems.add(item);
331: }
332: condensedItems.removeAll(removedItems);
333: NodeList nodeList = registry
334: .getElementsByTagName(tagName);
335: String attrValue = (expand) ? "expanded"
336: : "condensed";
337: for (int k = 0; k < nodeList.getLength(); k++) {
338: Element node = (Element) nodeList.item(k);
339: node.setAttribute(attrName, attrValue);
340: }
341: }
342:
343: }
344: }
345:
346: // Passing all the HTTP params back to the stylesheet
347: passAllParameters(xslt);
348: xslt.setStylesheetParameter("search-fragment",
349: searchFragment);
350: xslt
351: .setStylesheetParameter("search-channel",
352: searchChannel);
353: xslt.setStylesheetParameter("search-category",
354: searchCategory);
355: xslt.setStylesheetParameter("search-query", CommonUtils
356: .nvl(searchQuery));
357: xslt.setStylesheetParameter("isFragment", String
358: .valueOf(isFragment));
359:
360: } catch (DOMException e) {
361: throw new PortalException(e);
362: } catch (XPathExpressionException e) {
363: throw new PortalException(e);
364: }
365:
366: }
367:
368: private void passAllParameters(XSLT xslt) {
369: for (Enumeration params = runtimeData.getParameterNames(); params
370: .hasMoreElements();) {
371: String paramName = (String) params.nextElement();
372: xslt.setStylesheetParameter(paramName, runtimeData
373: .getParameter(paramName));
374: }
375: }
376:
377: // Returns only subscribable pulled fragments that do not exist the current user layout
378: protected Collection getFragments() throws PortalException {
379: Collection pulledFragments = alm.getSubscribableFragments();
380: Set layoutFragments = ((IAggregatedLayout) alm.getUserLayout())
381: .getFragmentIds();
382: pulledFragments.removeAll(layoutFragments);
383: return pulledFragments;
384: }
385:
386: public void initRegistry() throws PortalException {
387: channelRegistry = ChannelRegistryManager
388: .getChannelRegistry(staticData.getPerson());
389: registry = DocumentFactory.getNewDocument();
390: registry.appendChild(registry.importNode(channelRegistry
391: .getDocumentElement(), true));
392: getFragmentList(registry, registry.getDocumentElement());
393: }
394:
395: /**
396: * Passes portal control structure to the channel.
397: * @see PortalControlStructures
398: */
399: public void setPortalControlStructures(PortalControlStructures pcs)
400: throws PortalException {
401: super .setPortalControlStructures(pcs);
402: if (alm == null)
403: throw new PortalException(
404: "The layout manager must have type IAgreggatedUserLayoutManager!");
405: }
406:
407: public void renderXML(ContentHandler out) throws PortalException {
408:
409: XSLT xslt = XSLT.getTransformer(this , runtimeData.getLocales());
410: analyzeParameters(xslt);
411: //System.out.println ( "registry:\n" + org.jasig.portal.utils.XML.serializeNode(registry));
412: xslt.setXML(registry);
413: xslt.setXSL(sslLocation, "contentSubscriber", runtimeData
414: .getBrowserInfo());
415: xslt.setTarget(out);
416: xslt.setStylesheetParameter("baseActionURL", runtimeData
417: .getBaseActionURL());
418: xslt.transform();
419:
420: }
421:
422: }
|