Java tutorial
/* * Copyright 2004-2007 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 org.grails.plugins; import groovy.util.XmlSlurper; import groovy.util.slurpersupport.GPathResult; import groovy.util.slurpersupport.Node; import java.io.IOException; import java.io.InputStream; import java.util.*; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import grails.core.GrailsApplication; import org.grails.core.exceptions.GrailsConfigurationException; import org.grails.core.io.CachingPathMatchingResourcePatternResolver; import org.grails.io.support.SpringIOUtils; import grails.core.support.ParentApplicationContextAware; import org.springframework.context.ApplicationContext; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.util.StringUtils; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Loads core plugin classes. Contains functionality moved in from <code>DefaultGrailsPluginManager</code>. * * @author Graeme Rocher * @author Phil Zoio */ public class CorePluginFinder implements ParentApplicationContextAware { private static final Log LOG = LogFactory.getLog(CorePluginFinder.class); public static final String CORE_PLUGIN_PATTERN = "classpath*:META-INF/grails-plugin.xml"; private PathMatchingResourcePatternResolver resolver = CachingPathMatchingResourcePatternResolver.INSTANCE; private final Set<Class<?>> foundPluginClasses = new HashSet<Class<?>>(); @SuppressWarnings("unused") private final GrailsApplication application; @SuppressWarnings("rawtypes") private final Map<Class, BinaryGrailsPluginDescriptor> binaryDescriptors = new HashMap<Class, BinaryGrailsPluginDescriptor>(); public CorePluginFinder(GrailsApplication application) { this.application = application; } public Class<?>[] getPluginClasses() { // just in case we try to use this twice foundPluginClasses.clear(); try { Resource[] resources = resolvePluginResources(); if (resources.length > 0) { loadCorePluginsFromResources(resources); } else { throw new IllegalStateException( "Grails was unable to load plugins dynamically. This is normally a problem with the container class loader configuration, see troubleshooting and FAQ for more info. "); } } catch (IOException e) { throw new IllegalStateException( "WARNING: I/O exception loading core plugin dynamically, attempting static load. This is usually due to deployment onto containers with unusual classloading setups. Message: " + e.getMessage()); } return foundPluginClasses.toArray(new Class[foundPluginClasses.size()]); } public BinaryGrailsPluginDescriptor getBinaryDescriptor(Class<?> pluginClass) { return binaryDescriptors.get(pluginClass); } private Resource[] resolvePluginResources() throws IOException { return resolver.getResources(CORE_PLUGIN_PATTERN); } @SuppressWarnings("rawtypes") private void loadCorePluginsFromResources(Resource[] resources) throws IOException { LOG.debug("Attempting to load [" + resources.length + "] core plugins"); try { SAXParser saxParser = SpringIOUtils.newSAXParser(); for (Resource resource : resources) { InputStream input = null; try { input = resource.getInputStream(); PluginHandler ph = new PluginHandler(); saxParser.parse(input, ph); for (String pluginType : ph.pluginTypes) { Class<?> pluginClass = attemptCorePluginClassLoad(pluginType); if (pluginClass != null) { addPlugin(pluginClass); binaryDescriptors.put(pluginClass, new BinaryGrailsPluginDescriptor(resource, ph.pluginClasses)); } } } finally { if (input != null) { input.close(); } } } } catch (ParserConfigurationException e) { throw new GrailsConfigurationException("XML parsing error loading core plugins: " + e.getMessage(), e); } catch (SAXException e) { throw new GrailsConfigurationException("XML parsing error loading core plugins: " + e.getMessage(), e); } } private Class<?> attemptCorePluginClassLoad(String pluginClassName) { try { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); return classLoader.loadClass(pluginClassName); } catch (ClassNotFoundException e) { LOG.warn("[GrailsPluginManager] Core plugin [" + pluginClassName + "] not found, resuming load without.."); if (LOG.isDebugEnabled()) { LOG.debug(e.getMessage(), e); } } return null; } private void addPlugin(Class<?> plugin) { foundPluginClasses.add(plugin); } public void setParentApplicationContext(ApplicationContext parent) { if (parent != null) { resolver = new PathMatchingResourcePatternResolver(parent); } } private enum PluginParseState { PARSING, TYPE, RESOURCE } class PluginHandler extends DefaultHandler { PluginParseState state = PluginParseState.PARSING; List<String> pluginTypes = new ArrayList<>(); List<String> pluginClasses = new ArrayList<>(); private StringBuilder buff = new StringBuilder(); @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (localName.equals("type")) { state = PluginParseState.TYPE; buff = new StringBuilder(); } else if (localName.equals("resource")) { state = PluginParseState.RESOURCE; buff = new StringBuilder(); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { switch (state) { case TYPE: buff.append(String.valueOf(ch, start, length)); break; case RESOURCE: buff.append(String.valueOf(ch, start, length)); break; } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { switch (state) { case TYPE: pluginTypes.add(buff.toString()); break; case RESOURCE: pluginClasses.add(buff.toString()); break; } state = PluginParseState.PARSING; } } }