/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.transformation; import java.io.IOException; import java.io.Serializable; import java.util.Map; import org.apache.avalon.framework.activity.Disposable; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.caching.CacheableProcessingComponent; import org.apache.cocoon.components.validation.ValidationHandler; import org.apache.cocoon.components.validation.Validator; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.xml.ContentHandlerWrapper; import org.apache.cocoon.xml.XMLConsumer; import org.apache.cocoon.xml.XMLMulticaster; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceValidity; import org.xml.sax.SAXException; /** * <p>The {@link ValidatingTransformer} provides a very simple {@link Transformer} * validating documents while being processed in a Cocoon pipeline.</p> * * <p>The only defined (but not required) configuration for this component is * <code><grammar><i>...string...</i></grammar></code> * indicating the default grammar language of the schemas to use.</p> * * <p>This configuration parameter can be overridden by specifying the * <code>grammar</code> parameter when using this {@link Transformer} in a * pipeline.</p> * * <p>If no grammar is specified (either as a configuration, or a parameter) this * transformer will instruct the {@link Validator} to try and guess the grammar * of the schema being parsed.</p> * */ public class ValidatingTransformer extends AbstractTransformer implements Configurable, Serviceable, Disposable, CacheableProcessingComponent { /** <p>The configured {@link ServiceManager} instance.</p> */ private ServiceManager serviceManager = null; /** <p>The configured {@link Validator} instance.</p> */ private Validator validator = null; /** <p>The configured default grammar language.</p> */ private String grammar = null; /** <p>The {@link ValidationHandler} to use in this transformation.</p> */ private ValidationHandler handler = null; /** <p>A unique key identifying the schema source for caching.</p> */ private String key = null; /** * <p>Create a new {@link ValidatingTransformer} instance.</p> */ public ValidatingTransformer() { super(); } /** * <p>Contextualize this component instance specifying its associated * {@link ServiceManager} instance.</p> * * @param manager the {@link ServiceManager} to associate with this component. * @throws ServiceException if a dependancy of this could not be resolved. */ public void service(ServiceManager manager) throws ServiceException { this.serviceManager = manager; this.validator = (Validator) manager.lookup(Validator.ROLE); } /** * <p>Configure this component instance.</p> * * <p>The only defined (but not required) configuration for this component is * <code><grammar><i>...string...</i></grammar></code> * indicating the default grammar used by this transformer used for parsing * schemas.</p> * * @param configuration a {@link Configuration} instance for this component. * @throws ConfigurationException never thrown. */ public void configure(Configuration configuration) throws ConfigurationException { this.grammar = configuration.getChild("grammar").getValue(null); } /** * <p>Dispose of this component instance releasing all previously acquired * required instances back to the {@link ServiceManager}.</p> */ public void dispose() { this.serviceManager.release(this.validator); } /** * <p>Contextualize this component in the scope of a pipeline when a request * is processed.</p> * * @param resolver the {@link SourceResolver} contextualized in this request. * @param objectModel unused. * @param source the source URI of the schema to validate against. * @param parameters unused. */ public void setup(SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws ProcessingException, SAXException, IOException { Source s = null; try { s = resolver.resolveURI(source); String g = parameters.getParameter("grammar", this.grammar); if (g == null) { this.handler = this.validator.getValidationHandler(s); } else{ this.handler = this.validator.getValidationHandler(s, g); } } finally { if (source != null) resolver.release(s); } } /** * <p>Specify the {@link XMLConsumer} receiving SAX events emitted by this * {@link Transformer} instance in the scope of a request.</p> * * @param consumer the {@link XMLConsumer} to send SAX events to. */ public void setConsumer(XMLConsumer consumer) { XMLConsumer handler = new ContentHandlerWrapper(this.handler, this.handler); super.setConsumer(new XMLMulticaster(handler, consumer)); } /** * <p>Return the unique key to associated with the schema being processed in * the scope of the request being processed for caching.</p> * * @return a non null {@link String} representing the unique key for the schema. */ public Serializable getKey() { return this.key; } /** * <p>Return the {@link SourceValidity} associated with the schema currently * being processed in the scope of the request being processed.</p> * * @return a non null {@link SourceValidity} instance. */ public SourceValidity getValidity() { return this.handler.getValidity(); } /** * <p>Recycle this component instance at the end of request processing.</p> */ public void recycle() { this.handler = null; this.key = null; super.recycle(); } }