| /* |
| * 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.myfaces.test.config; |
| |
| import org.apache.commons.digester.Digester; |
| import org.apache.commons.digester.Rule; |
| import org.apache.myfaces.test.mock.MockRenderKit; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| |
| import javax.faces.FactoryFinder; |
| import javax.faces.application.Application; |
| import javax.faces.application.ApplicationFactory; |
| import javax.faces.render.RenderKit; |
| import javax.faces.render.RenderKitFactory; |
| import javax.faces.render.Renderer; |
| import java.io.IOException; |
| import java.net.URL; |
| |
| /** |
| * <p>Utility class to parse JavaServer Faces configuration resources, and |
| * register JSF artifacts with the mock object hierarchy.</p> |
| * |
| * <p>The following artifacts are registered:</p> |
| * <ul> |
| * <li><code>Converter</code> (by-id and by-class)</li> |
| * <li><code>RenderKit</code> and <code>Renderer</code></li> |
| * <li><code>UIComponent</code></li> |
| * <li><code>Validator</code></li> |
| * </ul> |
| * |
| * <p>Note that any declared <em>factory</em> instances are explicitly |
| * <strong>NOT</strong> registered, allowing the mock object hierarchy |
| * of the Myfaces Test Framework to manage these APIs.</p> |
| * |
| * <p><strong>USAGE NOTE</strong> - If you are using an instance of this |
| * class within a subclass of <code>AbstractJsfTestCase</code> or |
| * <code>AbstractJmockJsfTestCase</code>, be sure you have completed the |
| * <code>setUp()</code> processing in this base class before calling one |
| * of the <code>parse()</code> methods.</p> |
| * |
| * @since 1.1 |
| */ |
| public class ConfigParser { |
| |
| |
| // ------------------------------------------------------------ Constructors |
| |
| |
| /** Creates a new instance of ConfigParser */ |
| public ConfigParser() { |
| } |
| |
| |
| // ------------------------------------------------------ Manifest Constants |
| |
| |
| /** |
| * <p>Configuration resource URLs for the JSF RI.</p> |
| */ |
| private static final String[] JSFRI_RESOURCES = |
| { "/com/sun/faces/jsf-ri-runtime.xml", |
| }; |
| |
| |
| /** |
| * <p>Configuration resource URLs for Apache MyFaces.</p> |
| */ |
| private static final String[] MYFACES_RESOURCES = |
| { "/org/apache/myfaces/resource/standard-faces-config.xml", |
| }; |
| |
| /** |
| * <p>Configuration resource URLs for Apache MyFaces 1.2.</p> |
| */ |
| private static final String[] MYFACES_RESOURCES12 = |
| { "/META-INF/standard-faces-config.xml", |
| }; |
| |
| // ------------------------------------------------------ Instance Variables |
| |
| |
| /** |
| * <p>The <code>Digester</code> instance we will use for parsing.</p> |
| */ |
| private Digester digester = null; |
| |
| |
| // ------------------------------------------------------- Public Properties |
| |
| |
| /** |
| * <p>Return the URLs of the platform configuration resources for this |
| * application. The following platforms are currently supported:</p> |
| * <ul> |
| * <li>JavaServer Faces Reference Implementation (version 1.0 - 1.2)</li> |
| * <li>MyFaces (version 1.1)</li> |
| * </ul> |
| * |
| * <p>If MyFaces (version 1.2), currently under development, does not change |
| * the name of the configuration resource, it will be supported as well.</p> |
| */ |
| public URL[] getPlatformURLs() { |
| |
| URL[] urls = translate(JSFRI_RESOURCES); |
| if (urls[0] == null) { |
| urls = translate(MYFACES_RESOURCES12); |
| if (urls[0] == null) { |
| urls = translate(MYFACES_RESOURCES); |
| } |
| } |
| return urls; |
| |
| } |
| |
| |
| // ---------------------------------------------------------- Public Methods |
| |
| |
| /** |
| * <p>Parse the specified JavaServer Faces configuration resource, causing |
| * the appropriate JSF artifacts to be registered with the mock object |
| * hierarchy.</p> |
| * |
| * @param url <code>URL</code> of the configuration resource to parse |
| * |
| * @exception IOException if an input/output error occurs |
| * @exception SAXException if a parsing error occurs |
| */ |
| public void parse(URL url) throws IOException, SAXException { |
| |
| // Acquire and configure the Digester instance we will use |
| Digester digester = digester(); |
| ApplicationFactory factory = (ApplicationFactory) |
| FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY); |
| Application application = factory.getApplication(); |
| digester.push(application); |
| |
| // Perform the required parsing |
| try { |
| digester.parse(url); |
| } finally { |
| digester.clear(); |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Parse the specified set of JavaServer Faces configuration resources, |
| * in the listed order, causing the appropriate JSF artifacts to be registered |
| * with the mock object hierarchy.</p> |
| * |
| * @param urls <code>URL</code>s of the configuration resources to parse |
| * |
| * @exception IOException if an input/output error occurs |
| * @exception SAXException if a parsing error occurs |
| */ |
| public void parse(URL[] urls) throws IOException, SAXException { |
| |
| for (int i = 0; i < urls.length; i++) { |
| parse(urls[i]); |
| } |
| |
| } |
| |
| |
| // --------------------------------------------------------- Private Methods |
| |
| |
| /** |
| * <p>Return the <code>Digester</code> instance we will use for parsing, |
| * creating and configuring a new instance if necessary.</p> |
| */ |
| private Digester digester() { |
| |
| if (this.digester == null) { |
| this.digester = new Digester(); |
| digester.addRule("faces-config/component", new ComponentRule()); |
| digester.addCallMethod |
| ("faces-config/component/component-type", "setComponentType", 0); |
| digester.addCallMethod |
| ("faces-config/component/component-class", "setComponentClass", 0); |
| digester.addRule("faces-config/converter", new ConverterRule()); |
| digester.addCallMethod |
| ("faces-config/converter/converter-id", "setConverterId", 0); |
| digester.addCallMethod |
| ("faces-config/converter/converter-class", "setConverterClass", 0); |
| digester.addCallMethod |
| ("faces-config/converter/converter-for-class", "setConverterForClass", 0); |
| digester.addRule("faces-config/render-kit", new RenderKitRule()); |
| digester.addRule("faces-config/render-kit/render-kit-id", new RenderKitIdRule()); |
| digester.addRule("faces-config/render-kit/renderer", new RendererRule()); |
| digester.addCallMethod |
| ("faces-config/render-kit/renderer/component-family", "setComponentFamily", 0); |
| digester.addCallMethod |
| ("faces-config/render-kit/renderer/renderer-class", "setRendererClass", 0); |
| digester.addCallMethod |
| ("faces-config/render-kit/renderer/renderer-type", "setRendererType", 0); |
| digester.addRule("faces-config/validator", new ValidatorRule()); |
| digester.addCallMethod |
| ("faces-config/validator/validator-id", "setValidatorId", 0); |
| digester.addCallMethod |
| ("faces-config/validator/validator-class", "setValidatorClass", 0); |
| } |
| return this.digester; |
| |
| } |
| |
| |
| /** |
| * <p>Translate an array of resource names into an array of resource URLs.</p> |
| * |
| * @param names Resource names to translate |
| */ |
| private URL[] translate(String[] names) { |
| |
| URL[] results = new URL[names.length]; |
| for (int i = 0; i < names.length; i++) { |
| results[i] = this.getClass().getResource(names[i]); |
| } |
| return results; |
| |
| } |
| |
| |
| // --------------------------------------------------------- Private Classes |
| |
| |
| /** |
| * <p>Data bean that stores information related to a component.</p> |
| */ |
| class ComponentBean { |
| |
| private String componentClass; |
| public String getComponentClass() { |
| return this.componentClass; |
| } |
| public void setComponentClass(String componentClass) { |
| this.componentClass = componentClass; |
| } |
| |
| private String componentType; |
| public String getComponentType() { |
| return this.componentType; |
| } |
| public void setComponentType(String componentType) { |
| this.componentType = componentType; |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Digester <code>Rule</code> for processing components.</p> |
| */ |
| class ComponentRule extends Rule { |
| |
| public void begin(String namespace, String name, Attributes attributes) { |
| getDigester().push(new ComponentBean()); |
| } |
| |
| public void end(String namespace, String name) { |
| ComponentBean bean = (ComponentBean) getDigester().pop(); |
| Application application = (Application) getDigester().peek(); |
| application.addComponent(bean.getComponentType(), bean.getComponentClass()); |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Data bean that stores information related to a converter.</p> |
| */ |
| class ConverterBean { |
| |
| private String converterClass; |
| public String getConverterClass() { |
| return this.converterClass; |
| } |
| public void setConverterClass(String converterClass) { |
| this.converterClass = converterClass; |
| } |
| |
| private String converterForClass; |
| public String getConverterForClass() { |
| return this.converterForClass; |
| } |
| public void setConverterForClass(String converterForClass) { |
| this.converterForClass = converterForClass; |
| } |
| |
| private String converterId; |
| public String getConverterId() { |
| return this.converterId; |
| } |
| public void setConverterId(String converterId) { |
| this.converterId = converterId; |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Digester <code>Rule</code> for processing converers.</p> |
| */ |
| class ConverterRule extends Rule { |
| |
| public void begin(String namespace, String name, Attributes attributes) { |
| getDigester().push(new ConverterBean()); |
| } |
| |
| public void end(String namespace, String name) { |
| ConverterBean bean = (ConverterBean) getDigester().pop(); |
| Application application = (Application) getDigester().peek(); |
| if (bean.getConverterId() != null) { |
| application.addConverter(bean.getConverterId(), bean.getConverterClass()); |
| } else { |
| Class clazz = null; |
| try { |
| clazz = this.getClass().getClassLoader().loadClass(bean.getConverterForClass()); |
| } catch (ClassNotFoundException e) { |
| throw new IllegalArgumentException("java.lang.ClassNotFoundException: " |
| + bean.getConverterForClass()); |
| } |
| application.addConverter(clazz, bean.getConverterClass()); |
| } |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Digester <code>Rule</code> for processing render kits.</p> |
| */ |
| class RenderKitRule extends Rule { |
| |
| public void begin(String namespace, String name, Attributes attributes) { |
| RenderKitFactory factory = (RenderKitFactory) |
| FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); |
| getDigester().push(factory.getRenderKit(null, RenderKitFactory.HTML_BASIC_RENDER_KIT)); |
| } |
| |
| public void end(String namespace, String name) { |
| getDigester().pop(); |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Digester <code>Rule</code> for processing render kit identifiers.</p> |
| */ |
| class RenderKitIdRule extends Rule { |
| |
| public void body(String namespace, String name, String text) { |
| String renderKitId = text.trim(); |
| RenderKitFactory factory = (RenderKitFactory) |
| FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); |
| RenderKit renderKit = factory.getRenderKit(null, renderKitId); |
| if (renderKit == null) { |
| renderKit = new MockRenderKit(); |
| factory.addRenderKit(renderKitId, renderKit); |
| } |
| getDigester().pop(); |
| getDigester().push(renderKit); |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Data bean that stores information related to a renderer.</p> |
| */ |
| class RendererBean { |
| |
| private String componentFamily; |
| public String getComponentFamily() { |
| return this.componentFamily; |
| } |
| public void setComponentFamily(String componentFamily) { |
| this.componentFamily = componentFamily; |
| } |
| |
| private String rendererClass; |
| public String getRendererClass() { |
| return this.rendererClass; |
| } |
| public void setRendererClass(String rendererClass) { |
| this.rendererClass = rendererClass; |
| } |
| |
| private String rendererType; |
| public String getRendererType() { |
| return this.rendererType; |
| } |
| public void setRendererType(String rendererType) { |
| this.rendererType = rendererType; |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Digester <code>Rule</code> for processing renderers.</p> |
| */ |
| class RendererRule extends Rule { |
| |
| public void begin(String namespace, String name, Attributes attributes) { |
| getDigester().push(new RendererBean()); |
| } |
| |
| public void end(String namespace, String name) { |
| RendererBean bean = (RendererBean) getDigester().pop(); |
| RenderKit kit = (RenderKit) getDigester().peek(); |
| Renderer renderer = null; |
| Class clazz = null; |
| try { |
| clazz = this.getClass().getClassLoader().loadClass(bean.getRendererClass()); |
| renderer = (Renderer) clazz.newInstance(); |
| } catch (Exception e) { |
| throw new IllegalArgumentException("Exception while trying to instantiate" |
| + " renderer class '" + bean.getRendererClass() + "' : " |
| + e.getMessage()); |
| } |
| kit.addRenderer(bean.getComponentFamily(), bean.getRendererType(), |
| renderer); |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Data bean that stores information related to a validator.</p> |
| */ |
| class ValidatorBean { |
| |
| private String validatorClass; |
| public String getValidatorClass() { |
| return this.validatorClass; |
| } |
| public void setValidatorClass(String validatorClass) { |
| this.validatorClass = validatorClass; |
| } |
| |
| private String validatorId; |
| public String getValidatorId() { |
| return this.validatorId; |
| } |
| public void setValidatorId(String validatorId) { |
| this.validatorId = validatorId; |
| } |
| |
| } |
| |
| |
| /** |
| * <p>Digester <code>Rule</code> for processing validators.</p> |
| */ |
| class ValidatorRule extends Rule { |
| |
| public void begin(String namespace, String name, Attributes attributes) { |
| getDigester().push(new ValidatorBean()); |
| } |
| |
| public void end(String namespace, String name) { |
| ValidatorBean bean = (ValidatorBean) getDigester().pop(); |
| Application application = (Application) getDigester().peek(); |
| application.addValidator(bean.getValidatorId(), bean.getValidatorClass()); |
| } |
| |
| } |
| |
| |
| } |