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.source.impl;
018:
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.Set;
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.logger.AbstractLogEnabled;
027: import org.apache.cocoon.components.source.SourceInspector;
028: import org.apache.cocoon.components.source.helpers.SourceProperty;
029: import org.apache.excalibur.source.Source;
030: import org.apache.excalibur.source.SourceException;
031:
032: /**
033: * Abstract base class for SourceInspectors that want to
034: * configure the set of properties they handle beforehand.
035: *
036: * <p>
037: * Knowing which properties an inspector handles beforehand
038: * greatly improves property management performance.
039: * </p>
040: *
041: * @author <a href="mailto:unico@apache.org">Unico Hommes</a>
042: */
043: public abstract class AbstractConfigurableSourceInspector extends
044: AbstractLogEnabled implements SourceInspector, Configurable {
045:
046: // the set of properties this inspector is configured to handle
047: private Set m_properties;
048:
049: // ---------------------------------------------------- lifecycle
050:
051: public AbstractConfigurableSourceInspector() {
052: }
053:
054: /**
055: * Configure this source inspector to handle properties of required types.
056: * <p>
057: * Configuration is in the form of a set of property elements as follows:<br>
058: * <code><property name="owner" namespace="meta"></code>
059: * </p>
060: */
061: public void configure(Configuration configuration)
062: throws ConfigurationException {
063: final Configuration[] properties = configuration
064: .getChildren("property");
065: m_properties = new HashSet(properties.length);
066: for (int i = 0; i < properties.length; i++) {
067: String namespace = properties[i].getAttribute("namespace");
068: String name = properties[i].getAttribute("name");
069: if (namespace.indexOf('#') != -1 || name.indexOf('#') != -1) {
070: final String message = "Illegal character '#' in definition at "
071: + properties[i].getLocation();
072: throw new ConfigurationException(message);
073: }
074: String property = namespace + "#" + name;
075: if (getLogger().isDebugEnabled()) {
076: getLogger().debug("Handling '" + property + "'");
077: }
078: m_properties.add(property);
079: }
080: }
081:
082: // ---------------------------------------------------- SourceInspector methods
083:
084: /**
085: * Iterates over the configured set of properties to handle,
086: * for each property calls <code>doGetSourceProperty()</code>,
087: * and returns the list of properties thus obtained. Subclasses
088: * may want to overide this behavior to improve performance.
089: */
090: public SourceProperty[] getSourceProperties(Source source)
091: throws SourceException {
092: final Set result = new HashSet();
093: final Iterator properties = m_properties.iterator();
094: while (properties.hasNext()) {
095: String property = (String) properties.next();
096: int index = property.indexOf('#');
097: String namespace = property.substring(0, index);
098: String name = property.substring(index + 1);
099: SourceProperty sp = doGetSourceProperty(source, namespace,
100: name);
101: if (sp != null) {
102: result.add(sp);
103: }
104: }
105: return (SourceProperty[]) result
106: .toArray(new SourceProperty[result.size()]);
107: }
108:
109: /**
110: * Checks if this inspector is configured to handle the requested property
111: * and if so forwards the call to <code>doGetSourceProperty</code>.
112: */
113: public final SourceProperty getSourceProperty(Source source,
114: String namespace, String name) throws SourceException {
115:
116: if (handlesProperty(namespace, name)) {
117: if (getLogger().isDebugEnabled()) {
118: getLogger().debug(
119: "Getting property " + namespace + "#" + name
120: + " for source " + source.getURI());
121: }
122: return doGetSourceProperty(source, namespace, name);
123: }
124: return null;
125: }
126:
127: // ---------------------------------------------------- abstract methods
128:
129: /**
130: * Do the actual work of getting the requested SourceProperty for the given Source.
131: */
132: protected abstract SourceProperty doGetSourceProperty(
133: Source source, String ns, String name)
134: throws SourceException;
135:
136: // ---------------------------------------------------- utility methods
137:
138: /**
139: * Check if this inspector is configured to handle properties of
140: * the given type.
141: */
142: public final boolean handlesProperty(String namespace, String name) {
143: String propname;
144: if (namespace == null) {
145: propname = "#" + name;
146: } else {
147: propname = namespace + "#" + name;
148: }
149: return m_properties.contains(propname);
150: }
151:
152: /**
153: * Provide subclasses access to the set of configured properties.
154: */
155: protected final Set getPropertyTypes() {
156: return m_properties;
157: }
158:
159: }
|