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.activity.Disposable;
025: import org.apache.avalon.framework.component.Component;
026: import org.apache.avalon.framework.configuration.Configurable;
027: import org.apache.avalon.framework.configuration.Configuration;
028: import org.apache.avalon.framework.context.Context;
029: import org.apache.avalon.framework.context.ContextException;
030: import org.apache.avalon.framework.context.Contextualizable;
031: import org.apache.avalon.framework.logger.AbstractLogEnabled;
032: import org.apache.avalon.framework.service.ServiceException;
033: import org.apache.avalon.framework.service.ServiceManager;
034: import org.apache.avalon.framework.service.Serviceable;
035: import org.apache.avalon.framework.thread.ThreadSafe;
036: import org.apache.cocoon.components.ContextHelper;
037: import org.apache.cocoon.environment.ObjectModelHelper;
038: import org.apache.cocoon.environment.Request;
039: import org.apache.cocoon.portal.PortalService;
040: import org.apache.cocoon.portal.event.impl.ChangeAspectDataEvent;
041: import org.apache.cocoon.portal.layout.CompositeLayout;
042: import org.apache.cocoon.portal.layout.Item;
043: import org.apache.cocoon.portal.layout.Layout;
044: import org.apache.cocoon.portal.layout.NamedItem;
045:
046: /**
047: * Manages the various activities required for page labels.
048: *
049: * The name of the request parameter used to identify the page labelmay be configured
050: * here by declaring
051: * <br><parameter-name><i>request-parm-name</i></parameter-name><br>
052: * in the configuration for this component. The default request parameter name is
053: * 'pageLabel'.
054: * @author Ralph Goers
055: *
056: * @version CVS $Id: PageLabelManager.java 603497 2007-12-12 07:29:01Z cziegeler $
057: */
058: public class PageLabelManager extends AbstractLogEnabled implements
059: ThreadSafe, Serviceable, Configurable, Contextualizable,
060: Component, Disposable {
061:
062: public static final String ROLE = PageLabelManager.class.getName();
063:
064: /** The service manager */
065: protected ServiceManager manager;
066: /** The portal service */
067: protected PortalService portalService;
068: /** The cocoon context */
069: protected Context context;
070: protected String aspectName = null;
071: private String requestParameterName;
072:
073: /** boolean to determine if page label should use directory structure */
074: private boolean useUrlPath;
075: private boolean nonStickyTabs;
076: private boolean marshallEvents;
077:
078: protected static final String LABEL_ARRAY = PageLabelManager.class
079: .getName()
080: + "A";
081: protected static final String LABEL_MAP = "page-labels";
082: protected static final String EVENT_MAP = PageLabelManager.class
083: .getName()
084: + "E";
085: private static final String DEFAULT_REQUEST_PARAMETER_NAME = "pageLabel";
086:
087: /**
088: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
089: */
090: public void service(ServiceManager manager) throws ServiceException {
091: this .manager = manager;
092: this .portalService = (PortalService) this .manager
093: .lookup(PortalService.ROLE);
094: }
095:
096: /**
097: * @see org.apache.avalon.framework.activity.Disposable#dispose()
098: */
099: public void dispose() {
100: if (this .manager != null) {
101: this .manager.release(this .portalService);
102: this .manager = null;
103: }
104: }
105:
106: /* (non-Javadoc)
107: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
108: */
109: public void configure(Configuration config) {
110: this .requestParameterName = config.getChild("parameterName")
111: .getValue(DEFAULT_REQUEST_PARAMETER_NAME);
112: this .aspectName = config.getChild("aspectName").getValue("tab");
113: this .nonStickyTabs = Boolean.valueOf(
114: config.getChild("nonStickyTabs").getValue("false"))
115: .booleanValue();
116: this .marshallEvents = Boolean.valueOf(
117: config.getChild("marshallEvents").getValue("false"))
118: .booleanValue();
119: this .useUrlPath = Boolean.valueOf(
120: config.getChild("urlPath").getValue("false"))
121: .booleanValue();
122: }
123:
124: /* (non-Javadoc)
125: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
126: */
127: public void contextualize(Context context) throws ContextException {
128: this .context = context;
129: }
130:
131: /**
132: * Return the current page label.
133: * @return The current page label.
134: */
135: public String getCurrentLabel() {
136: String[] labels = getLabels();
137:
138: return labels[0];
139: }
140:
141: /**
142: * Return the page label from the previous request.
143: * @return The previous page label.
144: */
145: public String getPreviousLabel() {
146: String[] labels = getLabels();
147:
148: return labels[1];
149: }
150:
151: /**
152: * Sets the current page label.
153: * @return The current page label.
154: */
155: public String setCurrentLabel() {
156: final Request request = ObjectModelHelper
157: .getRequest(ContextHelper.getObjectModel(this .context));
158: String value;
159: if (this .useUrlPath) {
160: value = request.getSitemapURI();
161: if (!isLabel(value)) {
162: value = null;
163: }
164: } else {
165: value = request.getParameter(this .requestParameterName);
166: }
167:
168: String[] labels = getLabels();
169:
170: if (value != null) {
171: labels[1] = labels[0];
172: labels[0] = value;
173: }
174: return labels[0];
175: }
176:
177: /**
178: * Returns whether directory structure should be used
179: * @return A boolean specifying if directory structure should be used.
180: */
181: public boolean isUrlPath() {
182: return this .useUrlPath;
183: }
184:
185: /**
186: * Returns the request parameter being used to identify the page label.
187: * @return A String containing the request parameter name used for page labels.
188: */
189: public String getRequestParameterName() {
190: return this .requestParameterName;
191: }
192:
193: /**
194: * Return the Map that contains events for all the page labels.
195: * @return The Map to use for converting events to and from urls.
196: */
197: public Map getPageEventMap() {
198: Map map = (Map) portalService.getAttribute(EVENT_MAP);
199: if (null == map) {
200: map = new HashMap();
201: portalService.setAttribute(EVENT_MAP, map);
202: }
203:
204: return map;
205: }
206:
207: protected Map getLabelMap() {
208: final Layout rootLayout = portalService.getComponentManager()
209: .getProfileManager().getPortalLayout(null, null);
210: Map map = (Map) rootLayout.getAspectData(LABEL_MAP);
211: if (null == map) {
212: map = this .initializeLabels();
213: rootLayout.setAspectData(LABEL_MAP, map);
214: }
215: return map;
216: }
217:
218: /**
219: * Retrieve the events associated with the specified page label.
220: *
221: * @param pageLabel The label to retrieve the events for.
222: * @return A List containing all the events associated with the page label in the order they
223: * should occur.
224: */
225: public List getPageLabelEvents(String pageLabel) {
226: final Map labelMap = this .getLabelMap();
227: List list = (List) labelMap.get(pageLabel);
228:
229: if (list == null) {
230: list = new ArrayList();
231: labelMap.put(pageLabel, list);
232: }
233:
234: return list;
235: }
236:
237: public boolean isLabel(String pageLabel) {
238: final Map labelMap = this .getLabelMap();
239:
240: return labelMap.containsKey(pageLabel);
241: }
242:
243: /**
244: * Returns true if events are not to be exposed as request parameters
245: */
246: public boolean isMarshallEvents() {
247: return this .marshallEvents;
248: }
249:
250: /**
251: * Return the array containing the current and previous labels.
252: */
253: private String[] getLabels() {
254: String[] labels = (String[]) portalService
255: .getAttribute(LABEL_ARRAY);
256: if (null == labels) {
257: labels = new String[2];
258: labels[0] = getRoot();
259: portalService.setAttribute(LABEL_ARRAY, labels);
260: }
261: return labels;
262: }
263:
264: /**
265: * Create the page label event map and return it.
266: *
267: * @param service The portal service
268: * @return The page label map.
269: */
270: private Map initializeLabels() {
271: final Map map = new HashMap();
272:
273: final Layout portalLayout = portalService.getComponentManager()
274: .getProfileManager().getPortalLayout(null, null);
275:
276: if (portalLayout instanceof CompositeLayout) {
277: this .populate((CompositeLayout) portalLayout, map, "",
278: new ArrayList());
279: }
280:
281: return map;
282: }
283:
284: private String getRoot() {
285: final Layout portalLayout = portalService.getComponentManager()
286: .getProfileManager().getPortalLayout(null, null);
287:
288: if (portalLayout instanceof CompositeLayout) {
289: return getRoot((CompositeLayout) portalLayout,
290: new StringBuffer(""));
291: }
292: return "";
293: }
294:
295: private String getRoot(CompositeLayout layout, StringBuffer root) {
296: for (int j = 0; j < layout.getSize(); j++) {
297: Item tab = layout.getItem(j);
298: if (tab instanceof NamedItem) {
299: if (root.length() > 0) {
300: root.append(".");
301: }
302: root.append(((NamedItem) tab).getName());
303: Layout child = tab.getLayout();
304: if (child != null && child instanceof CompositeLayout) {
305: getRoot((CompositeLayout) child, root);
306: }
307: break;
308: }
309: }
310: return root.toString();
311: }
312:
313: /**
314: * Populate the event map
315: *
316: * @param layout
317: * @param map
318: * @param name
319: * @param parentEvents
320: */
321: private List populate(CompositeLayout layout, Map map, String name,
322: List parentEvents) {
323: List lhList = null;
324: for (int j = 0; j < layout.getSize(); j++) {
325: Item tab = layout.getItem(j);
326: ChangeAspectDataEvent event = new ChangeAspectDataEvent(
327: layout, this .aspectName, new Integer(j));
328: StringBuffer label = new StringBuffer(name);
329: if (label.length() > 0) {
330: label.append(".");
331: }
332: label.append((tab instanceof NamedItem) ? ((NamedItem) tab)
333: .getName() : Integer.toString(j));
334: List events = new ArrayList(parentEvents);
335: events.add(event);
336: Layout child = tab.getLayout();
337: List allEvents = null;
338: if (child != null && child instanceof CompositeLayout) {
339: allEvents = populate((CompositeLayout) child, map,
340: label.toString(), events);
341: }
342: if (this .nonStickyTabs) {
343: // With non-sticky tabs the non-leaf nodes always display
344: // the left-most child tabs
345: if (lhList == null) {
346: if (allEvents != null) {
347: lhList = allEvents;
348: } else {
349: lhList = events;
350: }
351: }
352: if (allEvents != null) {
353: map.put(label.toString(), allEvents);
354: } else {
355: map.put(label.toString(), events);
356: }
357: } else {
358: map.put(label.toString(), events);
359: }
360: }
361: return lhList;
362: }
363: }
|