/* ********************************************************************** ** ** Copyright notice ** ** ** ** (c) 2005-2009 RSSOwl Development Team ** ** http://www.rssowl.org/ ** ** ** ** All rights reserved ** ** ** ** This program and the accompanying materials are made available under ** ** the terms of the Eclipse Public License v1.0 which accompanies this ** ** distribution, and is available at: ** ** http://www.rssowl.org/legal/epl-v10.html ** ** ** ** A copy is found in the file epl-v10.html and important notices to the ** ** license from the team is found in the textfile LICENSE.txt distributed ** ** in this package. ** ** ** ** This copyright notice MUST APPEAR in all copies of the file! ** ** ** ** Contributors: ** ** RSSOwl Development Team - initial API and implementation ** ** ** ** ********************************************************************** */ package org.rssowl.core.internal.interpreter; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.InvalidRegistryObjectException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.osgi.util.NLS; import org.jdom.Document; import org.jdom.input.DOMBuilder; import org.rssowl.core.internal.Activator; import org.rssowl.core.internal.interpreter.json.JSONInterpreter; import org.rssowl.core.internal.interpreter.json.JSONObject; import org.rssowl.core.interpreter.IElementHandler; import org.rssowl.core.interpreter.IFormatInterpreter; import org.rssowl.core.interpreter.IInterpreterService; import org.rssowl.core.interpreter.INamespaceHandler; import org.rssowl.core.interpreter.ITypeExporter; import org.rssowl.core.interpreter.ITypeExporter.Options; import org.rssowl.core.interpreter.ITypeImporter; import org.rssowl.core.interpreter.IXMLParser; import org.rssowl.core.interpreter.InterpreterException; import org.rssowl.core.interpreter.ParserException; import org.rssowl.core.interpreter.UnknownFormatException; import org.rssowl.core.persist.IEntity; import org.rssowl.core.persist.IFeed; import org.rssowl.core.persist.IFolderChild; import org.rssowl.core.util.ExtensionUtils; import java.io.File; import java.io.InputStream; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * <p> * Main class of the Interpreter. A contributed or default-JDKs XML-Parser is * used to parse the given InputStream into a <code>org.jdom.Document</code>. * The Document is then passed to the Contribution responsible for the given * Format. * </p> * The following kind of Extensions are possible: * <ul> * <li>SAXParser allows to contribute the XML Parser to be used</li> * <li>FormatInterpreter allow to contribute Interpreters based on a XML Format</li> * <li>NamespaceHandler allow to contribute processing for Namespaces</li> * <li>ElementHandler allow to contribute custom processing for Elements</li> * </ul> * * @author bpasero */ public class InterpreterServiceImpl implements IInterpreterService { /* ID for SAXParser Contribution */ private static final String SAXPARSER_EXTENSION_POINT = "org.rssowl.core.XMLParser"; //$NON-NLS-1$ /* ID for FormatInterpreter Contributions */ private static final String FORMATINTERPRETER_EXTENSION_POINT = "org.rssowl.core.FormatInterpreter"; //$NON-NLS-1$ /* ID for TypeImporter Contributions */ private static final String TYPEIMPORTER_EXTENSION_POINT = "org.rssowl.core.TypeImporter"; //$NON-NLS-1$ /* ID for TypeExporter Contributions */ private static final String TYPEEXPORTER_EXTENSION_POINT = "org.rssowl.core.TypeExporter"; //$NON-NLS-1$ /* ID for NamespaceHandler Contributions */ private static final String NSHANDLER_EXTENSION_POINT = "org.rssowl.core.NamespaceHandler"; //$NON-NLS-1$ /* ID for ElementHandler Contributions */ private static final String ELHANDLER_EXTENSION_POINT = "org.rssowl.core.ElementHandler"; //$NON-NLS-1$ private volatile Map<String, IFormatInterpreter> fFormatInterpreters; private volatile Map<String, ITypeImporter> fTypeImporters; private volatile Map<String, ITypeExporter> fTypeExporters; private volatile Map<String, INamespaceHandler> fNamespaceHandlers; private volatile Map<String, IElementHandler> fElementHandlers; private volatile IXMLParser fXMLParserImpl; private ITypeExporter fDefaultExporter = new OPMLExporter(); /** */ public InterpreterServiceImpl() { startup(); } /* * @see * org.rssowl.core.interpreter.IInterpreterService#interpret(java.io.InputStream * , org.rssowl.core.persist.IFeed, java.util.Map) */ public void interpret(InputStream inS, IFeed feed, Map<Object, Object> properties) throws ParserException, InterpreterException { Document document = fXMLParserImpl.parse(inS, properties); if (document != null) interpretJDomDocument(document, feed); } /* * @see * org.rssowl.core.interpreter.IInterpreterService#interpretW3CDocument(org * .w3c.dom.Document, org.rssowl.core.model.persist.IFeed) */ public void interpretW3CDocument(org.w3c.dom.Document w3cDocument, IFeed feed) throws InterpreterException { DOMBuilder domBuilder = new DOMBuilder(); Document jDomDocument = domBuilder.build(w3cDocument); if (jDomDocument != null) interpretJDomDocument(jDomDocument, feed); } /* * @see * org.rssowl.core.interpreter.IInterpreterService#interpretJDomDocument(org * .jdom.Document, org.rssowl.core.model.persist.IFeed) */ public void interpretJDomDocument(Document document, IFeed feed) throws InterpreterException { /* A Root Element is required */ if (!document.hasRootElement()) throw new InterpreterException(Activator.getDefault().createErrorStatus(Messages.InterpreterServiceImpl_ERROR_NO_ROOT_ELEMENT, null)); /* Determine Format of the Feed */ String format = document.getRootElement().getName().toLowerCase(); /* A Interpreter is required */ if (!fFormatInterpreters.containsKey(format)) throw new UnknownFormatException(Activator.getDefault().createErrorStatus(NLS.bind(Messages.InterpreterServiceImpl_ERROR_NO_INTERPRETER_FOUND, format), null), format); /* Interpret Document into a Feed */ fFormatInterpreters.get(format).interpret(document, feed); } /* * @see * org.rssowl.core.interpreter.IInterpreterService#interpretJSONObject(org * .rssowl.core.internal.interpreter.json.JSONObject, * org.rssowl.core.persist.IFeed) */ public void interpretJSONObject(JSONObject json, IFeed feed) throws InterpreterException { new JSONInterpreter().interpret(json, feed); } /* * @see * org.rssowl.core.interpreter.IInterpreterService#importFrom(java.io.InputStream * ) */ public List<IEntity> importFrom(InputStream inS) throws InterpreterException, ParserException { Document document = fXMLParserImpl.parse(inS, null); /* A Root Element is required */ if (!document.hasRootElement()) throw new InterpreterException(Activator.getDefault().createErrorStatus(Messages.InterpreterServiceImpl_ERROR_NO_ROOT_ELEMENT, null)); /* Determine Format of the Feed */ String format = document.getRootElement().getName().toLowerCase(); /* An Importer is required */ if (!fTypeImporters.containsKey(format)) throw new UnknownFormatException(Activator.getDefault().createErrorStatus(NLS.bind(Messages.InterpreterServiceImpl_ERROR_NO_IMPORTER_FOUND, format), null), format); /* Import Type from the Document */ return fTypeImporters.get(format).importFrom(document); } /* * @see org.rssowl.core.interpreter.IInterpreterService#exportTo(java.io.File, * java.util.Collection, java.util.Set) */ public void exportTo(File destination, Collection<? extends IFolderChild> elements, Set<Options> options) throws InterpreterException { ITypeExporter exporter = null; String fileName = destination.getName(); int i = fileName.lastIndexOf("."); //$NON-NLS-1$ if (i != -1 && !fileName.endsWith(".")) { //$NON-NLS-1$ String formatName = fileName.substring(i + 1); exporter = fTypeExporters.get(formatName); } /* Use default as Fallback */ if (exporter == null) exporter = fDefaultExporter; exporter.exportTo(destination, elements, options); } /* * @see org.rssowl.core.interpreter.IInterpreterService#getExportFormats() */ public Collection<String> getExportFormats() { return fTypeExporters.keySet(); } /* * @see * org.rssowl.core.interpreter.IInterpreterService#getNamespaceHandler(java * .lang.String) */ public INamespaceHandler getNamespaceHandler(String namespaceUri) { return fNamespaceHandlers.get(namespaceUri); } /* * @see * org.rssowl.core.interpreter.IInterpreterService#getElementHandler(java. * lang.String, java.lang.String) */ public IElementHandler getElementHandler(String elementName, String rootName) { if (fElementHandlers != null) return fElementHandlers.get(elementName.toLowerCase() + rootName.toLowerCase()); return null; } private void startup() { /* Load and Init XMLParser */ fXMLParserImpl = loadXMLParserImpl(); Assert.isNotNull(fXMLParserImpl); SafeRunner.run(new ISafeRunnable() { /* Use Default XML Parser Impl */ public void handleException(Throwable exception) { fXMLParserImpl = new DefaultSaxParserImpl(); try { fXMLParserImpl.init(); } catch (ParserException e) { Activator.getDefault().getLog().log(e.getStatus()); } } /* Try Contribution */ public void run() throws Exception { fXMLParserImpl.init(); } }); /* Load Format Interpreters */ fFormatInterpreters = new HashMap<String, IFormatInterpreter>(); loadFormatInterpreters(); /* Load Type Importers */ fTypeImporters = new HashMap<String, ITypeImporter>(); loadTypeImporters(); /* Load Type Exporters */ fTypeExporters = new HashMap<String, ITypeExporter>(); loadTypeExporters(); /* Load Namespace Handlers */ fNamespaceHandlers = new HashMap<String, INamespaceHandler>(); loadNamespaceHandlers(); /* Load Element Handlers */ loadElementHandlers(); } private void loadNamespaceHandlers() { IExtensionRegistry reg = Platform.getExtensionRegistry(); IConfigurationElement elements[] = reg.getConfigurationElementsFor(NSHANDLER_EXTENSION_POINT); for (IConfigurationElement element : elements) { try { String namespaceUri = element.getAttribute("namespaceURI"); //$NON-NLS-1$ /* Let 3d-Party contributions override our contributions */ if (fNamespaceHandlers.containsKey(namespaceUri) && element.getNamespaceIdentifier().contains(ExtensionUtils.RSSOWL_NAMESPACE)) continue; fNamespaceHandlers.put(namespaceUri, (INamespaceHandler) element.createExecutableExtension("class"));//$NON-NLS-1$ } catch (InvalidRegistryObjectException e) { Activator.getDefault().logError(e.getMessage(), e); } catch (CoreException e) { Activator.getDefault().getLog().log(e.getStatus()); } } } private void loadElementHandlers() { IExtensionRegistry reg = Platform.getExtensionRegistry(); IConfigurationElement elements[] = reg.getConfigurationElementsFor(ELHANDLER_EXTENSION_POINT); if (elements.length > 0) fElementHandlers = new HashMap<String, IElementHandler>(); for (IConfigurationElement element : elements) { String elementName = element.getAttribute("elementName").toLowerCase(); //$NON-NLS-1$ String rootName = element.getAttribute("rootElement").toLowerCase(); //$NON-NLS-1$ /* Let 3d-Party contributions override our contributions */ if (fElementHandlers.containsKey(elementName + rootName) && element.getNamespaceIdentifier().contains(ExtensionUtils.RSSOWL_NAMESPACE)) continue; try { fElementHandlers.put(elementName + rootName, (IElementHandler) element.createExecutableExtension("class"));//$NON-NLS-1$ } catch (CoreException e) { Activator.getDefault().getLog().log(e.getStatus()); } } } private void loadFormatInterpreters() { IExtensionRegistry reg = Platform.getExtensionRegistry(); IConfigurationElement elements[] = reg.getConfigurationElementsFor(FORMATINTERPRETER_EXTENSION_POINT); for (IConfigurationElement element : elements) { try { String format = element.getAttribute("rootElement").toLowerCase(); //$NON-NLS-1$ /* Let 3d-Party contributions override our contributions */ if (fFormatInterpreters.containsKey(format) && element.getNamespaceIdentifier().contains(ExtensionUtils.RSSOWL_NAMESPACE)) continue; fFormatInterpreters.put(format, (IFormatInterpreter) element.createExecutableExtension("class")); //$NON-NLS-1$ } catch (InvalidRegistryObjectException e) { Activator.getDefault().logError(e.getMessage(), e); } catch (CoreException e) { Activator.getDefault().getLog().log(e.getStatus()); } } } private void loadTypeImporters() { IExtensionRegistry reg = Platform.getExtensionRegistry(); IConfigurationElement elements[] = reg.getConfigurationElementsFor(TYPEIMPORTER_EXTENSION_POINT); for (IConfigurationElement element : elements) { try { String format = element.getAttribute("rootElement").toLowerCase(); //$NON-NLS-1$ /* Let 3d-Party contributions override our contributions */ if (fTypeImporters.containsKey(format) && element.getNamespaceIdentifier().contains(ExtensionUtils.RSSOWL_NAMESPACE)) continue; fTypeImporters.put(format, (ITypeImporter) element.createExecutableExtension("class")); //$NON-NLS-1$ } catch (InvalidRegistryObjectException e) { Activator.getDefault().logError(e.getMessage(), e); } catch (CoreException e) { Activator.getDefault().getLog().log(e.getStatus()); } } } private void loadTypeExporters() { IExtensionRegistry reg = Platform.getExtensionRegistry(); IConfigurationElement elements[] = reg.getConfigurationElementsFor(TYPEEXPORTER_EXTENSION_POINT); for (IConfigurationElement element : elements) { try { IConfigurationElement[] formats = element.getChildren("format"); //$NON-NLS-1$ for (IConfigurationElement format : formats) { String formatName = format.getAttribute("name").toLowerCase(); //$NON-NLS-1$ /* Let 3d-Party contributions override our contributions */ if (fTypeExporters.containsKey(formatName) && element.getNamespaceIdentifier().contains(ExtensionUtils.RSSOWL_NAMESPACE)) continue; fTypeExporters.put(formatName, (ITypeExporter) element.createExecutableExtension("class")); //$NON-NLS-1$ } } catch (InvalidRegistryObjectException e) { Activator.getDefault().logError(e.getMessage(), e); } catch (CoreException e) { Activator.getDefault().getLog().log(e.getStatus()); } } } /* Load XML Parser contribution */ private IXMLParser loadXMLParserImpl() { return (IXMLParser) ExtensionUtils.loadSingletonExecutableExtension(SAXPARSER_EXTENSION_POINT); } }