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.Collections;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Set;
025:
026: import org.apache.excalibur.xml.sax.XMLizable;
027:
028: import org.apache.cocoon.forms.FormsException;
029: import org.apache.cocoon.forms.FormsRuntimeException;
030:
031: import org.apache.oro.text.regex.Pattern;
032: import org.outerj.expression.Expression;
033:
034: /**
035: * The {@link WidgetDefinition} part of a AggregateField widget, see {@link AggregateField}
036: * for more information.
037: *
038: * @version $Id: AggregateFieldDefinition.java 449149 2006-09-23 03:58:05Z crossley $
039: */
040: public class AggregateFieldDefinition extends FieldDefinition {
041:
042: /**
043: * Defines expression which combines values of nested fields into this value
044: */
045: private Expression combineExpr;
046:
047: /**
048: * Regular expression which splits this value on the values of the nested fields.
049: * It is compiled into the {@link #splitPattern}.
050: */
051: private String splitRegexp;
052:
053: /**
054: * Compiled pattern out of the {@link #splitRegexp} regular expression.
055: */
056: private Pattern splitPattern;
057:
058: /**
059: * Message to be displayed when the {@link #setSplitPattern(Pattern, String) splitPattern}
060: * does not match what the user entered. Optional.
061: */
062: protected XMLizable splitFailMessage;
063:
064: /**
065: * List containing instances of {@link SplitMapping}, i.e. the mapping between
066: * a group (paren) from the regular expression and corresponding field id.
067: */
068: private List splitMappings = new ArrayList();
069:
070: /**
071: * Set containing widgets mapped to groups to find out if a specific widget has been mapped already
072: */
073: private Set mappedFields = new HashSet();
074:
075: /**
076: *
077: */
078: private WidgetDefinitionList container = new WidgetDefinitionList(
079: this );
080:
081: /**
082: * initialize this definition with the other, sort of like a copy constructor
083: */
084: public void initializeFrom(WidgetDefinition definition)
085: throws Exception {
086: super .initializeFrom(definition);
087:
088: if (!(definition instanceof AggregateFieldDefinition)) {
089: throw new FormsException("Ancestor definition "
090: + definition.getClass().getName()
091: + " is not an AggregateFieldDefinition.",
092: getLocation());
093: }
094:
095: AggregateFieldDefinition other = (AggregateFieldDefinition) definition;
096:
097: this .combineExpr = other.combineExpr;
098: this .splitRegexp = other.splitRegexp;
099: this .splitPattern = other.splitPattern;
100: this .splitFailMessage = other.splitFailMessage;
101:
102: Iterator defs = other.container.getWidgetDefinitions()
103: .iterator();
104: while (defs.hasNext()) {
105: container.addWidgetDefinition((WidgetDefinition) defs
106: .next());
107: }
108:
109: Collections.copy(this .splitMappings, other.splitMappings);
110:
111: Iterator fields = other.mappedFields.iterator();
112: while (fields.hasNext()) {
113: this .mappedFields.add(fields.next());
114: }
115: }
116:
117: public void addWidgetDefinition(WidgetDefinition widgetDefinition)
118: throws DuplicateIdException {
119: checkMutable();
120: container.addWidgetDefinition(widgetDefinition);
121: }
122:
123: /**
124: * checks completeness of this definition
125: */
126: public void checkCompleteness() throws IncompletenessException {
127: super .checkCompleteness();
128:
129: if (this .container.size() == 0) {
130: throw new IncompletenessException("Aggregate field '"
131: + getId() + "' doesn't have any child widgets.",
132: this );
133: }
134:
135: if (this .combineExpr == null) {
136: throw new IncompletenessException("Aggregate field '"
137: + getId() + "' requires combine expression.", this );
138: }
139:
140: if (this .splitPattern == null) {
141: throw new IncompletenessException("Aggregate field '"
142: + getId() + "' requires split regular expression.",
143: this );
144: }
145:
146: if (this .splitMappings.size() == 0) {
147: throw new IncompletenessException(
148: "Aggregate field '"
149: + getId()
150: + "' requires at least one group to field mapping.",
151: this );
152: }
153:
154: // now check children's completeness
155: Iterator i = container.getWidgetDefinitions().iterator();
156: while (i.hasNext()) {
157: ((WidgetDefinition) i.next()).checkCompleteness();
158: }
159: }
160:
161: public boolean hasWidget(String id) {
162: return container.hasWidget(id);
163: }
164:
165: protected void setCombineExpression(Expression expression) {
166: checkMutable();
167: combineExpr = expression;
168: }
169:
170: public Expression getCombineExpression() {
171: return combineExpr;
172: }
173:
174: protected void setSplitPattern(Pattern pattern, String regexp) {
175: checkMutable();
176: this .splitPattern = pattern;
177: this .splitRegexp = regexp;
178: }
179:
180: public Pattern getSplitPattern() {
181: return splitPattern;
182: }
183:
184: public String getSplitRegexp() {
185: return splitRegexp;
186: }
187:
188: public XMLizable getSplitFailMessage() {
189: return splitFailMessage;
190: }
191:
192: protected void setSplitFailMessage(XMLizable splitFailMessage) {
193: checkMutable();
194: this .splitFailMessage = splitFailMessage;
195: }
196:
197: protected void addSplitMapping(int group, String fieldId) {
198: checkMutable();
199:
200: if (mappedFields.contains(fieldId)) {
201: throw new FormsRuntimeException("Field '" + fieldId
202: + "' is already mapped to another group.",
203: getLocation());
204: }
205:
206: mappedFields.add(fieldId);
207:
208: splitMappings.add(new SplitMapping(group, fieldId));
209: }
210:
211: public Iterator getSplitMappingsIterator() {
212: return splitMappings.iterator();
213: }
214:
215: public Widget createInstance() {
216: AggregateField aggregateField = new AggregateField(this );
217:
218: Iterator i = container.getWidgetDefinitions().iterator();
219: while (i.hasNext()) {
220: FieldDefinition fieldDefinition = (FieldDefinition) i
221: .next();
222: aggregateField.addField((Field) fieldDefinition
223: .createInstance());
224: }
225:
226: return aggregateField;
227: }
228:
229: public static class SplitMapping {
230: private int group;
231: private String fieldId;
232:
233: public SplitMapping(int group, String fieldId) {
234: this .group = group;
235: this .fieldId = fieldId;
236: }
237:
238: public int getGroup() {
239: return group;
240: }
241:
242: public String getFieldId() {
243: return fieldId;
244: }
245: }
246: }
|