001: package org.apache.turbine.services.intake;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026:
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029:
030: import org.apache.turbine.om.Retrievable;
031: import org.apache.turbine.services.intake.model.Group;
032: import org.apache.turbine.services.pull.ApplicationTool;
033: import org.apache.turbine.util.RunData;
034: import org.apache.turbine.util.TurbineException;
035: import org.apache.turbine.util.parser.ValueParser;
036: import org.apache.turbine.util.pool.Recyclable;
037:
038: /**
039: * The main class through which Intake is accessed.
040: *
041: * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
042: * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
043: * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
044: * @version $Id: IntakeTool.java 534527 2007-05-02 16:10:59Z tv $
045: */
046: public class IntakeTool implements ApplicationTool, Recyclable {
047: /** Used for logging */
048: private static Log log = LogFactory.getLog(IntakeTool.class);
049:
050: /** Constant for default key */
051: public static final String DEFAULT_KEY = "_0";
052:
053: /** Constant for the hidden fieldname */
054: public static final String INTAKE_GRP = "intake-grp";
055:
056: /** Groups from intake.xml */
057: private HashMap groups;
058:
059: /** ValueParser instance */
060: private ValueParser pp;
061:
062: HashMap declaredGroups = new HashMap();
063: StringBuffer allGroupsSB = new StringBuffer(256);
064: StringBuffer groupSB = new StringBuffer(128);
065:
066: /** The cache of PullHelpers. **/
067: private Map pullMap;
068:
069: /**
070: * Constructor
071: */
072: public IntakeTool() {
073: String[] groupNames = TurbineIntake.getGroupNames();
074: int groupCount = 0;
075: if (groupNames != null) {
076: groupCount = groupNames.length;
077: }
078: groups = new HashMap((int) (1.25 * groupCount + 1));
079: pullMap = new HashMap((int) (1.25 * groupCount + 1));
080:
081: for (int i = groupCount - 1; i >= 0; i--) {
082: pullMap.put(groupNames[i], new PullHelper(groupNames[i]));
083: }
084: }
085:
086: /**
087: * Prepares intake for a single request
088: */
089: public void init(Object runData) {
090: this .pp = ((RunData) runData).getParameters();
091:
092: String[] groupKeys = pp.getStrings(INTAKE_GRP);
093: String[] groupNames = null;
094: if (groupKeys == null || groupKeys.length == 0) {
095: groupNames = TurbineIntake.getGroupNames();
096: } else {
097: groupNames = new String[groupKeys.length];
098: for (int i = groupKeys.length - 1; i >= 0; i--) {
099: groupNames[i] = TurbineIntake
100: .getGroupName(groupKeys[i]);
101: }
102:
103: }
104:
105: for (int i = groupNames.length - 1; i >= 0; i--) {
106: try {
107: List foundGroups = TurbineIntake
108: .getGroup(groupNames[i]).getObjects(pp);
109:
110: if (foundGroups != null) {
111: for (Iterator iter = foundGroups.iterator(); iter
112: .hasNext();) {
113: Group group = (Group) iter.next();
114: groups.put(group.getObjectKey(), group);
115: }
116: }
117: } catch (Exception e) {
118: log.error(e);
119: }
120: }
121: }
122:
123: public void addGroupsToParameters(ValueParser vp) {
124: for (Iterator i = groups.values().iterator(); i.hasNext();) {
125: Group group = (Group) i.next();
126: if (!declaredGroups.containsKey(group.getIntakeGroupName())) {
127: declaredGroups.put(group.getIntakeGroupName(), null);
128: vp.add("intake-grp", group.getGID());
129: }
130: vp.add(group.getGID(), group.getOID());
131: }
132: declaredGroups.clear();
133: }
134:
135: /**
136: * A convenience method to write out the hidden form fields
137: * that notify intake of the relevant groups. It should be used
138: * only in templates with 1 form. In multiform templates, the groups
139: * that are relevant for each form need to be declared using
140: * $intake.newForm() and $intake.declareGroup($group) for the relevant
141: * groups in the form.
142: *
143: */
144: public String declareGroups() {
145: allGroupsSB.setLength(0);
146: for (Iterator i = groups.values().iterator(); i.hasNext();) {
147: declareGroup((Group) i.next(), allGroupsSB);
148: }
149: return allGroupsSB.toString();
150: }
151:
152: /**
153: * A convenience method to write out the hidden form fields
154: * that notify intake of the group.
155: */
156: public String declareGroup(Group group) {
157: groupSB.setLength(0);
158: declareGroup(group, groupSB);
159: return groupSB.toString();
160: }
161:
162: /**
163: * xhtml valid hidden input field(s) that notifies intake of the
164: * group's presence.
165: */
166: public void declareGroup(Group group, StringBuffer sb) {
167: if (!declaredGroups.containsKey(group.getIntakeGroupName())) {
168: declaredGroups.put(group.getIntakeGroupName(), null);
169: sb.append("<input type=\"hidden\" name=\"").append(
170: INTAKE_GRP).append("\" value=\"").append(
171: group.getGID()).append("\"/>\n");
172: }
173: group.appendHtmlFormInput(sb);
174: }
175:
176: public void newForm() {
177: declaredGroups.clear();
178: for (Iterator i = groups.values().iterator(); i.hasNext();) {
179: ((Group) i.next()).resetDeclared();
180: }
181: }
182:
183: /**
184: * Implementation of ApplicationTool interface is not needed for this
185: * tool as it is request scoped
186: */
187: public void refresh() {
188: // empty
189: }
190:
191: /**
192: * Inner class to present a nice interface to the template designer
193: */
194: public class PullHelper {
195: /** Name of the group used by the pull helper */
196: String groupName;
197:
198: /**
199: * Private constructor to force use of factory method.
200: *
201: * @param groupName
202: */
203: private PullHelper(String groupName) {
204: this .groupName = groupName;
205: }
206:
207: /**
208: * Populates the object with the default values from the XML File
209: *
210: * @return a Group object with the default values
211: * @throws IntakeException
212: */
213: public Group getDefault() throws IntakeException {
214: return setKey(DEFAULT_KEY);
215: }
216:
217: /**
218: * Calls setKey(key,true)
219: *
220: * @param key
221: * @return an Intake Group
222: * @throws IntakeException
223: */
224: public Group setKey(String key) throws IntakeException {
225: return setKey(key, true);
226: }
227:
228: /**
229: *
230: * @param key
231: * @param create
232: * @return an Intake Group
233: * @throws IntakeException
234: */
235: public Group setKey(String key, boolean create)
236: throws IntakeException {
237: Group g = null;
238:
239: String inputKey = TurbineIntake.getGroupKey(groupName)
240: + key;
241: if (groups.containsKey(inputKey)) {
242: g = (Group) groups.get(inputKey);
243: } else if (create) {
244: g = TurbineIntake.getGroup(groupName);
245: groups.put(inputKey, g);
246: g.init(key, pp);
247: }
248:
249: return g;
250: }
251:
252: /**
253: * maps an Intake Group to the values from a Retrievable object.
254: *
255: * @param obj A retrievable object
256: * @return an Intake Group
257: */
258: public Group mapTo(Retrievable obj) throws IntakeException {
259: Group g = null;
260:
261: try {
262: String inputKey = TurbineIntake.getGroupKey(groupName)
263: + obj.getQueryKey();
264: if (groups.containsKey(inputKey)) {
265: g = (Group) groups.get(inputKey);
266: } else {
267: g = TurbineIntake.getGroup(groupName);
268: groups.put(inputKey, g);
269: }
270: return g.init(obj);
271: } catch (Exception e) {
272: log.error(e);
273: }
274:
275: return null;
276: }
277: }
278:
279: /**
280: * get a specific group
281: */
282: public PullHelper get(String groupName) throws IntakeException {
283: return (PullHelper) pullMap.get(groupName);
284: }
285:
286: /**
287: * Get a specific group
288: *
289: * @param throwExceptions if false, exceptions will be supressed.
290: * @throws IntakeException could not retrieve group
291: */
292: public PullHelper get(String groupName, boolean throwExceptions)
293: throws IntakeException {
294: return (PullHelper) pullMap.get(groupName);
295: }
296:
297: /**
298: * Loops through all of the Groups and checks to see if
299: * the data within the Group is valid.
300: */
301: public boolean isAllValid() {
302: boolean allValid = true;
303: for (Iterator iter = groups.values().iterator(); iter.hasNext();) {
304: Group group = (Group) iter.next();
305: allValid &= group.isAllValid();
306: }
307: return allValid;
308: }
309:
310: /**
311: * Get a specific group by name and key.
312: */
313: public Group get(String groupName, String key)
314: throws IntakeException {
315: if (groupName == null) {
316: throw new IntakeException("Intake.get: groupName == null");
317: }
318: if (key == null) {
319: throw new IntakeException("Intake.get: key == null");
320: }
321:
322: PullHelper ph = get(groupName);
323: return (ph == null) ? null : ph.setKey(key);
324: }
325:
326: /**
327: * Get a specific group by name and key. Also specify
328: * whether or not you want to create a new group.
329: */
330: public Group get(String groupName, String key, boolean create)
331: throws IntakeException {
332: if (groupName == null) {
333: throw new IntakeException("Intake.get: groupName == null");
334: }
335: if (key == null) {
336: throw new IntakeException("Intake.get: key == null");
337: }
338:
339: PullHelper ph = get(groupName);
340: return (ph == null) ? null : ph.setKey(key, create);
341: }
342:
343: /**
344: * Removes group. Primary use is to remove a group that has
345: * been processed by an action and is no longer appropriate
346: * in the view (screen).
347: */
348: public void remove(Group group) {
349: if (group != null) {
350: groups.remove(group.getObjectKey());
351: group.removeFromRequest();
352:
353: String[] groupKeys = pp.getStrings(INTAKE_GRP);
354:
355: pp.remove(INTAKE_GRP);
356:
357: if (groupKeys != null) {
358: for (int i = 0; i < groupKeys.length; i++) {
359: if (!groupKeys[i].equals(group.getGID())) {
360: pp.add(INTAKE_GRP, groupKeys[i]);
361: }
362: }
363: }
364:
365: try {
366: TurbineIntake.releaseGroup(group);
367: } catch (TurbineException se) {
368: log.error("Tried to release unknown group "
369: + group.getIntakeGroupName());
370: }
371: }
372: }
373:
374: /**
375: * Removes all groups. Primary use is to remove groups that have
376: * been processed by an action and are no longer appropriate
377: * in the view (screen).
378: */
379: public void removeAll() {
380: Object[] allGroups = groups.values().toArray();
381: for (int i = allGroups.length - 1; i >= 0; i--) {
382: Group group = (Group) allGroups[i];
383: remove(group);
384: }
385: }
386:
387: /**
388: * Get a Map containing all the groups.
389: *
390: * @return the Group Map
391: */
392: public Map getGroups() {
393: return groups;
394: }
395:
396: // ****************** Recyclable implementation ************************
397:
398: private boolean disposed;
399:
400: /**
401: * Recycles the object for a new client. Recycle methods with
402: * parameters must be added to implementing object and they will be
403: * automatically called by pool implementations when the object is
404: * taken from the pool for a new client. The parameters must
405: * correspond to the parameters of the constructors of the object.
406: * For new objects, constructors can call their corresponding recycle
407: * methods whenever applicable.
408: * The recycle methods must call their super.
409: */
410: public void recycle() {
411: disposed = false;
412: }
413:
414: /**
415: * Disposes the object after use. The method is called
416: * when the object is returned to its pool.
417: * The dispose method must call its super.
418: */
419: public void dispose() {
420: for (Iterator iter = groups.values().iterator(); iter.hasNext();) {
421: Group g = (Group) iter.next();
422:
423: try {
424: TurbineIntake.releaseGroup(g);
425: } catch (TurbineException se) {
426: log.error("Tried to release unknown group "
427: + g.getIntakeGroupName());
428: }
429: }
430:
431: groups.clear();
432: declaredGroups.clear();
433: pp = null;
434:
435: disposed = true;
436: }
437:
438: /**
439: * Checks whether the recyclable has been disposed.
440: *
441: * @return true, if the recyclable is disposed.
442: */
443: public boolean isDisposed() {
444: return disposed;
445: }
446: }
|