/* * Copyright 2008-2011 the original author or authors. * * Licensed 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 com.nominanuda.springmvc; import java.util.LinkedList; import java.util.List; import java.util.UUID; import javax.annotation.Nullable; import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import com.nominanuda.urispec.Utils; import com.nominanuda.web.mvc.URISpecMatcher; import com.nominanuda.web.mvc.URITransformerURLStreamer; import com.nominanuda.zen.common.Check; public class MvcFrontControllerBeanDefinitionParser extends AbstractBeanDefinitionParser { private static final String ns = MvcFrontControllerNsHandler.SITEMAP_NS; private static final String beansNs = MvcFrontControllerNsHandler.BEANS_NS; private List<MvcFrontControllerBeanDefinitionParserPlugin> plugins = null; protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { if (plugins == null) { try { initPlugins(parserContext); } catch (Exception e) { throw new IllegalStateException(e); } } BeanDefinitionBuilder bdBuilder = BeanDefinitionBuilder.rootBeanDefinition(HandlerMatcherMapping.class); String pattern = ((Element) element.getElementsByTagNameNS(ns, "pattern").item(0)).getTextContent(); Sitemap.registerPattern(element.getAttribute("id"), pattern, parserContext); String uriSpec = Utils.extracturiSpecFromSitemapMatch(pattern); BeanDefinitionBuilder matchBuilder = BeanDefinitionBuilder .genericBeanDefinition(URISpecMatcher.class) .addPropertyValue("spec", pattern); String matchId = uuid(); parserContext.getRegistry().registerBeanDefinition(matchId, matchBuilder.getBeanDefinition()); bdBuilder.addPropertyReference("handlerMatcher", matchId); matchBuilder.addPropertyReference("handler", generateHandler(element, parserContext, uriSpec)); List<BeanMetadataElement> filters = generateFilterList(element, parserContext, uriSpec); if (filters != null) { matchBuilder.addPropertyValue("handlerFilters", filters); } AbstractBeanDefinition abd = bdBuilder.getBeanDefinition(); abd.setAutowireCandidate(false); return abd; } protected @Nullable List<BeanMetadataElement> generateFilterList(Element element, ParserContext parserContext, String uriSpec) { NodeList nl = element.getElementsByTagNameNS(ns, "filter"); if (nl == null || nl.getLength() == 0) { return null; } List<BeanMetadataElement> l = new ManagedList<BeanMetadataElement>(); for (int i = 0; i < nl.getLength(); i++) { Element filter = (Element)nl.item(i); String ref = getAttribute(filter, "ref"); BeanDefinition bd; if (ref != null) { bd = parserContext.getRegistry().getBeanDefinition(ref); } else { Element innerBean = (Element) filter.getElementsByTagNameNS(beansNs, "bean").item(0); String innerBeanId = getAttribute(innerBean, "id"); if (innerBeanId == null) { innerBeanId = uuid(); } bd = parserContext.getDelegate() .parseBeanDefinitionElement(innerBean) .getBeanDefinition(); parserContext.getRegistry().registerBeanDefinition(innerBeanId, bd); } l.add(Check.notNull(bd)); } return l; } private void initPlugins(ParserContext parserContext) throws InstantiationException, IllegalAccessException { plugins = new LinkedList<MvcFrontControllerBeanDefinitionParserPlugin>(); plugins.add(new HandlerParserPlugin()); plugins.add(new SourceParserPlugin()); String[] beanNames = parserContext.getRegistry().getBeanDefinitionNames(); for (String beanName : beanNames) { BeanDefinition bd = parserContext.getRegistry().getBeanDefinition(beanName); String clsName = bd.getBeanClassName(); if (clsName != null) { try { Class<?> cls = Class.forName(clsName); if (MvcFrontControllerBeanDefinitionParserPlugin.class.isAssignableFrom(cls)) { plugins.add((MvcFrontControllerBeanDefinitionParserPlugin) cls.newInstance()); } } catch (ClassNotFoundException e) { continue; } } } } private String generateHandler(Element element, ParserContext parserContext, String uriSpec) { for (MvcFrontControllerBeanDefinitionParserPlugin p : plugins) { if (p.supports(element)) { return p.generateHandler(element, parserContext, uriSpec); } } throw new IllegalStateException("could not find a suitable plugin for element " + element.getNodeName()); } public static String uuid() { return UUID.randomUUID().toString(); } public static String getAttribute(Element el, String name) { String val = el.getAttribute(name); if (val == null || "".equals(val)) { return null; } return val; } /* handler plugin */ private static class HandlerParserPlugin implements MvcFrontControllerBeanDefinitionParserPlugin { @Override public boolean supports(Element el) { return null != el.getElementsByTagNameNS(ns, "handler").item(0); } @Override public String generateHandler(Element element, ParserContext parserContext, String uriSpec) { Element handler = (Element) element.getElementsByTagNameNS(ns, "handler").item(0); String ref = getAttribute(handler, "ref"); if (ref != null) { return ref; } else { Element innerBean = (Element) handler.getElementsByTagNameNS(beansNs, "bean").item(0); String innerBeanId = getAttribute(innerBean, "id"); if (innerBeanId == null) { innerBeanId = uuid(); } BeanDefinition bd = parserContext.getDelegate() .parseBeanDefinitionElement(innerBean) .getBeanDefinition(); parserContext.getRegistry().registerBeanDefinition(innerBeanId, bd); return innerBeanId; } } } /* source plugin */ private class SourceParserPlugin implements MvcFrontControllerBeanDefinitionParserPlugin { @Override public boolean supports(Element el) { return null != el.getElementsByTagNameNS(ns, "source").item(0); } @Override public String generateHandler(Element element, ParserContext parserContext, String uriSpec) { Element handler = (Element) element.getElementsByTagNameNS(ns, "source").item(0); String url = handler.getElementsByTagNameNS(ns, "url").item(0).getTextContent(); BeanDefinitionBuilder sourceBuilder = BeanDefinitionBuilder .genericBeanDefinition(URITransformerURLStreamer.class) .addPropertyValue("match", uriSpec) .addPropertyValue("template", url); //sourceBuilder.addPropertyReference("urlResolver", "urlResolver"); String id = uuid(); parserContext.getRegistry().registerBeanDefinition(id, sourceBuilder.getBeanDefinition()); return id; } } }