001/** 002 * 003 * Copyright the original author or authors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * 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 */ 017package org.jivesoftware.smack.provider; 018 019import java.io.InputStream; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.LinkedList; 023import java.util.List; 024import java.util.logging.Level; 025import java.util.logging.Logger; 026 027import org.jivesoftware.smack.packet.ExtensionElement; 028import org.jivesoftware.smack.packet.IQ; 029import org.jivesoftware.smack.util.PacketParserUtils; 030import org.jivesoftware.smack.xml.XmlPullParser; 031 032/** 033 * Loads the {@link IqProvider} and {@link ExtensionElementProvider} information from a standard provider file in preparation 034 * for loading into the {@link ProviderManager}. 035 * 036 * @author Robin Collier 037 * 038 */ 039public class ProviderFileLoader implements ProviderLoader { 040 private static final Logger LOGGER = Logger.getLogger(ProviderFileLoader.class.getName()); 041 042 private final Collection<IQProviderInfo> iqProviders = new LinkedList<IQProviderInfo>(); 043 private final Collection<ExtensionProviderInfo> extProviders = new LinkedList<ExtensionProviderInfo>(); 044 private final Collection<StreamFeatureProviderInfo> sfProviders = new LinkedList<StreamFeatureProviderInfo>(); 045 046 private List<Exception> exceptions = new LinkedList<Exception>(); 047 048 public ProviderFileLoader(InputStream providerStream) { 049 this(providerStream, ProviderFileLoader.class.getClassLoader()); 050 } 051 052 @SuppressWarnings("unchecked") 053 public ProviderFileLoader(InputStream providerStream, ClassLoader classLoader) { 054 // Load processing providers. 055 try (InputStream is = providerStream) { 056 XmlPullParser parser = PacketParserUtils.getParserFor(is); 057 XmlPullParser.Event eventType = parser.getEventType(); 058 do { 059 if (eventType == XmlPullParser.Event.START_ELEMENT) { 060 final String typeName = parser.getName(); 061 062 try { 063 if (!"smackProviders".equals(typeName)) { 064 parser.next(); 065 parser.next(); 066 String elementName = parser.nextText(); 067 parser.next(); 068 parser.next(); 069 String namespace = parser.nextText(); 070 parser.next(); 071 parser.next(); 072 String className = parser.nextText(); 073 074 try { 075 final Class<?> provider = classLoader.loadClass(className); 076 switch (typeName) { 077 case "iqProvider": 078 // Attempt to load the provider class and then create 079 // a new instance if it's an IqProvider. Otherwise, if it's 080 // an IQ class, add the class object itself, then we'll use 081 // reflection later to create instances of the class. 082 // Add the provider to the map. 083 if (IqProvider.class.isAssignableFrom(provider)) { 084 IqProvider<IQ> iqProvider = (IqProvider<IQ>) provider.getConstructor().newInstance(); 085 iqProviders.add(new IQProviderInfo(elementName, namespace, iqProvider)); 086 } 087 else { 088 exceptions.add(new IllegalArgumentException(className + " is not a IqProvider")); 089 } 090 break; 091 case "extensionProvider": 092 // Attempt to load the provider class and then create 093 // a new instance if it's an ExtensionProvider. Otherwise, if it's 094 // a PacketExtension, add the class object itself and 095 // then we'll use reflection later to create instances 096 // of the class. 097 if (ExtensionElementProvider.class.isAssignableFrom(provider)) { 098 ExtensionElementProvider<ExtensionElement> extensionElementProvider = (ExtensionElementProvider<ExtensionElement>) provider.getConstructor().newInstance(); 099 extProviders.add(new ExtensionProviderInfo(elementName, namespace, 100 extensionElementProvider)); 101 } 102 else { 103 exceptions.add(new IllegalArgumentException(className 104 + " is not a PacketExtensionProvider")); 105 } 106 break; 107 case "streamFeatureProvider": 108 ExtensionElementProvider<ExtensionElement> streamFeatureProvider = (ExtensionElementProvider<ExtensionElement>) provider.getConstructor().newInstance(); 109 sfProviders.add(new StreamFeatureProviderInfo(elementName, 110 namespace, 111 streamFeatureProvider)); 112 break; 113 default: 114 LOGGER.warning("Unknown provider type: " + typeName); 115 } 116 } 117 catch (ClassNotFoundException cnfe) { 118 LOGGER.log(Level.SEVERE, "Could not find provider class", cnfe); 119 exceptions.add(cnfe); 120 } 121 catch (InstantiationException ie) { 122 LOGGER.log(Level.SEVERE, "Could not instanciate " + className, ie); 123 exceptions.add(ie); 124 } 125 } 126 } 127 catch (IllegalArgumentException illExc) { 128 LOGGER.log(Level.SEVERE, "Invalid provider type found [" + typeName + "] when expecting iqProvider or extensionProvider", illExc); 129 exceptions.add(illExc); 130 } 131 } 132 eventType = parser.next(); 133 } 134 while (eventType != XmlPullParser.Event.END_DOCUMENT); 135 } 136 catch (Exception e) { 137 LOGGER.log(Level.SEVERE, "Unknown error occurred while parsing provider file", e); 138 exceptions.add(e); 139 } 140 } 141 142 @Override 143 public Collection<IQProviderInfo> getIQProviderInfo() { 144 return iqProviders; 145 } 146 147 @Override 148 public Collection<ExtensionProviderInfo> getExtensionProviderInfo() { 149 return extProviders; 150 } 151 152 @Override 153 public Collection<StreamFeatureProviderInfo> getStreamFeatureProviderInfo() { 154 return sfProviders; 155 } 156 157 public List<Exception> getLoadingExceptions() { 158 return Collections.unmodifiableList(exceptions); 159 } 160}