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