Java tutorial
/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * * Copyright (c) 2002-2019 Hitachi Vantara. All rights reserved. */ package org.pentaho.platform.plugin.services.pluginmgr; import org.apache.commons.io.IOCase; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.lang.StringUtils; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.pentaho.platform.api.engine.CsrfProtectionDefinition; import org.pentaho.platform.api.engine.IContentGeneratorInfo; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.IPlatformPlugin; import org.pentaho.platform.api.engine.IPluginProvider; import org.pentaho.platform.api.engine.PlatformPluginRegistrationException; import org.pentaho.platform.api.engine.PluginBeanDefinition; import org.pentaho.platform.api.engine.PluginServiceDefinition; import org.pentaho.platform.api.engine.perspective.pojo.IPluginPerspective; import org.pentaho.platform.api.repository2.unified.RepositoryFile; import org.pentaho.platform.engine.core.solution.ContentGeneratorInfo; import org.pentaho.platform.engine.core.solution.ContentInfo; import org.pentaho.platform.engine.core.solution.PluginOperation; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.SolutionURIResolver; import org.pentaho.platform.engine.services.actionsequence.ActionSequenceResource; import org.pentaho.platform.plugin.services.messages.Messages; import org.pentaho.platform.util.logging.Logger; import org.pentaho.platform.util.messages.LocaleHelper; import org.pentaho.platform.util.xml.XMLParserFactoryProducer; import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper; import org.pentaho.platform.web.WebUtil; import org.pentaho.ui.xul.impl.DefaultXulOverlay; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * An implementation of {@link IPluginProvider} that searches for plugin.xml files in the Pentaho system path and * instantiates {@link IPlatformPlugin}s from the information in those files. * * @author aphillips */ public class SystemPathXmlPluginProvider implements IPluginProvider { /** * Gets the list of plugins that this provider class has discovered. * * @return an read-only list of plugins * @see IPluginProvider#getPlugins() * @throws PlatformPluginRegistrationException * if there is a problem preventing the impl from looking for plugins */ public List<IPlatformPlugin> getPlugins(IPentahoSession session) throws PlatformPluginRegistrationException { List<IPlatformPlugin> plugins = new ArrayList<IPlatformPlugin>(); // look in each of the system setting folders looking for plugin.xml files String systemPath = PentahoSystem.getApplicationContext().getSolutionPath("system"); //$NON-NLS-1$ File systemDir = new File(systemPath); if (!systemDir.exists() || !systemDir.isDirectory()) { throw new PlatformPluginRegistrationException( Messages.getInstance().getErrorString("PluginManager.ERROR_0004_CANNOT_FIND_SYSTEM_FOLDER")); //$NON-NLS-1$ } File[] kids = systemDir.listFiles(); // look at each child to see if it is a folder for (File kid : kids) { if (kid.isDirectory()) { try { processDirectory(plugins, kid, session); } catch (Throwable t) { // don't throw an exception. we need to continue to process any remaining good plugins String msg = Messages.getInstance().getErrorString( "SystemPathXmlPluginProvider.ERROR_0001_FAILED_TO_PROCESS_PLUGIN", //$NON-NLS-1$ kid.getAbsolutePath()); Logger.error(getClass().toString(), msg, t); PluginMessageLogger.add(msg); } } } return Collections.unmodifiableList(plugins); } protected void processDirectory(List<IPlatformPlugin> plugins, File folder, IPentahoSession session) throws PlatformPluginRegistrationException { // see if there is a plugin.xml file FilenameFilter filter = new NameFileFilter("plugin.xml", IOCase.SENSITIVE); //$NON-NLS-1$ File[] kids = folder.listFiles(filter); if (kids == null || kids.length == 0) { return; } boolean hasLib = false; filter = new NameFileFilter("lib", IOCase.SENSITIVE); //$NON-NLS-1$ kids = folder.listFiles(filter); if (kids != null && kids.length > 0) { hasLib = kids[0].exists() && kids[0].isDirectory(); } // we have found a plugin.xml file // get the file from the repository String path = "system" + RepositoryFile.SEPARATOR + folder.getName() + RepositoryFile.SEPARATOR //$NON-NLS-1$ + "plugin.xml"; //$NON-NLS-1$ Document doc = null; try { try { org.dom4j.io.SAXReader reader = XMLParserFactoryProducer.getSAXReader(new SolutionURIResolver()); doc = reader.read(ActionSequenceResource.getInputStream(path, LocaleHelper.getLocale())); } catch (Throwable t) { // XML document can't be read. We'll just return a null document. } if (doc != null) { plugins.add(createPlugin(doc, session, folder.getName(), hasLib)); } } catch (Exception e) { throw new PlatformPluginRegistrationException(Messages.getInstance() .getErrorString("PluginManager.ERROR_0005_CANNOT_PROCESS_PLUGIN_XML", path), e); //$NON-NLS-1$ } if (doc == null) { throw new PlatformPluginRegistrationException(Messages.getInstance() .getErrorString("PluginManager.ERROR_0005_CANNOT_PROCESS_PLUGIN_XML", path)); //$NON-NLS-1$ } } protected PlatformPlugin createPlugin(Document doc, IPentahoSession session, String folder, boolean hasLib) { PlatformPlugin plugin = new PlatformPlugin(); processStaticResourcePaths(plugin, doc, session); processPluginInfo(plugin, doc, folder, session); processContentTypes(plugin, doc, session); processContentGenerators(plugin, doc, session, folder, hasLib); processOverlays(plugin, doc, session); processLifecycleListeners(plugin, doc); processBeans(plugin, doc); processWebservices(plugin, doc); processExternalResources(plugin, doc); processPerspectives(plugin, doc); processCsrfProtection(plugin, doc); String listenerCount = (StringUtils.isEmpty(plugin.getLifecycleListenerClassname())) ? "0" : "1"; //$NON-NLS-1$//$NON-NLS-2$ String msg = Messages.getInstance().getString("SystemPathXmlPluginProvider.PLUGIN_PROVIDES", //$NON-NLS-1$ Integer.toString(plugin.getContentInfos().size()), Integer.toString(plugin.getContentGenerators().size()), Integer.toString(plugin.getOverlays().size()), listenerCount); PluginMessageLogger.add(msg); plugin.setSourceDescription(folder); return plugin; } /** * @param plugin * @param doc */ protected void processPerspectives(PlatformPlugin plugin, Document doc) { // TODO Auto-generated method stub List<?> nodes = doc.selectNodes("/*/perspective"); //$NON-NLS-1$ for (Object obj : nodes) { Element node = (Element) obj; if (node != null) { IPluginPerspective perspective = PerspectiveUtil.createPerspective(node); plugin.addPluginPerspective(perspective); } } } protected void processStaticResourcePaths(PlatformPlugin plugin, Document doc, IPentahoSession session) { List<?> nodes = doc.selectNodes("//static-path"); //$NON-NLS-1$ for (Object obj : nodes) { Element node = (Element) obj; if (node != null) { String url = node.attributeValue("url"); //$NON-NLS-1$ String localFolder = node.attributeValue("localFolder"); //$NON-NLS-1$ plugin.addStaticResourcePath(url, localFolder); } } } protected void processExternalResources(PlatformPlugin plugin, Document doc) { Node parentNode = doc.selectSingleNode("//external-resources"); //$NON-NLS-1$ if (parentNode == null) { return; } for (Object obj : parentNode.selectNodes("file")) { Element node = (Element) obj; if (node != null) { String context = node.attributeValue("context"); //$NON-NLS-1$ String resource = node.getStringValue(); plugin.addExternalResource(context, resource); } } } protected void processLifecycleListeners(PlatformPlugin plugin, Document doc) { Element node = (Element) doc.selectSingleNode("//lifecycle-listener"); //$NON-NLS-1$ if (node != null) { String classname = node.attributeValue("class"); //$NON-NLS-1$ plugin.setLifecycleListenerClassname(classname); } } protected void processBeans(PlatformPlugin plugin, Document doc) { List<?> nodes = doc.selectNodes("//bean"); //$NON-NLS-1$ for (Object obj : nodes) { Element node = (Element) obj; if (node != null) { plugin.addBean(new PluginBeanDefinition(node.attributeValue("id"), node.attributeValue("class"))); //$NON-NLS-1$ //$NON-NLS-2$ } } } protected void processWebservices(PlatformPlugin plugin, Document doc) { List<?> nodes = doc.selectNodes("//webservice"); //$NON-NLS-1$ for (Object obj : nodes) { Element node = (Element) obj; PluginServiceDefinition pws = new PluginServiceDefinition(); pws.setId(getProperty(node, "id")); //$NON-NLS-1$ String type = getProperty(node, "type"); //$NON-NLS-1$ if (!StringUtils.isEmpty(type)) { pws.setTypes(type.split(",")); //$NON-NLS-1$ } pws.setTitle(getProperty(node, "title")); //$NON-NLS-1$ pws.setDescription(getProperty(node, "description")); //$NON-NLS-1$ // TODO: add support for inline service class definition pws.setServiceBeanId(getProperty(node, "ref")); //$NON-NLS-1$ pws.setServiceClass(getProperty(node, "class")); //$NON-NLS-1$ Collection<String> extraClasses = new ArrayList<String>(); List<?> extraNodes = node.selectNodes("extra"); //$NON-NLS-1$ for (Object extra : extraNodes) { Element extraElement = (Element) extra; String extraClass = getProperty(extraElement, "class"); //$NON-NLS-1$ if (extraClasses != null) { extraClasses.add(extraClass); } } pws.setExtraClasses(extraClasses); if (pws.getServiceBeanId() == null && pws.getServiceClass() == null) { PluginMessageLogger.add(Messages.getInstance().getString("PluginManager.NO_SERVICE_CLASS_FOUND")); //$NON-NLS-1$ } else { plugin.addWebservice(pws); } } } protected void processPluginInfo(PlatformPlugin plugin, Document doc, String folder, IPentahoSession session) { Element node = (Element) doc.selectSingleNode("/plugin"); //$NON-NLS-1$ // "name" is the attribute that unique identifies a plugin. It acts as the plugin ID. For backwards compatibility, // if name is not provided, name is set to the value of the "title" attribute // if (node != null) { String name = (node.attributeValue("name") != null) ? node.attributeValue("name") //$NON-NLS-1$//$NON-NLS-2$ : node.attributeValue("title"); //$NON-NLS-1$ if (StringUtils.isEmpty(name)) { String msg = Messages.getInstance() .getErrorString("SystemPathXmlPluginProvider.ERROR_0002_PLUGIN_INVALID", folder); //$NON-NLS-1$ PluginMessageLogger.add(msg); Logger.error(getClass().toString(), msg); } plugin.setId(name); PluginMessageLogger.add(Messages.getInstance() .getString("SystemPathXmlPluginProvider.DISCOVERED_PLUGIN", name, folder)); //$NON-NLS-1$ IPlatformPlugin.ClassLoaderType loaderType = IPlatformPlugin.ClassLoaderType.DEFAULT; String loader = node.attributeValue("loader"); //$NON-NLS-1$ if (!StringUtils.isEmpty(loader)) { loaderType = IPlatformPlugin.ClassLoaderType.valueOf(loader.toUpperCase()); } plugin.setLoadertype(loaderType); } } protected void processOverlays(PlatformPlugin plugin, Document doc, IPentahoSession session) { // look for content types List<?> nodes = doc.selectNodes("//overlays/overlay"); //$NON-NLS-1$ for (Object obj : nodes) { Element node = (Element) obj; DefaultXulOverlay overlay = processOverlay(node); if (overlay != null) { plugin.addOverlay(overlay); } } } public static DefaultXulOverlay processOverlay(Element node) { DefaultXulOverlay overlay = null; String id = node.attributeValue("id"); //$NON-NLS-1$ String resourceBundleUri = node.attributeValue("resourcebundle"); //$NON-NLS-1$ String priority = node.attributeValue("priority"); String xml = node.asXML(); if (StringUtils.isNotEmpty(id) && StringUtils.isNotEmpty(xml)) { // check for overlay priority attribute. if not present, do not provide one // so default will be used if (StringUtils.isNotEmpty(priority)) { try { overlay = new DefaultXulOverlay(id, null, xml, resourceBundleUri, Integer.parseInt(priority)); } catch (NumberFormatException e) { // don't fail if attribute value is invalid. just use alt constructor without priority overlay = new DefaultXulOverlay(id, null, xml, resourceBundleUri); } } else { overlay = new DefaultXulOverlay(id, null, xml, resourceBundleUri); } } return overlay; } protected void processContentTypes(PlatformPlugin plugin, Document doc, IPentahoSession session) { // look for content types List<?> nodes = doc.selectNodes("//content-type"); //$NON-NLS-1$ for (Object obj : nodes) { Element node = (Element) obj; String title = XmlDom4JHelper.getNodeText("title", node); //$NON-NLS-1$ String extension = node.attributeValue("type"); //$NON-NLS-1$ if (title != null && extension != null) { String description = XmlDom4JHelper.getNodeText("description", node, ""); //$NON-NLS-1$ //$NON-NLS-2$ String mimeType = node.attributeValue("mime-type", ""); //$NON-NLS-1$ //$NON-NLS-2$ String iconUrl = XmlDom4JHelper.getNodeText("icon-url", node, ""); //$NON-NLS-1$ //$NON-NLS-2$ ContentInfo contentInfo = new ContentInfo(); contentInfo.setDescription(description); contentInfo.setTitle(title); contentInfo.setExtension(extension); contentInfo.setMimeType(mimeType); contentInfo.setIconUrl(iconUrl); List<?> operationNodes = node.selectNodes("operations/operation"); //$NON-NLS-1$ for (Object operationObj : operationNodes) { Element operationNode = (Element) operationObj; String id = XmlDom4JHelper.getNodeText("id", operationNode, ""); //$NON-NLS-1$ //$NON-NLS-2$ String perspective = XmlDom4JHelper.getNodeText("perspective", operationNode, ""); //$NON-NLS-1$ //$NON-NLS-2$ if (StringUtils.isNotEmpty(id)) { PluginOperation operation = new PluginOperation(id); if (StringUtils.isNotEmpty(perspective)) { operation.setPerspective(perspective); } contentInfo.addOperation(operation); } } plugin.addContentInfo(contentInfo); PluginMessageLogger.add(Messages.getInstance() .getString("PluginManager.USER_CONTENT_TYPE_REGISTERED", extension, title)); //$NON-NLS-1$ } else { PluginMessageLogger.add(Messages.getInstance() .getString("PluginManager.USER_CONTENT_TYPE_NOT_REGISTERED", extension, title)); //$NON-NLS-1$ } } } /* * Finds propName as either an attribute of the given node or the text element of a child element called propName */ private static String getProperty(Element node, String propName) { String propValue = null; propValue = node.attributeValue(propName); if (propValue == null) { propValue = XmlDom4JHelper.getNodeText(propName, node, null); } return propValue; } protected void processContentGenerators(PlatformPlugin plugin, Document doc, IPentahoSession session, String folder, boolean hasLib) { // look for content generators List<?> nodes = doc.selectNodes("//content-generator"); //$NON-NLS-1$ for (Object obj : nodes) { Element node = (Element) obj; String className = getProperty(node, "class"); //$NON-NLS-1$ if (className == null) { className = XmlDom4JHelper.getNodeText("classname", node, null); //$NON-NLS-1$ } String id = node.attributeValue("id"); //$NON-NLS-1$ String type = node.attributeValue("type"); //$NON-NLS-1$ String url = node.attributeValue("url"); //$NON-NLS-1$ String title = getProperty(node, "title"); //$NON-NLS-1$ String description = getProperty(node, "description"); //$NON-NLS-1$ try { if (id != null && type != null && className != null && title != null) { try { IContentGeneratorInfo info = createContentGenerator(plugin, id, title, description, type, url, className, session, folder); plugin.addContentGenerator(info); } catch (Exception e) { PluginMessageLogger.add(Messages.getInstance() .getString("PluginManager.USER_CONTENT_GENERATOR_NOT_REGISTERED", id, folder)); //$NON-NLS-1$ } } else { PluginMessageLogger.add(Messages.getInstance() .getString("PluginManager.USER_CONTENT_GENERATOR_NOT_REGISTERED", id, folder)); //$NON-NLS-1$ } } catch (Exception e) { PluginMessageLogger.add(Messages.getInstance() .getString("PluginManager.USER_CONTENT_GENERATOR_NOT_REGISTERED", id, folder)); //$NON-NLS-1$ Logger.error(getClass().toString(), Messages.getInstance().getErrorString( "PluginManager.ERROR_0006_CANNOT_CREATE_CONTENT_GENERATOR_FACTORY", folder), e); //$NON-NLS-1$ } } } private static IContentGeneratorInfo createContentGenerator(PlatformPlugin plugin, String id, String title, String description, String type, String url, String className, IPentahoSession session, String location) throws ClassNotFoundException, InstantiationException, IllegalAccessException { ContentGeneratorInfo info = new ContentGeneratorInfo(); info.setId(id); info.setTitle(title); info.setDescription(description); info.setUrl((url != null) ? url : ""); //$NON-NLS-1$ info.setType(type); info.setClassname(className); return info; } protected void processCsrfProtection(PlatformPlugin plugin, Document doc) { Node csrfProtectionElem = doc.selectSingleNode("*/csrf-protection"); if (csrfProtectionElem != null) { try { CsrfProtectionDefinition protectionDefinition = WebUtil .parseXmlCsrfProtectionDefinition((Element) csrfProtectionElem); if (protectionDefinition != null) { plugin.setCsrfProtection(protectionDefinition); } } catch (IllegalArgumentException parseError) { PluginMessageLogger.add( Messages.getInstance().getString("PluginManager.WARN_CSRF_REQUEST_MATCHER_NOT_REGISTERED", plugin.getId(), parseError.getMessage())); } } } }