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.forms.formmodel;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.ListIterator;
024: import java.util.Map;
025:
026: import org.apache.cocoon.forms.FormsException;
027: import org.apache.cocoon.forms.FormsRuntimeException;
028: import org.apache.cocoon.util.location.Location;
029:
030: // TODO: Refine and i18n the exception messages.
031: /**
032: * Helper class for the Definition implementation of widgets containing
033: * other widgets.
034: *
035: * @version $Id: WidgetDefinitionList.java 449149 2006-09-23 03:58:05Z crossley $
036: */
037: public class WidgetDefinitionList {
038:
039: private List widgetDefinitions = new ArrayList();
040: private Map widgetDefinitionsById = new HashMap();
041: private WidgetDefinition containerDefinition;
042: private boolean wasHere;
043: private ListIterator definitionsIt = widgetDefinitions
044: .listIterator();
045:
046: /**
047: * @param definition the widget definition to which this container delegate belongs
048: */
049: public WidgetDefinitionList(WidgetDefinition definition) {
050: this .containerDefinition = definition;
051: wasHere = false;
052: }
053:
054: public int size() {
055: return widgetDefinitions.size();
056: }
057:
058: public void addWidgetDefinition(WidgetDefinition widgetDefinition)
059: throws DuplicateIdException {
060: String id = widgetDefinition.getId();
061: // Do not add NewDefinition id's hash.
062: if (!(widgetDefinition instanceof NewDefinition)) {
063: if (widgetDefinitionsById.containsKey(id)) {
064: Location containerLocation = containerDefinition
065: .getLocation();
066: Location firstLocation = getWidgetDefinition(id)
067: .getLocation();
068: throw new DuplicateIdException(
069: "Detected duplicate widget id '"
070: + id
071: + "'.\n"
072: + "Container widget '"
073: + containerDefinition.getId()
074: + "' at "
075: + containerLocation
076: + "\n"
077: + "already contains a widget with the same id at "
078: + firstLocation + ".", widgetDefinition);
079: }
080: widgetDefinitionsById.put(widgetDefinition.getId(),
081: widgetDefinition);
082: }
083: this .definitionsIt.add(widgetDefinition);
084: }
085:
086: public List getWidgetDefinitions() {
087: return widgetDefinitions;
088: }
089:
090: public boolean hasWidget(String id) {
091: return widgetDefinitionsById.containsKey(id);
092: }
093:
094: public WidgetDefinition getWidgetDefinition(String id) {
095: return (WidgetDefinition) widgetDefinitionsById.get(id);
096: }
097:
098: public void resolve(List parents, WidgetDefinition parent)
099: throws Exception {
100: if (!wasHere) {
101: wasHere = true;
102: this .definitionsIt = widgetDefinitions.listIterator();
103: parents.add(containerDefinition);
104: while (this .definitionsIt.hasNext()) {
105: WidgetDefinition widgetDefinition = (WidgetDefinition) this .definitionsIt
106: .next();
107: // ClassDefinition's get resolved by NewDefinition rather than here.
108: if (!(widgetDefinition instanceof ClassDefinition)) {
109: if (widgetDefinition instanceof NewDefinition) {
110: // Remove NewDefinition in preparation for its referenced class of widget definitions to be added.
111: this .definitionsIt.remove();
112: ((NewDefinition) widgetDefinition).resolve(
113: parents, containerDefinition);
114: } else {
115: if (widgetDefinition instanceof ContainerDefinition) {
116: ((ContainerDefinition) widgetDefinition)
117: .resolve(parents,
118: containerDefinition);
119: }
120: }
121: }
122: }
123: parents.remove(parents.size() - 1);
124: wasHere = false;
125: } else {
126: // Non-terminating recursion detection
127: // Search up parent list in hopes of finding a "Union" or "Repeater" before finding previous "New" for this "Class".
128: ListIterator parentsIt = parents.listIterator(parents
129: .size());
130: while (parentsIt.hasPrevious()) {
131: WidgetDefinition widgetDefinition = (WidgetDefinition) parentsIt
132: .previous();
133: if (widgetDefinition instanceof UnionDefinition) {
134: break;
135: }
136: if (widgetDefinition instanceof RepeaterDefinition) {
137: break;
138: }
139: if (widgetDefinition == containerDefinition) {
140: Location location = containerDefinition
141: .getLocation();
142: if (parent instanceof FormDefinition) {
143: throw new FormsException(
144: "Container: Non-terminating recursion detected in form definition.",
145: location);
146: }
147:
148: throw new FormsException(
149: "Container: Non-terminating recursion detected in widget definition: "
150: + parent.getId(), location);
151: }
152: }
153: }
154: }
155:
156: public void createWidget(Widget parent, String id) {
157: WidgetDefinition widgetDefinition = (WidgetDefinition) widgetDefinitionsById
158: .get(id);
159: if (widgetDefinition == null) {
160: throw new FormsRuntimeException(
161: containerDefinition.getId()
162: + ": WidgetDefinition '" + id
163: + "' does not exist.", containerDefinition
164: .getLocation());
165: }
166:
167: Widget widget = widgetDefinition.createInstance();
168: if (widget != null) {
169: ((ContainerWidget) parent).addChild(widget);
170: }
171: }
172:
173: public void createWidgets(Widget parent) {
174: Iterator i = widgetDefinitions.iterator();
175: while (i.hasNext()) {
176: WidgetDefinition widgetDefinition = (WidgetDefinition) i
177: .next();
178: Widget widget = widgetDefinition.createInstance();
179: if (widget != null) {
180: ((ContainerWidget) parent).addChild(widget);
181: }
182: }
183: }
184:
185: public void checkCompleteness() throws IncompletenessException {
186: if (!wasHere) {
187: wasHere = true;
188: // FIXME: is it legal to have no widgets in a container? There are some cases of this in Swan
189: // if(size() == 0)
190: // throw new IncompletenessException(this.containerDefinition.getClass().getName() +
191: // " requires at least one child widget!", this.containerDefinition);
192:
193: // now check children's completeness
194: Iterator i = widgetDefinitions.iterator();
195: while (i.hasNext()) {
196: ((WidgetDefinition) i.next()).checkCompleteness();
197: }
198: wasHere = false;
199: }
200: }
201: }
|