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: */
018: package org.apache.lenya.cms.usecase;
019:
020: import java.util.HashMap;
021: import java.util.Map;
022:
023: import org.apache.avalon.framework.configuration.Configurable;
024: import org.apache.avalon.framework.configuration.Configuration;
025: import org.apache.avalon.framework.configuration.ConfigurationException;
026: import org.apache.avalon.framework.service.ServiceException;
027: import org.apache.avalon.framework.service.ServiceManager;
028: import org.apache.avalon.framework.service.Serviceable;
029: import org.apache.lenya.cms.usecase.gui.GUIManager;
030: import org.apache.lenya.cms.usecase.gui.Tab;
031:
032: /**
033: * Information about a usecase view.
034: *
035: * @version $Id: UsecaseView.java 587463 2007-10-23 11:58:57Z nettings $
036: * <p>
037: * Example configuration:
038: * <code><pre><view uri="/modules/foo/usecases/foo-mogrify.jx"
039: * customFlow="/modules/foo/flow/myflow.js"
040: * menu="false|true"
041: * createContinuation="false|true"
042: * >
043: * <tab group="foo" name="bar"/> // optional
044: * <parameter name="foo" value="bar/> // optional
045: * </view></pre></code>
046: * </p>
047: * <p>
048: * <code>uri</code> is the relative URL of the page to be sent back to the client. If the URI
049: * starts with a slash, it is resolved starting at the root sitemap, otherwise it
050: * is resolved relative to the current sitemap. The URI should not contain a
051: * scheme (such as cocoon:).
052: * </p>
053: * <p>
054: * <code>menu</code> is a boolean that governs whether the Lenya GUI menu is displayed while
055: * the usecase is running. The displaying of the menu is handled by the usecase.xmap sitemap;
056: * hence this option is only functional if <code>uri</code> does <em>not</em> start with a slash
057: * (or if you implement it yourself based on the <code>showMenu()</code> method of this object).<br>
058: * Default is <em>false</em>.
059: * </p>
060: * <p>
061: * <code>customFlow</code> is a javascript file where you can provide custom methods that will override
062: * those in the default usecase handler (<code>modules-core/usecase/usecases.js</code>).
063: * Currently, it provides support for "customLoopFlow" and "customSubmitFlow". Refer to the default handler
064: * for function prototypes and more information.
065: * NB: the "menu" and "createContinuation" attributes will have no effect when you use custom flow code, unless
066: * you check for them and implement the respective functions yourself.
067: * </p>
068: * <p>
069: * <code>createContinuation</code> can be set to false, in which case the generic flowscript
070: * uses "sendPage" instead of "sendPageAndWait" and terminates after the view has been sent.
071: * When <code>createContinuation</code> is false, you must not specify <code>submitFlow</code>
072: * or <code>loopFlow</code>.<br>
073: * Default is <em>true</em>.
074: * </p>
075: * <p>
076: * For tabbed usecases, you can optionally specify a tab group and name. Additional custom
077: * configuration can be passed via the generic "parameter" element.
078: * </p>
079: * <p>
080: * For backwards compatibility with existing usecases, the constructor looks for a <code>template</code>
081: * attribute if no <code>uri</code> is present. It is mapped to the same field, viewUri, internally.
082: * </p>
083: */
084: public class UsecaseView implements Configurable, Serviceable {
085:
086: protected static final String ATTRIBUTE_URI = "uri";
087: protected static final String ATTRIBUTE_TEMPLATE = "template"; // backwards compatibility, mapped to "uri"
088:
089: protected static final String ATTRIBUTE_CUSTOM_FLOW = "customFlow";
090: protected static final String ATTRIBUTE_SHOW_MENU = "menu";
091: protected static final String ATTRIBUTE_CREATE_CONT = "createContinuation";
092:
093: // additional parameters:
094: protected static final String ELEMENT_PARAMETER = "parameter";
095: protected static final String ATTRIBUTE_NAME = "name";
096: protected static final String ATTRIBUTE_VALUE = "value";
097:
098: // tabbed usecases:
099: protected static final String ATTRIBUTE_GROUP = "group";
100: protected static final String ELEMENT_TAB = "tab";
101:
102: private Map parameters = new HashMap();
103: private ServiceManager manager;
104:
105: private String viewUri;
106: private String customFlow;
107:
108: private boolean showMenu;
109: private boolean createContinuation;
110: private Tab tab;
111:
112: /**
113: * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
114: */
115: public void configure(Configuration config)
116: throws ConfigurationException {
117: // get <view> attributes:
118: this .viewUri = config.getAttribute(ATTRIBUTE_URI, "");
119: if (this .viewUri == "") {
120: // fall back to "template" attribute for backwards compatibility (rip out eventually).
121: this .viewUri = config.getAttribute(ATTRIBUTE_TEMPLATE, "");
122: }
123: this .showMenu = config.getAttributeAsBoolean(
124: ATTRIBUTE_SHOW_MENU, false);
125: this .customFlow = config
126: .getAttribute(ATTRIBUTE_CUSTOM_FLOW, "");
127: this .createContinuation = config.getAttributeAsBoolean(
128: ATTRIBUTE_CREATE_CONT, true);
129:
130: // get <tab/> configuration:
131: Configuration tabConfig = config.getChild(ELEMENT_TAB, false);
132: if (tabConfig != null) {
133: String tabName = tabConfig.getAttribute(ATTRIBUTE_NAME);
134: String tabGroup = tabConfig.getAttribute(ATTRIBUTE_GROUP);
135: GUIManager guiMgr = null;
136: try {
137: guiMgr = (GUIManager) this .manager
138: .lookup(GUIManager.ROLE);
139: this .tab = guiMgr.getTab(tabGroup, tabName);
140: } catch (ServiceException e) {
141: throw new RuntimeException(e);
142: } finally {
143: if (guiMgr != null) {
144: this .manager.release(guiMgr);
145: }
146: }
147: }
148:
149: // get <parameter/> configuration
150: Configuration[] parameterConfigs = config
151: .getChildren(ELEMENT_PARAMETER);
152: for (int i = 0; i < parameterConfigs.length; i++) {
153: String name = parameterConfigs[i]
154: .getAttribute(ATTRIBUTE_NAME);
155: String value = parameterConfigs[i]
156: .getAttribute(ATTRIBUTE_VALUE);
157: this .parameters.put(name, value);
158: }
159:
160: checkConfig();
161:
162: }
163:
164: /**
165: * @return The URI of the JX template;
166: */
167: public String getViewURI() {
168: return this .viewUri;
169: }
170:
171: /**
172: * @return whether the menubar should be visible on usecase screens.
173: */
174: public boolean showMenu() {
175: return this .showMenu;
176: }
177:
178: /**
179: * @return whether a continuation should be created.
180: */
181: public boolean createContinuation() {
182: return this .createContinuation;
183: }
184:
185: /**
186: * @return the Flowscript snippet to be executed during the usecase view loop.
187: */
188: public String getCustomFlow() {
189: return this .customFlow;
190: }
191:
192: /**
193: * @param name The parameter name.
194: * @return The parameter value.
195: */
196: public String getParameter(String name) {
197: return (String) this .parameters.get(name);
198: }
199:
200: /**
201: * @return The tab the usecase belongs to or <code>null</code>.
202: */
203: public Tab getTab() {
204: return this .tab;
205: }
206:
207: /**
208: * @return All tabs in the same group.
209: */
210: public Tab[] getTabsInGroup() {
211: if (getTab() == null) {
212: return null;
213: } else {
214: GUIManager guiMgr = null;
215: try {
216: guiMgr = (GUIManager) this .manager
217: .lookup(GUIManager.ROLE);
218: return guiMgr.getActiveTabs(getTab().getGroup());
219: } catch (ServiceException e) {
220: throw new RuntimeException(e);
221: } finally {
222: if (guiMgr != null) {
223: this .manager.release(guiMgr);
224: }
225: }
226: }
227: }
228:
229: /**
230: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
231: */
232: public void service(ServiceManager manager) throws ServiceException {
233: this .manager = manager;
234: }
235:
236: private void checkConfig() throws ConfigurationException {
237: if (this .tab != null && this .viewUri == "") {
238: throw new ConfigurationException(
239: "When you specify a <tab/>, you must specify a <view uri=\"..\"/> as well!");
240: }
241: }
242: }
|