001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.portal.impl;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.apache.avalon.framework.context.Context;
025: import org.apache.avalon.framework.context.ContextException;
026: import org.apache.avalon.framework.context.Contextualizable;
027: import org.apache.avalon.framework.logger.AbstractLogEnabled;
028: import org.apache.avalon.framework.service.ServiceException;
029: import org.apache.avalon.framework.service.ServiceManager;
030: import org.apache.avalon.framework.service.Serviceable;
031: import org.apache.avalon.framework.thread.ThreadSafe;
032: import org.apache.avalon.framework.CascadingRuntimeException;
033: import org.apache.avalon.framework.activity.Disposable;
034: import org.apache.avalon.framework.component.Component;
035: import org.apache.avalon.framework.configuration.Configurable;
036: import org.apache.avalon.framework.configuration.Configuration;
037: import org.apache.cocoon.portal.PortalService;
038: import org.apache.cocoon.portal.layout.Layout;
039: import org.apache.cocoon.portal.layout.CompositeLayout;
040: import org.apache.cocoon.portal.layout.Item;
041: import org.apache.cocoon.portal.layout.NamedItem;
042: import org.apache.cocoon.portal.event.impl.ChangeAspectDataEvent;
043: import org.apache.cocoon.environment.Request;
044: import org.apache.cocoon.environment.ObjectModelHelper;
045: import org.apache.cocoon.components.ContextHelper;
046:
047: /**
048: * Manages the various activities required for page labels.
049: *
050: * The name of the request parameter used to identify the page labelmay be configured
051: * here by declaring
052: * <br><parameter-name><i>request-parm-name</i></parameter-name><br>
053: * in the configuration for this component. The default request parameter name is
054: * 'pageLabel'.
055: * @author Ralph Goers
056: *
057: * @version CVS $Id: PageLabelManager.java 433543 2006-08-22 06:22:54Z crossley $
058: */
059: public class PageLabelManager extends AbstractLogEnabled implements
060: ThreadSafe, Serviceable, Configurable, Contextualizable,
061: Component, Disposable {
062:
063: public static final String ROLE = PageLabelManager.class.getName();
064:
065: /** The service manager */
066: protected ServiceManager manager;
067: /** The portal Service */
068: protected PortalService service;
069: /** The cocoon context */
070: protected Context context;
071: protected String aspectName = null;
072: private String requestParameterName;
073:
074: //boolean to determine if page label should use directory structure
075: private boolean useUrlPath;
076: private boolean nonStickyTabs;
077: private boolean marshallEvents;
078:
079: protected static final String LABEL_ARRAY = PageLabelManager.class
080: .getName()
081: + "A";
082: protected static final String LABEL_MAP = PageLabelManager.class
083: .getName()
084: + "M";
085: protected static final String EVENT_MAP = PageLabelManager.class
086: .getName()
087: + "E";
088: private static final String DEFAULT_REQUEST_PARAMETER_NAME = "pageLabel";
089:
090: /* (non-Javadoc)
091: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
092: */
093: public void service(ServiceManager manager) throws ServiceException {
094: this .manager = manager;
095: this .service = (PortalService) this .manager
096: .lookup(PortalService.ROLE);
097: }
098:
099: /**
100: * @see org.apache.avalon.framework.activity.Disposable#dispose()
101: */
102: public void dispose() {
103: if (this .manager != null) {
104: this .manager.release(this .service);
105: this .manager = null;
106: }
107: }
108:
109: /* (non-Javadoc)
110: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
111: */
112: public void configure(Configuration config) {
113: this .requestParameterName = config.getChild("parameterName")
114: .getValue(DEFAULT_REQUEST_PARAMETER_NAME);
115: this .aspectName = config.getChild("aspectName").getValue("tab");
116: this .nonStickyTabs = Boolean.valueOf(
117: config.getChild("nonStickyTabs").getValue("false"))
118: .booleanValue();
119: this .marshallEvents = Boolean.valueOf(
120: config.getChild("marshallEvents").getValue("false"))
121: .booleanValue();
122: this .useUrlPath = Boolean.valueOf(
123: config.getChild("urlPath").getValue("false"))
124: .booleanValue();
125: }
126:
127: /* (non-Javadoc)
128: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
129: */
130: public void contextualize(Context context) throws ContextException {
131: this .context = context;
132: }
133:
134: /**
135: * Return the current page label.
136: * @return The current page label.
137: */
138: public String getCurrentLabel() {
139: String[] labels = getLabels();
140:
141: return labels[0];
142: }
143:
144: /**
145: * Return the page label from the previous request.
146: * @return The previous page label.
147: */
148: public String getPreviousLabel() {
149: String[] labels = getLabels();
150:
151: return labels[1];
152: }
153:
154: /**
155: * Sets the current page label.
156: * @return The current page label.
157: */
158: public String setCurrentLabel() {
159: final Request request = ObjectModelHelper
160: .getRequest(ContextHelper.getObjectModel(this .context));
161: String value;
162: if (this .useUrlPath) {
163: value = request.getSitemapURI();
164: if (!isLabel(value)) {
165: value = null;
166: }
167: } else {
168: value = request.getParameter(this .requestParameterName);
169: }
170:
171: String[] labels = getLabels();
172:
173: if (value != null) {
174: labels[1] = labels[0];
175: labels[0] = value;
176: }
177: return labels[0];
178: }
179:
180: /**
181: * Returns whether directory structure should be used
182: * @return A boolean specifying if directory structure should be used.
183: */
184: public boolean isUrlPath() {
185: return this .useUrlPath;
186: }
187:
188: /**
189: * Returns the request parameter being used to identify the page label.
190: * @return A String containing the request parameter name used for page labels.
191: */
192: public String getRequestParameterName() {
193: return this .requestParameterName;
194: }
195:
196: /**
197: * Return the Map that contains events for all the page labels.
198: * @return The Map to use for converting events to and from urls.
199: */
200: public Map getPageEventMap() {
201: PortalService service = null;
202: try {
203: service = (PortalService) this .manager
204: .lookup(PortalService.ROLE);
205: Map map = (Map) service.getAttribute(EVENT_MAP);
206: if (null == map) {
207: map = new HashMap();
208: service.setAttribute(EVENT_MAP, map);
209: }
210:
211: return map;
212: } catch (ServiceException ce) {
213: throw new CascadingRuntimeException(
214: "Unable to lookup component.", ce);
215: } finally {
216: this .manager.release(service);
217: }
218: }
219:
220: /**
221: * Retrieve the events associated with the specified page label.
222: *
223: * @param pageLabel The label to retrieve the events for.
224: * @return A List containing all the events associated with the page label in the order they
225: * should occur.
226: */
227: public List getPageLabelEvents(String pageLabel) {
228: PortalService service = null;
229: try {
230: service = (PortalService) this .manager
231: .lookup(PortalService.ROLE);
232: Map map = (Map) service.getAttribute(LABEL_MAP);
233: if (null == map) {
234: map = initializeLabels(service);
235: service.setAttribute(LABEL_MAP, map);
236: }
237:
238: List list = (List) map.get(pageLabel);
239:
240: if (list == null) {
241: list = new ArrayList();
242: map.put(pageLabel, list);
243: }
244:
245: return list;
246: } catch (ServiceException ce) {
247: throw new CascadingRuntimeException(
248: "Unable to lookup component.", ce);
249: } finally {
250: this .manager.release(service);
251: }
252: }
253:
254: public boolean isLabel(String pageLabel) {
255: PortalService service = null;
256: try {
257: service = (PortalService) this .manager
258: .lookup(PortalService.ROLE);
259: Map map = (Map) service.getAttribute(LABEL_MAP);
260: if (null == map) {
261: map = initializeLabels(service);
262: service.setAttribute(LABEL_MAP, map);
263: }
264:
265: return map.containsKey(pageLabel);
266: } catch (ServiceException ce) {
267: throw new CascadingRuntimeException(
268: "Unable to lookup component.", ce);
269: } finally {
270: this .manager.release(service);
271: }
272: }
273:
274: /**
275: * Returns true if events are not to be exposed as request parameters
276: */
277: public boolean isMarshallEvents() {
278: return this .marshallEvents;
279: }
280:
281: /*
282: * Return the array containing the current and previous labels.
283: */
284: private String[] getLabels() {
285: PortalService service = null;
286: try {
287: service = (PortalService) this .manager
288: .lookup(PortalService.ROLE);
289: String[] labels = (String[]) service
290: .getAttribute(LABEL_ARRAY);
291: if (null == labels) {
292: labels = new String[2];
293: labels[0] = getRoot();
294: service.setAttribute(LABEL_ARRAY, labels);
295: }
296: return labels;
297: } catch (ServiceException ce) {
298: throw new CascadingRuntimeException(
299: "Unable to lookup component.", ce);
300: } finally {
301: this .manager.release(service);
302: }
303: }
304:
305: /**
306: * Create the page label event map and return it.
307: *
308: * @param service The portal service
309: * @return The page label map.
310: */
311: private Map initializeLabels(PortalService service) {
312: Map map = new HashMap();
313:
314: Layout portalLayout = service.getEntryLayout(null);
315: if (portalLayout == null) {
316: portalLayout = service.getComponentManager()
317: .getProfileManager().getPortalLayout(null, null);
318: }
319:
320: if (portalLayout instanceof CompositeLayout) {
321: populate((CompositeLayout) portalLayout, map, "",
322: new ArrayList());
323: }
324:
325: return map;
326: }
327:
328: private String getRoot() {
329: Layout portalLayout = service.getEntryLayout(null);
330: if (portalLayout == null) {
331: portalLayout = service.getComponentManager()
332: .getProfileManager().getPortalLayout(null, null);
333: }
334:
335: if (portalLayout instanceof CompositeLayout) {
336: return getRoot((CompositeLayout) portalLayout,
337: new StringBuffer(""));
338: }
339: return "";
340: }
341:
342: private String getRoot(CompositeLayout layout, StringBuffer root) {
343: for (int j = 0; j < layout.getSize(); j++) {
344: Item tab = layout.getItem(j);
345: if (tab instanceof NamedItem) {
346: if (root.length() > 0) {
347: root.append(".");
348: }
349: root.append(((NamedItem) tab).getName());
350: Layout child = tab.getLayout();
351: if (child != null && child instanceof CompositeLayout) {
352: getRoot((CompositeLayout) child, root);
353: }
354: break;
355: }
356: }
357: return root.toString();
358: }
359:
360: /**
361: * Populate the event map
362: *
363: * @param layout
364: * @param map
365: * @param name
366: * @param parentEvents
367: */
368: private List populate(CompositeLayout layout, Map map, String name,
369: List parentEvents) {
370: List lhList = null;
371: for (int j = 0; j < layout.getSize(); j++) {
372: Item tab = layout.getItem(j);
373: ChangeAspectDataEvent event = new ChangeAspectDataEvent(
374: layout, this .aspectName, new Integer(j));
375: StringBuffer label = new StringBuffer(name);
376: if (label.length() > 0) {
377: label.append(".");
378: }
379: label.append((tab instanceof NamedItem) ? ((NamedItem) tab)
380: .getName() : Integer.toString(j));
381: List events = new ArrayList(parentEvents);
382: events.add(event);
383: Layout child = tab.getLayout();
384: List allEvents = null;
385: if (child != null && child instanceof CompositeLayout) {
386: allEvents = populate((CompositeLayout) child, map,
387: label.toString(), events);
388: }
389: if (this .nonStickyTabs) {
390: // With non-sticky tabs the non-leaf nodes always display
391: // the left-most child tabs
392: if (lhList == null) {
393: if (allEvents != null) {
394: lhList = allEvents;
395: } else {
396: lhList = events;
397: }
398: }
399: if (allEvents != null) {
400: map.put(label.toString(), allEvents);
401: } else {
402: map.put(label.toString(), events);
403: }
404: } else {
405: map.put(label.toString(), events);
406: }
407: }
408: return lhList;
409: }
410: }
|