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.transformation;
018:
019: import java.io.IOException;
020: import java.io.Serializable;
021: import java.util.Map;
022:
023: import org.apache.avalon.framework.activity.Disposable;
024: import org.apache.avalon.framework.configuration.Configurable;
025: import org.apache.avalon.framework.configuration.Configuration;
026: import org.apache.avalon.framework.configuration.ConfigurationException;
027: import org.apache.avalon.framework.parameters.Parameters;
028: import org.apache.avalon.framework.service.ServiceException;
029: import org.apache.avalon.framework.service.ServiceManager;
030: import org.apache.avalon.framework.service.Serviceable;
031: import org.apache.cocoon.ProcessingException;
032: import org.apache.cocoon.caching.CacheableProcessingComponent;
033: import org.apache.cocoon.components.validation.ValidationHandler;
034: import org.apache.cocoon.components.validation.Validator;
035: import org.apache.cocoon.environment.SourceResolver;
036: import org.apache.cocoon.xml.ContentHandlerWrapper;
037: import org.apache.cocoon.xml.XMLConsumer;
038: import org.apache.cocoon.xml.XMLMulticaster;
039: import org.apache.excalibur.source.Source;
040: import org.apache.excalibur.source.SourceValidity;
041: import org.xml.sax.SAXException;
042:
043: /**
044: * <p>The {@link ValidatingTransformer} provides a very simple {@link Transformer}
045: * validating documents while being processed in a Cocoon pipeline.</p>
046: *
047: * <p>The only defined (but not required) configuration for this component is
048: * <code><grammar><i>...string...</i></grammar></code>
049: * indicating the default grammar language of the schemas to use.</p>
050: *
051: * <p>This configuration parameter can be overridden by specifying the
052: * <code>grammar</code> parameter when using this {@link Transformer} in a
053: * pipeline.</p>
054: *
055: * <p>If no grammar is specified (either as a configuration, or a parameter) this
056: * transformer will instruct the {@link Validator} to try and guess the grammar
057: * of the schema being parsed.</p>
058: *
059: */
060: public class ValidatingTransformer extends AbstractTransformer
061: implements Configurable, Serviceable, Disposable,
062: CacheableProcessingComponent {
063:
064: /** <p>The configured {@link ServiceManager} instance.</p> */
065: private ServiceManager serviceManager = null;
066: /** <p>The configured {@link Validator} instance.</p> */
067: private Validator validator = null;
068: /** <p>The configured default grammar language.</p> */
069: private String grammar = null;
070:
071: /** <p>The {@link ValidationHandler} to use in this transformation.</p> */
072: private ValidationHandler handler = null;
073: /** <p>A unique key identifying the schema source for caching.</p> */
074: private String key = null;
075:
076: /**
077: * <p>Create a new {@link ValidatingTransformer} instance.</p>
078: */
079: public ValidatingTransformer() {
080: super ();
081: }
082:
083: /**
084: * <p>Contextualize this component instance specifying its associated
085: * {@link ServiceManager} instance.</p>
086: *
087: * @param manager the {@link ServiceManager} to associate with this component.
088: * @throws ServiceException if a dependancy of this could not be resolved.
089: */
090: public void service(ServiceManager manager) throws ServiceException {
091: this .serviceManager = manager;
092: this .validator = (Validator) manager.lookup(Validator.ROLE);
093: }
094:
095: /**
096: * <p>Configure this component instance.</p>
097: *
098: * <p>The only defined (but not required) configuration for this component is
099: * <code><grammar><i>...string...</i></grammar></code>
100: * indicating the default grammar used by this transformer used for parsing
101: * schemas.</p>
102: *
103: * @param configuration a {@link Configuration} instance for this component.
104: * @throws ConfigurationException never thrown.
105: */
106: public void configure(Configuration configuration)
107: throws ConfigurationException {
108: this .grammar = configuration.getChild("grammar").getValue(null);
109: }
110:
111: /**
112: * <p>Dispose of this component instance releasing all previously acquired
113: * required instances back to the {@link ServiceManager}.</p>
114: */
115: public void dispose() {
116: this .serviceManager.release(this .validator);
117: }
118:
119: /**
120: * <p>Contextualize this component in the scope of a pipeline when a request
121: * is processed.</p>
122: *
123: * @param resolver the {@link SourceResolver} contextualized in this request.
124: * @param objectModel unused.
125: * @param source the source URI of the schema to validate against.
126: * @param parameters unused.
127: */
128: public void setup(SourceResolver resolver, Map objectModel,
129: String source, Parameters parameters)
130: throws ProcessingException, SAXException, IOException {
131: Source s = null;
132: try {
133: s = resolver.resolveURI(source);
134: String g = parameters.getParameter("grammar", this .grammar);
135: if (g == null) {
136: this .handler = this .validator.getValidationHandler(s);
137: } else {
138: this .handler = this .validator
139: .getValidationHandler(s, g);
140: }
141: } finally {
142: if (source != null)
143: resolver.release(s);
144: }
145: }
146:
147: /**
148: * <p>Specify the {@link XMLConsumer} receiving SAX events emitted by this
149: * {@link Transformer} instance in the scope of a request.</p>
150: *
151: * @param consumer the {@link XMLConsumer} to send SAX events to.
152: */
153: public void setConsumer(XMLConsumer consumer) {
154: XMLConsumer handler = new ContentHandlerWrapper(this .handler,
155: this .handler);
156: super .setConsumer(new XMLMulticaster(handler, consumer));
157: }
158:
159: /**
160: * <p>Return the unique key to associated with the schema being processed in
161: * the scope of the request being processed for caching.</p>
162: *
163: * @return a non null {@link String} representing the unique key for the schema.
164: */
165: public Serializable getKey() {
166: return this .key;
167: }
168:
169: /**
170: * <p>Return the {@link SourceValidity} associated with the schema currently
171: * being processed in the scope of the request being processed.</p>
172: *
173: * @return a non null {@link SourceValidity} instance.
174: */
175: public SourceValidity getValidity() {
176: return this .handler.getValidity();
177: }
178:
179: /**
180: * <p>Recycle this component instance at the end of request processing.</p>
181: */
182: public void recycle() {
183: this.handler = null;
184: this.key = null;
185: super.recycle();
186: }
187: }
|