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.ArrayList; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.LinkedList; 024import java.util.List; 025import java.util.logging.Level; 026import java.util.logging.Logger; 027 028import org.jivesoftware.smack.packet.IQ; 029import org.jivesoftware.smack.packet.PacketExtension; 030import org.xmlpull.v1.XmlPullParserFactory; 031import org.xmlpull.v1.XmlPullParser; 032 033/** 034 * Loads the {@link IQProvider} and {@link PacketExtensionProvider} 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 Collection<IQProviderInfo> iqProviders; 044 private Collection<ExtensionProviderInfo> extProviders; 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 iqProviders = new ArrayList<IQProviderInfo>(); 055 extProviders = new ArrayList<ExtensionProviderInfo>(); 056 057 // Load processing providers. 058 try { 059 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); 060 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 061 parser.setInput(providerStream, "UTF-8"); 062 int eventType = parser.getEventType(); 063 do { 064 if (eventType == XmlPullParser.START_TAG) { 065 String typeName = parser.getName(); 066 067 try { 068 if (!"smackProviders".equals(typeName)) { 069 parser.next(); 070 parser.next(); 071 String elementName = parser.nextText(); 072 parser.next(); 073 parser.next(); 074 String namespace = parser.nextText(); 075 parser.next(); 076 parser.next(); 077 String className = parser.nextText(); 078 079 try { 080 final Class<?> provider = classLoader.loadClass(className); 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 if ("iqProvider".equals(typeName)) { 086 // Add the provider to the map. 087 088 if (IQProvider.class.isAssignableFrom(provider)) { 089 iqProviders.add(new IQProviderInfo(elementName, namespace, (IQProvider) provider.newInstance())); 090 } 091 else if (IQ.class.isAssignableFrom(provider)) { 092 iqProviders.add(new IQProviderInfo(elementName, namespace, (Class<? extends IQ>)provider)); 093 } 094 } 095 else { 096 // Attempt to load the provider class and then create 097 // a new instance if it's an ExtensionProvider. Otherwise, if it's 098 // a PacketExtension, add the class object itself and 099 // then we'll use reflection later to create instances 100 // of the class. 101 if (PacketExtensionProvider.class.isAssignableFrom(provider)) { 102 extProviders.add(new ExtensionProviderInfo(elementName, namespace, (PacketExtensionProvider) provider.newInstance())); 103 } 104 else if (PacketExtension.class.isAssignableFrom(provider)) { 105 extProviders.add(new ExtensionProviderInfo(elementName, namespace, provider)); 106 } 107 } 108 } 109 catch (ClassNotFoundException cnfe) { 110 LOGGER.log(Level.SEVERE, "Could not find provider class", cnfe); 111 exceptions.add(cnfe); 112 } 113 } 114 } 115 catch (IllegalArgumentException illExc) { 116 LOGGER.log(Level.SEVERE, "Invalid provider type found [" + typeName + "] when expecting iqProvider or extensionProvider", illExc); 117 exceptions.add(illExc); 118 } 119 } 120 eventType = parser.next(); 121 } 122 while (eventType != XmlPullParser.END_DOCUMENT); 123 } 124 catch (Exception e){ 125 LOGGER.log(Level.SEVERE, "Unknown error occurred while parsing provider file", e); 126 exceptions.add(e); 127 } 128 finally { 129 try { 130 providerStream.close(); 131 } 132 catch (Exception e) { 133 // Ignore. 134 } 135 } 136 } 137 138 @Override 139 public Collection<IQProviderInfo> getIQProviderInfo() { 140 return iqProviders; 141 } 142 143 @Override 144 public Collection<ExtensionProviderInfo> getExtensionProviderInfo() { 145 return extProviders; 146 } 147 148 public List<Exception> getLoadingExceptions() { 149 return Collections.unmodifiableList(exceptions); 150 } 151}