/* * #%L * carewebframework * %% * Copyright (C) 2008 - 2016 Regenstrief Institute, Inc. * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This Source Code Form is also subject to the terms of the Health-Related * Additional Disclaimer of Warranty and Limitation of Liability available at * * http://www.carewebframework.org/licensing/disclaimer. * * #L% */ package org.carewebframework.shell.plugins; import java.util.ArrayList; import java.util.List; import java.util.jar.Manifest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.carewebframework.api.ManifestIterator; import org.carewebframework.api.property.IPropertyProvider; import org.carewebframework.api.security.SecurityUtil; import org.carewebframework.shell.layout.UIElementBase; import org.carewebframework.shell.layout.UIElementPlugin; import org.carewebframework.shell.layout.UILayout; import org.carewebframework.shell.property.PropertyInfo; import org.springframework.beans.BeanUtils; import org.springframework.util.StringUtils; /** * Each instance of this class defines a complete definition of a CareWeb plugin. A definition * declares various attributes of a plugin, like its display name, url, toolbar buttons, help * module, etc. */ public class PluginDefinition { private static final Log log = LogFactory.getLog(PluginDefinition.class); /** * Represents a security authority. */ public static class Authority { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } } private String name; private String source; private String url; private String id; private String description; private String category; private String creator; private String copyright; private String version; private String released; private String icon; private boolean requiresAll; private boolean lazyLoad = true; private boolean disabled; private Class<? extends UIElementBase> clazz = UIElementPlugin.class; private final List<IPluginResource> resources = new ArrayList<>(); private final List<Authority> authorities = new ArrayList<>(); private final List<PropertyInfo> properties = new ArrayList<>(); private Manifest manifest; /** * Returns the plugin definition associated with the specified xml tag (same as plugin id). * * @param tag XML tag (plugin id). * @return The associated plugin definition, or null if not found. */ public static PluginDefinition getDefinition(String tag) { return PluginRegistry.getInstance().get(tag); } /** * Returns the plugin definition associated with the specified class. * * @param clazz The class whose plugin definition is sought. * @return The associated plugin definition, or null if not found. */ public static PluginDefinition getDefinition(Class<? extends UIElementBase> clazz) { return PluginRegistry.getInstance().get(clazz); } /** * The basic constructor. */ public PluginDefinition() { } /** * Constructs a plugin definition for the specified plugin name and class. * * @param name Display name of the plugin. * @param clazz Associated UI element class. * @throws ClassNotFoundException If class not found. */ public PluginDefinition(String name, Class<? extends UIElementBase> clazz) throws ClassNotFoundException { super(); this.name = name; this.clazz = clazz; } /** * Copy constructor. * * @param def Plugin definition to copy. */ public PluginDefinition(PluginDefinition def) { BeanUtils.copyProperties(def, this); } /** * Returns the unique id of the plugin definition. * * @return The unique id. */ public String getId() { return id; } /** * Sets the unique id of the plugin definition * * @param id The unique plugin id. */ public void setId(String id) { this.id = id; } /** * Returns the source of the plugin. * * @return The plugin source. */ public String getSource() { return getValueWithDefault(source, "Implementation-Vendor"); } /** * Sets the source of the plugin. * * @param source Plugin source. */ public void setSource(String source) { this.source = source; } /** * Returns the display name of the plugin definition. * * @return The display name. */ public String getName() { return name; } /** * Sets the display name of the plugin definition. * * @param name Plugin display name. */ public void setName(String name) { this.name = name; } /** * Returns the URL of the principal zul page for the plugin. * * @return The URL of the principal zul page. */ public String getUrl() { return url; } /** * Sets the URL of the principal zul page for the plugin. * * @param url The URL of the principal zul page. */ public void setUrl(String url) { this.url = url; } /** * Sets the requiresAll flag. When true, this flag indicates that all associated authorities * must be present in order to access the plugin. When false, any single associated authority is * sufficient for access. If no authorities are associated with the plugin, this setting is * ignored. * * @param requiresAll The requiresAll flag. */ public void setRequiresAll(boolean requiresAll) { this.requiresAll = requiresAll; } /** * Returns the requiresAll flag. When true, this flag indicates that all associated authorities * must be present in order to access the plugin. When false, any single associated authority is * sufficient for access. If no authorities are associated with the plugin, this setting is * ignored. * * @return The requiresAll flag. */ public boolean isRequiresAll() { return requiresAll; } /** * Returns the lazyLoad flag. When true, a plugin created from this definition is not fully * initialized until it is first activity. When false, the plugin is initialized immediately * after deserialization. * * @return The lazyLoad flag. */ public boolean isLazyLoad() { return lazyLoad; } /** * Sets the lazyLoad flag. When true, a plugin created from this definition is not fully * initialized until it is first activity. When false, the plugin is initialized immediately * after deserialization. * * @param lazyLoad The lazyLoad flag. */ public void setLazyLoad(boolean lazyLoad) { this.lazyLoad = lazyLoad; } /** * Returns the list of associated plugin resources. Never null. * * @return List of associated resources. */ public List<IPluginResource> getResources() { return resources; } /** * Returns the list of plugin resources belonging to the specified resource class. Never null. * * @param <E> A subclass of PluginResource. * @param clazz The resource class being sought. * @return List of associated resources. */ @SuppressWarnings("unchecked") public <E extends IPluginResource> List<E> getResources(Class<E> clazz) { List<E> list = new ArrayList<>(); for (IPluginResource resource : resources) { if (clazz.isInstance(resource)) { list.add((E) resource); } } return list; } /** * Adds resources from the list to the list of resources associated with this plugin. * * @param resources Resources to add. */ public void setResources(List<IPluginResource> resources) { this.resources.addAll(resources); } /** * Returns the list of authorities required for access to this plugin. Never null. * * @return List of authorities. */ public List<Authority> getAuthorities() { return authorities; } /** * Adds authorities from the list to the list of authorities associated with this plugin. * * @param authorities Authorities required by this plugin. */ public void setAuthorities(List<Authority> authorities) { this.authorities.addAll(authorities); } /** * Returns the list of properties associated with this plugin. Never null. * * @return List of properties. */ public List<PropertyInfo> getProperties() { return properties; } /** * Adds properties from the list to the list of properties associated with this plugin. * * @param properties List of associated properties. */ public void setProperties(List<PropertyInfo> properties) { this.properties.addAll(properties); } /** * Returns the UI element class associated with this definition. * * @return Associated UI element class. */ public Class<? extends UIElementBase> getClazz() { return clazz; } /** * Sets the UI element class associated with this definition. * * @param clazz The associated class. * @throws ClassNotFoundException If class not found. */ public void setClazz(Class<? extends UIElementBase> clazz) throws ClassNotFoundException { this.clazz = clazz; Class.forName(clazz.getName()); // Force execution of static initializers } /** * Returns the description of this plugin. * * @return Plugin description. */ public String getDescription() { return description; } /** * Sets the description of this plugin. * * @param description The plugin description. */ public void setDescription(String description) { this.description = description; } /** * Sets the category under which this plugin is to be classified. This can be specified as a * tree node path using "\" to separate the path components. * * @param category The plugin category. */ public void setCategory(String category) { this.category = category; } /** * Returns the category under which this plugin is to be classified. This can be specified as a * tree node path using "\" to separate the path components. * * @return Associated category. */ public String getCategory() { return category; } /** * Returns the name of the creator of this plugin. * * @return Plugin creator. */ public String getCreator() { return creator; } /** * Sets the name of the creator of this plugin. * * @param creator The plugin creator. */ public void setCreator(String creator) { this.creator = creator; } /** * Returns any copyright information for this plugin. * * @return Copyright info. */ public String getCopyright() { return copyright; } /** * Sets any copyright information for this plugin. * * @param copyright Plugin copyright information. */ public void setCopyright(String copyright) { this.copyright = copyright; } /** * Returns version information about the plugin. * * @return Version info. */ public String getVersion() { return getValueWithDefault(version, "Implementation-Version"); } /** * Sets version information about the plugin. * * @param version The plugin version. */ public void setVersion(String version) { this.version = version; } /** * Sets release information (typically a date) about the plugin. * * @param released Release information. */ public void setReleased(String released) { this.released = released; } /** * Returns release information (typically a date) about the plugin. * * @return Release info. */ public String getReleased() { return released; } /** * Sets the url of the icon associated with the plugin. * * @param icon Url of an icon. */ public void setIcon(String icon) { this.icon = icon; } /** * Returns the url of the icon associated with the plugin. * * @return Url of associated icon. */ public String getIcon() { return icon; } /** * Returns true if this definition represents an internal UI element (i.e., one that has been * pre-created by some other means). * * @return True if internal element. */ public boolean isInternal() { return id != null && id.startsWith("_"); } /** * Returns true if the plugin has been disabled. * * @return True if disabled. */ public boolean isDisabled() { return disabled; } /** * Sets the disabled state of the plugin. * * @param disabled The desired state. */ public void setDisabled(boolean disabled) { this.disabled = disabled; } /** * Returns true if access to the plugin is restricted. * * @return True if access to the plugin is restricted. */ public boolean isForbidden() { if (authorities.size() == 0) { return false; // If no restrictions, return false } boolean result = true; for (Authority priv : authorities) { result = !SecurityUtil.isGranted(priv.name); if (requiresAll == result) { break; } } return result; } /** * Returns true if this definition contains any editable properties. * * @return True if editable properties are present. */ public boolean hasEditableProperties() { for (PropertyInfo propInfo : properties) { if (propInfo.isEditable()) { return true; } } return false; } /** * Sets the path of the resource containing the plugin definition. This is used to locate the * manifest entry from which version and source information can be extracted. * * @param path Path of the resource containing this plugin definition. */ public void setPath(String path) { if (path != null) { manifest = ManifestIterator.getInstance().findByPath(path); } } /** * Returns a value's default if the initial value is null or empty. * * @param value The initial value. * @param manifestKey The manifest key from which to obtain the default value. * @return The initial value or, if it was null or empty, the default value. */ private String getValueWithDefault(String value, String manifestKey) { if (StringUtils.isEmpty(value) && manifest != null) { value = manifest.getMainAttributes().getValue(manifestKey); } return value; } /** * Creates an instance of the element based on its definition. If a property source is * specified, the source is used to initialize properties on the newly created element. * * @param parent Parent element (may be null). * @param propertySource Property source for initializing element properties (may be null). * @return Newly created element (may be null if access is restricted or plugin has been * disabled). * @throws Exception Unspecified exception. */ public UIElementBase createElement(UIElementBase parent, IPropertyProvider propertySource) throws Exception { UIElementBase element = null; boolean deserializing = propertySource instanceof UILayout; if (isForbidden()) { log.info("Access to plugin " + getName() + " is restricted."); } else if (isDisabled()) { log.info("Plugin " + getName() + " has been disabled."); } else { Class<? extends UIElementBase> clazz = getClazz(); if (isInternal()) { element = parent.getChild(clazz, null); } else { element = clazz.newInstance(); } if (element == null) { UIElementBase.raise("Failed to create UI element " + id + "."); } element.setDefinition(this); element.beforeInitialize(deserializing); if (propertySource != null) { for (PropertyInfo propInfo : getProperties()) { String key = propInfo.getId(); if (propertySource.hasProperty(key)) { String value = propertySource.getProperty(key); propInfo.setPropertyValue(element, value); } } } if (parent != null) { element.setParent(parent); } element.afterInitialize(deserializing); } return element; } }