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.components.treeprocessor;
018:
019: import org.apache.avalon.framework.configuration.Configurable;
020: import org.apache.avalon.framework.configuration.Configuration;
021: import org.apache.avalon.framework.configuration.ConfigurationException;
022: import org.apache.cocoon.util.StringUtils;
023:
024: import java.util.ArrayList;
025: import java.util.Arrays;
026: import java.util.Collection;
027: import java.util.List;
028:
029: /**
030: * Base class for parent <code>ProcessingNodeBuilders</code>, providing services for parsing
031: * children nodes.
032: *
033: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
034: * @version CVS $Id: AbstractParentProcessingNodeBuilder.java 433543 2006-08-22 06:22:54Z crossley $
035: */
036: public abstract class AbstractParentProcessingNodeBuilder extends
037: AbstractProcessingNodeBuilder implements Configurable {
038:
039: protected Collection allowedChildren;
040:
041: protected Collection forbiddenChildren;
042:
043: protected Collection ignoredChildren;
044:
045: /**
046: * Configure the sets of allowed, forbidden and ignored children nodes.
047: */
048: public void configure(Configuration config)
049: throws ConfigurationException {
050: this .allowedChildren = getStringCollection(config
051: .getChild("allowed-children"));
052: this .forbiddenChildren = getStringCollection(config
053: .getChild("forbidden-children"));
054: this .ignoredChildren = getStringCollection(config
055: .getChild("ignored-children"));
056: }
057:
058: /**
059: * Checks if a child element and is allowed, and if not throws a <code>ConfigurationException</code>.
060: *
061: * @param child the child configuration to check.
062: * @return <code>true</code> if this child should be considered or <code>false</code>
063: * if it should be ignored.
064: * @throws ConfigurationException if this child isn't allowed.
065: */
066: protected boolean isChild(Configuration child)
067: throws ConfigurationException {
068:
069: checkNamespace(child);
070:
071: String name = child.getName();
072:
073: // Is this a parameter of a parameterizable node builder ?
074: if (isParameter(child)) {
075: return false;
076: }
077:
078: // Is this element to be ignored ?
079: if (ignoredChildren != null && ignoredChildren.contains(name)) {
080: if (getLogger().isDebugEnabled()) {
081: getLogger()
082: .debug(
083: "Element '"
084: + name
085: + "' is ignored for building children of element '"
086: + child.getName() + "'");
087: }
088:
089: return false;
090: }
091:
092: // Is it allowed ?
093: if ((allowedChildren != null && !allowedChildren.contains(name))
094: || (forbiddenChildren != null && forbiddenChildren
095: .contains(name))) {
096: String msg = "Element '" + name + "' is not allowed at "
097: + child.getLocation();
098: throw new ConfigurationException(msg);
099: }
100:
101: return true;
102: }
103:
104: protected boolean isParameter(Configuration config)
105: throws ConfigurationException {
106: String name = config.getName();
107: if (name.equals(this .treeBuilder.getParameterName())) {
108: if (this .hasParameters()) {
109: return true;
110: } else {
111: String msg = "Element '" + name
112: + "' has no parameters at "
113: + config.getLocation();
114: throw new ConfigurationException(msg);
115: }
116: }
117: return false;
118: }
119:
120: /**
121: * Create the <code>ProcessingNode</code>s for the children of a given node.
122: * Child nodes are controlled to be actually allowed in this node.
123: */
124: protected List buildChildNodesList(Configuration config)
125: throws Exception {
126:
127: Configuration[] children = config.getChildren();
128: List result = new ArrayList();
129:
130: for (int i = 0; i < children.length; i++) {
131:
132: Configuration child = children[i];
133: try {
134: if (isChild(child)) {
135: // OK : get a builder.
136: ProcessingNodeBuilder childBuilder = this .treeBuilder
137: .createNodeBuilder(child);
138: result.add(childBuilder.buildNode(child));
139: }
140:
141: } catch (ConfigurationException ce) {
142: throw ce;
143: } catch (Exception e) {
144: String msg = "Error while creating node '"
145: + child.getName() + "' at "
146: + child.getLocation();
147: throw new ConfigurationException(msg, e);
148: }
149: }
150:
151: return result;
152: }
153:
154: protected ProcessingNode[] buildChildNodes(Configuration config)
155: throws Exception {
156: return toNodeArray(buildChildNodesList(config));
157: }
158:
159: /**
160: * Convenience function that converts a <code>List</code> of <code>ProcessingNode</code>s
161: * to an array.
162: */
163: public static ProcessingNode[] toNodeArray(List list) {
164: return (ProcessingNode[]) list.toArray(new ProcessingNode[list
165: .size()]);
166: }
167:
168: /**
169: * Splits the value of a Configuration in a Collection of Strings. Splitting
170: * occurs at space characters (incl. line breaks) and comma.
171: *
172: * @return a collection of Strings, or null if <code>config</code> has no value.
173: */
174: private Collection getStringCollection(Configuration config) {
175: String s = config.getValue(null);
176:
177: return (s == null) ? null : Arrays.asList(StringUtils.split(s,
178: ", \t\n\r"));
179: }
180: }
|