Changeset 4168
- Timestamp:
- Mar 4, 2008, 2:49:06 PM (15 years ago)
- Location:
- branches/extensions
- Files:
-
- 24 added
- 8 deleted
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/extensions/config/dist/web.xml
r3846 r4168 160 160 </servlet-mapping> 161 161 162 <!-- Extensions servlet for managing extensions to the web client --> 163 <servlet> 164 <servlet-name>ExtensionsServlet</servlet-name> 165 <display-name>Web client extensions manager</display-name> 166 <servlet-class>net.sf.basedb.clients.web.servlet.ExtensionsServlet</servlet-class> 167 <load-on-startup>1</load-on-startup> 168 </servlet> 169 <servlet-mapping> 170 <servlet-name>ExtensionsServlet</servlet-name> 171 <url-pattern>/extensions</url-pattern> 172 </servlet-mapping> 173 162 174 <!-- The CompileAll servlet used to compile all JSP pages --> 163 175 <!-- EXPERIMENTAL!! --> -
branches/extensions/src/clients/web/net/sf/basedb/clients/web/extensions/JspContext.java
r4158 r4168 24 24 package net.sf.basedb.clients.web.extensions; 25 25 26 import java.io.IOException; 26 27 import java.io.Writer; 28 import java.util.HashSet; 29 import java.util.Set; 30 31 import javax.servlet.jsp.PageContext; 27 32 28 33 import net.sf.basedb.core.SessionControl; … … 34 39 @version 2.7 35 40 @base.modified $Date$ 36 41 */ 37 42 public class JspContext 38 43 extends Context 39 44 { 45 46 private Set<String> scripts; 47 private Set<String> stylesheets; 48 40 49 private Writer out; 50 private PageContext pageContext; 41 51 42 52 public JspContext(SessionControl sc) … … 55 65 } 56 66 67 public void addScript(String path) 68 { 69 if (scripts == null) scripts = new HashSet<String>(); 70 scripts.add(path); 71 } 72 73 public void addStylesheet(String path) 74 { 75 if (stylesheets == null) stylesheets = new HashSet<String>(); 76 stylesheets.add(path); 77 } 78 79 public void writeScripts(String root) 80 throws IOException 81 { 82 if (scripts == null) return; 83 for (String script : scripts) 84 { 85 out.write("<script language=\"JavaScript\" type=\"text/javascript\" src=\""); 86 out.write(root); 87 out.write(script); 88 out.write("\"></script>\n"); 89 } 90 } 91 57 92 } -
branches/extensions/src/clients/web/net/sf/basedb/clients/web/extensions/MevActionButtonFactory.java
r4158 r4168 24 24 package net.sf.basedb.clients.web.extensions; 25 25 26 import net.sf.basedb.clients.web.extensions.toolbar.ButtonAction; 27 import net.sf.basedb.clients.web.extensions.toolbar.ButtonBean; 26 28 import net.sf.basedb.core.BioAssaySet; 27 29 import net.sf.basedb.util.extensions.AbstractActionFactory; … … 35 37 */ 36 38 public class MevActionButtonFactory 37 extends AbstractActionFactory< ActionButton>39 extends AbstractActionFactory<ButtonAction> 38 40 { 39 41 40 private String i mage;42 private String icon; 41 43 private String title; 42 44 private String onClick; 43 45 44 public ActionButton[] getActions(Context context) 46 public boolean prepareContext(Context context) 47 { 48 JspContext jspContext = (JspContext)context; 49 jspContext.addScript("mev_script.js"); 50 return true; 51 } 52 53 public ButtonAction[] getActions(Context context) 45 54 { 46 55 Object item = context.getCurrentItem(); 47 ActionButton action = null;56 ButtonBean action = null; 48 57 if (item instanceof BioAssaySet) 49 58 { 50 59 BioAssaySet bas = (BioAssaySet)item; 51 action = new ImmutableActionButton(image, title, onClick + "(" + bas.getId() + ")"); 60 action = new ButtonBean(); 61 action.setIcon(icon); 62 action.setTitle(title); 63 action.setOnClick(onClick + "(" + bas.getId() + ")"); 64 52 65 } 53 return action == null ? null : new ActionButton[]{action};66 return action == null ? null : new ButtonAction[]{action}; 54 67 } 55 68 56 public void setI mage(String image)69 public void setIcon(String icon) 57 70 { 58 this.i mage = image;71 this.icon = icon; 59 72 } 60 73 public void setTitle(String title) -
branches/extensions/src/clients/web/net/sf/basedb/clients/web/extensions/WebExtensions.java
r4163 r4168 24 24 package net.sf.basedb.clients.web.extensions; 25 25 26 import java.io.InputStream;27 import java.net.URL;28 import java.util.List;29 26 30 import net.sf.basedb.util.extensions.Action; 31 import net.sf.basedb.util.extensions.XmlLoader; 32 import net.sf.basedb.util.extensions.ExtensionBean; 33 import net.sf.basedb.util.extensions.ExtensionPoint; 34 import net.sf.basedb.util.extensions.ExtensionPointBean; 27 import net.sf.basedb.util.extensions.Extension; 28 import net.sf.basedb.util.extensions.ExtensionsInvoker; 35 29 import net.sf.basedb.util.extensions.Registry; 36 30 … … 44 38 { 45 39 46 public static finalRegistry REGISTRY = new Registry();40 public static Registry REGISTRY = new Registry(); 47 41 48 static 42 public static Settings SETTINGS; 43 44 45 public static ExtensionsInvoker<?> useExtensions(JspContext context, String...extensionPoints) 49 46 { 50 // Register core extension points 51 try 52 { 53 URL coreExtensionPoints = 54 WebExtensions.class.getResource("/net/sf/basedb/clients/web/extensions/core-extension-points.xml"); 55 XmlLoader loader = new XmlLoader(); 56 loader.loadXmlFile(coreExtensionPoints.openStream(), coreExtensionPoints.toString(), null); 57 loader.registerExtensionPoints(REGISTRY); 58 } 59 catch (Exception ex) 60 { 61 throw new RuntimeException(ex); 62 } 63 64 // Launch MeV button 65 MevActionButtonFactory mevButtonFactory = new MevActionButtonFactory(); 66 mevButtonFactory.setImage("../../../images/tm4.png"); 67 mevButtonFactory.setTitle("MeV: MultiExperiment Viewer"); 68 mevButtonFactory.setOnClick("net_sf_launchMeV"); 69 70 ExtensionBean<ActionButton> mev = new ExtensionBean<ActionButton>(); 71 mev.setId("net.sf.basedb.clients.web.bioassayset.list.tools.mev"); 72 mev.setExtends("net.sf.basedb.clients.web.bioassayset.list.tools"); 73 mev.setActionFactory(mevButtonFactory); 74 REGISTRY.registerExtension(mev); 75 76 // MAGE Export button 77 ImmutableActionButtonFactory otherButtonFactory = new ImmutableActionButtonFactory(); 78 otherButtonFactory.setImage("../../../images/decompress.png"); 79 otherButtonFactory.setTitle("MAGE Export"); 80 otherButtonFactory.setOnClick("alert('not yet implemented');"); 81 82 ExtensionBean<ActionButton> mage = new ExtensionBean<ActionButton>(); 83 mage.setId("net.sf.basedb.clients.web.bioassayset.list.tools.mage"); 84 mage.setExtends("net.sf.basedb.clients.web.bioassayset.list.tools"); 85 mage.setActionFactory(otherButtonFactory); 86 REGISTRY.registerExtension(mage); 47 return REGISTRY.useExtensions(context, SETTINGS, extensionPoints); 87 48 } 88 49 89 50 public static String getRootUrl(Extension extension) 51 { 52 return "/extensions/" + extension.getId(); 53 } 54 55 public static String makeAbsolutePath(String path, Extension extension) 56 { 57 if (path != null && path.startsWith("~")) 58 { 59 path = getRootUrl(extension) + path.substring(1); 60 } 61 return path; 62 } 90 63 91 64 } -
branches/extensions/src/clients/web/net/sf/basedb/clients/web/extensions/core-extension-points.xml
r4163 r4168 27 27 > 28 28 29 <extension-point 30 id="net.sf.basedb.clients.web.menu.extensions" 31 > 32 <action-class>net.sf.basedb.clients.web.extensions.menu.MenuItemAction</action-class> 33 <name>Menu: extensions</name> 34 <description> 35 Extension point for adding extensions to the 'Extensions' menu. 36 Extensions should provide MenuItemAction instances. The rendering 37 is internal and extensions can't use their own rendering factories. 38 The context will only include information about the currently logged 39 in user, not information about the current page that is displayed. 40 The reason for this is that the rendered menu is cached as a string 41 in the user session. The menu is not updated on every page request. 42 This extension point doesn't support custom stylesheets or javascripts. 43 </description> 44 </extension-point> 45 29 46 <extension-point 30 47 id="net.sf.basedb.clients.web.bioassayset.list.tools" 31 48 > 32 <action-class>net.sf.basedb.clients.web.extensions. ActionButton</action-class>49 <action-class>net.sf.basedb.clients.web.extensions.toolbar.ButtonAction</action-class> 33 50 <renderer-factory override="true"> 34 <factory-class>net.sf.basedb.clients.web.extensions. ActionButtonRendererFactory</factory-class>51 <factory-class>net.sf.basedb.clients.web.extensions.toolbar.CompactButtonRendererFactory</factory-class> 35 52 </renderer-factory> 53 <name>Bioassay set: Tools</name> 36 54 <description> 37 55 Extension point for the Tools column in the bioassayset tree 38 56 view of an experiment. Extensions should provide ActionButton 39 57 instances. The default renderer factory is ActionButtonRendererFactory, 40 but this can be overridden by the extensions. 58 but this can be overridden by the extensions. Note that the tree 59 contains items of more than one type: BioAssaySet, Transformation and 60 ExtraValue. The JspContext.getItem() can return any one of those 61 types. 41 62 </description> 42 63 </extension-point> -
branches/extensions/src/clients/web/net/sf/basedb/clients/web/taglib/Head.java
r4093 r4168 148 148 private void appendScripts(StringBuilder sb) 149 149 { 150 SessionControl sc = page.getSessionControl(); 150 151 LinkedHashSet<String> allSscripts = new LinkedHashSet<String>(); 151 152 allSscripts.add("main.js"); … … 164 165 sb.append("\t\tfunction getScale()\n"); 165 166 sb.append("\t\t{\n"); 166 sb.append("\t\t\treturn ").append(Base.getScale(page.getSessionControl())).append(";\n"); 167 sb.append("\t\t\treturn ").append(Base.getScale(sc)).append(";\n"); 168 sb.append("\t\t}\n"); 169 sb.append("\t\tfunction getSessionId()\n"); 170 sb.append("\t\t{\n"); 171 sb.append("\t\t\treturn '").append(sc == null ? "" : sc.getId()).append("';\n"); 167 172 sb.append("\t\t}\n"); 168 173 sb.append("\t</script>\n"); -
branches/extensions/src/clients/web/net/sf/basedb/clients/web/taglib/menu/Menuitem.java
r4093 r4168 270 270 { 271 271 String theIcon = getIcon() == null ? "padding.gif" : getIcon(); 272 sb.append("<img src=\"").append(menu.getRoot()).append("images/").append(theIcon).append("\" alt=\"\" style=\"padding-left: 4px; padding-right: 4px;\">"); 272 if (theIcon.startsWith("/")) 273 { 274 // Remove starting / to avoid // in the src attribute 275 theIcon = theIcon.substring(1); 276 } 277 else 278 { 279 // The icon is in the 'images' directory 280 theIcon = "images/" + theIcon; 281 } 282 sb.append("<img src=\"").append(menu.getRoot()).append(theIcon).append("\" alt=\"\" style=\"padding-left: 4px; padding-right: 4px;\">"); 273 283 } 274 284 String padding = menu.isVertical() ? " " : ""; -
branches/extensions/src/core/net/sf/basedb/core/Presets.java
r3675 r4168 31 31 import java.util.Map; 32 32 import java.util.TreeMap; 33 import java.io.InputStream; 34 import java.io.OutputStream; 33 35 import java.net.URL; 34 36 35 37 import org.jdom.Document; 36 38 import org.jdom.Element; 39 import org.jdom.output.Format; 37 40 import org.jdom.output.XMLOutputter; 38 41 … … 102 105 103 106 /** 107 Load presets from a stream. 108 @param in The stream to read from 109 @param filename The original filename the stream is loaded 110 from, or null if not known 111 @since 2.7 112 */ 113 public void loadFrom(InputStream in, String filename) 114 { 115 try 116 { 117 Document dom = XMLUtil.getValidatedXML(in, dtdFile, filename); 118 loadPresets(dom); 119 } 120 catch (Exception ex) 121 { 122 throw new BaseException(ex); 123 } 124 } 125 126 /** 127 Write the prestes to a stream as an XML file. 128 @param out The stream to write to. 129 @since 2.7 130 */ 131 public void writeTo(OutputStream out) 132 { 133 try 134 { 135 new XMLOutputter(Format.getPrettyFormat()).output(buildDocument(), out); 136 } 137 catch (Exception ex) 138 { 139 throw new BaseException(ex); 140 } 141 } 142 143 /** 104 144 Convert the presets to an XML string. 105 145 @return The XML string 106 146 */ 107 147 public String asXml() 148 { 149 return new XMLOutputter().outputString(buildDocument()); 150 } 151 152 /** 153 Convert the presets to a XML document. 154 @since 2.7 155 */ 156 private Document buildDocument() 108 157 { 109 158 Document dom = XMLUtil.createDom("presets", "presets.dtd"); … … 121 170 root.addContent(el); 122 171 } 123 return new XMLOutputter().outputString(dom);124 } 125 172 return dom; 173 } 174 126 175 /** 127 176 Get the default preset. If no default exists a new default -
branches/extensions/src/core/net/sf/basedb/core/xsd/extensions.xsd
r4163 r4168 45 45 </xsd:complexType> 46 46 </xsd:element> 47 <xsd:element name="name" type="xsd:string" minOccurs="0" /> 47 48 <xsd:element name="description" type="xsd:string" minOccurs="0" /> 48 49 </xsd:all> … … 57 58 <xsd:element name="renderer-factory" type="factoryType" minOccurs="0" /> 58 59 <xsd:element name="about" type="aboutType" minOccurs="0" /> 59 <xsd:element name="index" type="xsd:float" />60 <xsd:element name="index" type="xsd:float" minOccurs="0" /> 60 61 </xsd:all> 61 62 <xsd:attribute name="id" type="xsd:ID" use="required" /> -
branches/extensions/src/core/net/sf/basedb/util/extensions/Context.java
r4158 r4168 24 24 package net.sf.basedb.util.extensions; 25 25 26 import java.util.HashMap; 27 import java.util.Map; 28 26 29 import net.sf.basedb.core.SessionControl; 27 30 28 31 /** 32 Keeps information about the current context that 33 extensions can use to decide what actions to generate. 34 It is, for example, possible to check the permissions 35 of logged in user and enable/disable certain actions 36 if a condition is not met. Or, the extension may inspect 37 the current item and decide if the extension can be used 38 on that item or not. 39 40 <p> 41 The current context is passed to an {@link ActionFactory} twice, first 42 to check if an extension should be enabled or not 43 with the {@link ActionFactory#prepareContext(Context)} 44 method. This method also allows an extension to write 45 back information to the context. This may, for example, 46 include information about which Javascript scripts to import 47 or which stylesheets to load. The <code>prepareContext</code> 48 method is only called once for each use of an extension. 49 50 <p> 51 The second time is when calling the {@link 52 ActionFactory#getActions(Context)} method. This method can 53 be called multiple times. For example, if an extension point 54 is in a list context, the <code>getActions</code> method may 55 be called one time for each item in the list. If so, the 56 {@link #getCurrentItem()} returns the currently active item. 57 58 <p> 59 Client applications may subclass this object to provide more 60 information about the client environment. See, for example, 61 the {@link net.sf.basedb.clients.web.extensions.JspContext} object. 29 62 30 63 @author nicklas 31 64 @version 2.7 32 65 @base.modified $Date$ 33 66 */ 34 67 public class Context 35 68 { … … 37 70 private final SessionControl sc; 38 71 private Object item; 72 private Map<String, Object> attributes; 39 73 74 /** 75 Create a new context. 76 @param sc The current session 77 */ 40 78 public Context(SessionControl sc) 41 79 { … … 43 81 } 44 82 83 /** 84 Create a new context. 85 @param sc The current session 86 @param item The current item 87 */ 88 public Context(SessionControl sc, Object item) 89 { 90 this.sc = sc; 91 this.item = item; 92 } 93 94 /** 95 Get the current session control. 96 */ 97 public SessionControl getSessionControl() 98 { 99 return sc; 100 } 101 102 /** 103 Get the currently active item. It can be any type of 104 object, but the extension point may declare (in it's 105 documentation) that the current item is always of a 106 certain type. 107 @return The current item, or null 108 */ 109 public Object getCurrentItem() 110 { 111 return item; 112 } 113 114 /** 115 Set the currently active item. 116 @param item The item that is the current item 117 */ 45 118 public void setCurrentItem(Object item) 46 119 { … … 48 121 } 49 122 50 public ResourceManager getResourceManager() 123 /** 124 Get an attribute of the context. 125 @param name The name of the attribute 126 @return The value, or null 127 */ 128 public Object getAttribute(String name) 51 129 { 52 return null;130 return attributes == null ? null : attributes.get(name); 53 131 } 54 132 55 public Object getCurrentItem() 133 /** 134 Set an attribute of the context. 135 @param name The name of the attribute 136 @param value The value, if null the attribute is removed 137 */ 138 public void setAttribute(String name, Object value) 56 139 { 57 return item; 140 if (attributes == null) attributes = new HashMap<String, Object>(); 141 if (value != null) 142 { 143 attributes.put(name, value); 144 } 145 else 146 { 147 attributes.remove(name); 148 } 58 149 } 59 150 60 public SessionControl getSessionControl()61 {62 return sc;63 }64 65 66 151 } -
branches/extensions/src/core/net/sf/basedb/util/extensions/ExtensionPoint.java
r4163 r4168 66 66 67 67 /** 68 Get the name of the extension point. This is just for display 69 purposes and the value is optional. If no name is given the 70 ID can be used instead. 71 */ 72 public String getName(); 73 74 /** 68 75 Get a description of the extension point. This value is optional 69 76 but we recommend that the description contains a text documenting -
branches/extensions/src/core/net/sf/basedb/util/extensions/ExtensionPointBean.java
r4163 r4168 38 38 39 39 private String id; 40 private String name; 40 41 private String description; 41 42 private Class<A> actionClass; … … 58 59 public ExtensionPointBean( 59 60 String id, 61 String name, 60 62 String description, 61 63 Class<A> actionClass, … … 64 66 { 65 67 this.id = id; 68 this.name = name; 66 69 this.description = description; 67 70 this.actionClass = actionClass; … … 78 81 { 79 82 this.id = id; 83 } 84 85 @Override 86 public String getName() 87 { 88 return name; 89 } 90 public void setName(String name) 91 { 92 this.name = name; 80 93 } 81 94 -
branches/extensions/src/core/net/sf/basedb/util/extensions/ExtensionsInvoker.java
r4163 r4168 25 25 26 26 import java.util.Collection; 27 import java.util.IdentityHashMap;28 27 import java.util.Iterator; 29 import java.util.Map;30 import java.util.NoSuchElementException;31 28 32 29 import net.sf.basedb.util.extensions.Registry.RegisteredExtension; 33 import net.sf.basedb.util.extensions.Registry.RegisteredExtensionPoint; 30 34 31 35 32 /** … … 61 58 { 62 59 63 privatefinal Collection<RegisteredExtension<A>> extensions;64 privatefinal Context context;60 final Collection<RegisteredExtension<A>> extensions; 61 final Context context; 65 62 private RendererFactory<A> currentRenderFactory; 66 63 … … 69 66 this.extensions = extensions; 70 67 this.context = context; 71 System.out.println("invoker: extensions=" + extensions);72 68 } 73 69 … … 78 74 @return An iterator 79 75 */ 80 public Iterator<A> iterate()76 public ActionIterator<A> iterate() 81 77 { 82 return new ActionIterator ();78 return new ActionIterator<A>(context, extensions.iterator()); 83 79 } 84 80 … … 92 88 public void renderDefault() 93 89 { 94 ActionIterator it = new ActionIterator();90 ActionIterator<A> it = iterate(); 95 91 while (it.hasNext()) 96 92 { … … 121 117 } 122 118 } 123 124 /**125 Internal iterator over all actions. The starting point is to126 iterate over all extensions. Each extension may return127 more than one action.128 */129 private class ActionIterator130 implements Iterator<A>131 {132 private final Iterator<RegisteredExtension<A>> iterator;133 134 // The actions created by the current extension135 private A[] actions;136 // The iterator's offset in the actions array137 private int offset;138 139 // The currently active extension140 private RegisteredExtension<A> currentExtension;141 142 // The renderer for the current action143 private Renderer<A> currentRenderer;144 145 // Cache for created renderers146 private Map<Object, Renderer<A>> rendererCache;147 148 // Boolean flags to indicate if we have a next element and if149 // we need to check or not. If both are 'false' we have reached the end150 private boolean checkNext;151 private boolean hasNext;152 153 154 ActionIterator()155 {156 this.iterator = extensions.iterator();157 this.checkNext = true;158 this.rendererCache = new IdentityHashMap<Object, Renderer<A>>();159 }160 161 public boolean hasNext()162 {163 if (checkNext)164 {165 checkNext = false;166 offset++;167 if (actions != null && offset < actions.length)168 {169 // There are more actions in the array170 hasNext = true;171 }172 else173 {174 // No more actions in the array, move on to the next extension175 currentExtension = null;176 currentRenderer = null;177 actions = null;178 offset = 0;179 hasNext = false;180 181 // Continue until we find an extension that creates at least one182 // action, or until we run out of extensions183 while (iterator.hasNext())184 {185 currentExtension = iterator.next();186 System.out.println("invoker: currentExtension=" + currentExtension);187 188 // Get the actions for the extension189 actions = currentExtension.getActionFactory().getActions(context);190 System.out.println("invoker: actions=" + actions);191 if (actions != null && actions.length > 0)192 {193 System.out.println("invoker: actions=" + actions.length);194 hasNext = true;195 break;196 }197 }198 }199 }200 return hasNext;201 }202 203 public A next()204 {205 if (checkNext) hasNext();206 if (!hasNext) throw new NoSuchElementException();207 checkNext = true;208 return actions[offset];209 }210 211 /**212 Not supported.213 @throws UnsupportedOperationException Always214 */215 public void remove()216 {217 throw new UnsupportedOperationException();218 }219 220 /**221 Get the extension that created the current action.222 */223 RegisteredExtension<A> getExtension()224 {225 return currentExtension;226 }227 228 /**229 Gets the renderer for the current action.230 */231 Renderer<A> getRenderer()232 {233 if (currentRenderer == null)234 {235 RegisteredExtensionPoint<A> ep = currentExtension.getExtensionPoint();236 RendererFactory<A> rf = currentExtension.getRendererFactory();237 if (ep.allowRendererOverride() && rf != null)238 {239 // Use the extension's renderer factory if it is240 // allowed and if one is provided241 currentRenderer = rf.getRenderer(context);242 }243 else244 {245 // We must use the extensions points renderer factory246 // First, check the cache if we already have a renderer247 currentRenderer = rendererCache.get(ep);248 if (currentRenderer == null)249 {250 currentRenderer = ep.getRendererFactory().getRenderer(context);251 rendererCache.put(ep, currentRenderer);252 }253 }254 }255 return currentRenderer;256 }257 }258 119 } -
branches/extensions/src/core/net/sf/basedb/util/extensions/Registry.java
r4163 r4168 27 27 import java.util.Collection; 28 28 import java.util.Collections; 29 import java.util.Comparator;30 29 import java.util.HashMap; 31 30 import java.util.Iterator; … … 164 163 // Create a copy, or the iterator will fail if new 165 164 // extension points are registered by another thread 166 List<ExtensionPoint<?>> copy = new ArrayList<ExtensionPoint<?>>(extensionPoints.values()); 165 List<ExtensionPoint<?>> copy = 166 new ArrayList<ExtensionPoint<?>>(extensionPoints.values()); 167 167 return Collections.unmodifiableList(copy).iterator(); 168 168 } … … 255 255 @param id The ID of the extension point 256 256 @return An {@link Extension} object or null if that 257 extension pointdoesn't exists257 extension doesn't exists 258 258 */ 259 259 public Extension<?> getExtension(String id) … … 273 273 // Create a copy, or the iterator will fail if new 274 274 // extension points are registered by another thread 275 List<Extension<?>> copy = new ArrayList<Extension<?>>(extensions.values()); 275 List<Extension<?>> copy = 276 new ArrayList<Extension<?>>(extensions.values()); 276 277 return Collections.unmodifiableList(copy).iterator(); 277 278 } … … 299 300 // Create a copy, or the iterator will fail if new 300 301 // extension points are registered by another thread 301 List<Extension<?>> copy = new ArrayList<Extension<?>>(rep.getExtensions()); 302 List<Extension<?>> copy = 303 new ArrayList<Extension<?>>(rep.getExtensions()); 304 Collections.sort(copy, DefaultFilter.INDEX_COMPARATOR); 302 305 return Collections.unmodifiableList(copy).iterator(); 303 306 } … … 326 329 327 330 @param context Information about the current context 331 @param filter A filter object that can be used to filter out 332 disabled extensions and sort the extensions in a particular order. 333 If this value is null, no extensions are filtered out and they 334 are sorted according to their {@link Extension#getIndex()} value 328 335 @param extensionPoints An array of extension point ID:s to get 329 336 extension for. In most cases the extension points should … … 333 340 */ 334 341 @SuppressWarnings("unchecked") 335 public ExtensionsInvoker<?> useExtensions(Context context, String... extensionPoints) 336 { 342 public ExtensionsInvoker<?> useExtensions(Context context, ExtensionsFilter filter, String... extensionPoints) 343 { 344 if (filter == null) filter = DEFAULT_FILTER; 337 345 List<RegisteredExtension<Action>> use = new LinkedList<RegisteredExtension<Action>>(); 338 346 for (String id : extensionPoints) 339 347 { 340 RegisteredExtensionPoint<Action> rep = (RegisteredExtensionPoint<Action>)this.extensionPoints.get(id); 341 if (rep != null) 348 RegisteredExtensionPoint<Action> rep = 349 (RegisteredExtensionPoint<Action>)this.extensionPoints.get(id); 350 if (rep != null && filter.isEnabled(rep)) 342 351 { 343 352 for (RegisteredExtension<Action> ext : rep.getExtensions()) 344 353 { 345 if ( ext.getActionFactory().prepareContext(context))354 if (filter.isEnabled(ext) && ext.getActionFactory().prepareContext(context)) 346 355 { 347 356 use.add(ext); … … 350 359 } 351 360 } 352 Collections.sort(use, INDEX_COMPARATOR);361 filter.sort(use); 353 362 return new ExtensionsInvoker<Action>(use, context); 354 363 } 355 364 356 365 /** 357 Comparator used to order extensions by their index value. 358 @see Extension#getIndex() 359 */ 360 private static final Comparator<Extension> INDEX_COMPARATOR = 361 new Comparator<Extension>() 362 { 363 @Override 364 public int compare(Extension o1, Extension o2) 365 { 366 return Float.compare(o1.getIndex(), o2.getIndex()); 367 } 368 }; 369 370 366 Default filter implementation for 367 {@link #useExtensions(Context, ExtensionsFilter, String...)} 368 */ 369 private static final ExtensionsFilter DEFAULT_FILTER = new DefaultFilter(); 370 371 371 /** 372 372 Internal representation of an extension point. … … 378 378 private final String id; 379 379 private final Class<A> actionClass; 380 private String name; 380 381 private String description; 381 382 private RendererFactory<A> rendererFactory; … … 391 392 { 392 393 this.id = ep.getId(); 394 this.name = ep.getName(); 393 395 this.description = ep.getDescription(); 394 396 this.actionClass = ep.getActionClass(); … … 409 411 410 412 @Override 413 public String getName() 414 { 415 return name; 416 } 417 418 @Override 411 419 public String getDescription() 412 420 { … … 436 444 public String toString() 437 445 { 438 return "ExtensionPoint[id="+ id +" ]";446 return "ExtensionPoint[id="+ id +"; name=" + name + "]"; 439 447 } 440 448 … … 444 452 void update(ExtensionPoint<A> ep) 445 453 { 454 this.name = ep.getName(); 446 455 this.description = ep.getDescription(); 447 456 this.rendererFactory = ep.getRendererFactory(); … … 471 480 { 472 481 return this.extensions.values(); 473 } 474 475 } 476 482 } 483 } 484 477 485 /** 478 486 Internal representation of an extension. … … 500 508 this.extensionPoint = extension.getExtends(); 501 509 this.index = extension.getIndex(); 502 this.about = extension.getAbout() == null ? null : new RegisteredAbout(about); 510 this.about = extension.getAbout() == null ? 511 null : new RegisteredAbout(extension.getAbout()); 503 512 this.actionFactory = extension.getActionFactory(); 504 513 this.rendererFactory = extension.getRendererFactory(); … … 551 560 return "Extension[id="+ id +"]"; 552 561 } 553 562 554 563 /** 555 564 Update the registered information. … … 584 593 return rep; 585 594 } 586 } 587 595 } 596 588 597 static class RegisteredAbout 589 598 implements About -
branches/extensions/src/core/net/sf/basedb/util/extensions/XmlLoader.java
r4163 r4168 196 196 id="..." 197 197 > 198 <name>...</name> 198 199 <description>...</description> 199 200 <action-class>...</action-class> … … 218 219 extensionPoint.setId(id); 219 220 220 // Set Description (optional) 221 // Set Name and Description (optional) 222 extensionPoint.setName(Values.getStringOrNull(epTag.getChildText("name", ns))); 221 223 extensionPoint.setDescription(Values.getStringOrNull(epTag.getChildText("description", ns))); 222 224 … … 295 297 ext.setExtends(extensionPoint); 296 298 297 // Set index position ( required)298 ext.setIndex(Values.getFloat(epTag.getChildText("index", ns) ));299 // Set index position (optional, default value = 999) 300 ext.setIndex(Values.getFloat(epTag.getChildText("index", ns), 999.0f)); 299 301 300 302 // Set About (optional) … … 303 305 { 304 306 AboutBean about = new AboutBean(); 307 ext.setAbout(about); 305 308 about.setName(Values.getStringOrNull(aboutTag.getChildText("name", ns))); 306 309 about.setDescription(Values.getStringOrNull(aboutTag.getChildText("description", ns))); -
branches/extensions/www/include/menu.jsp
r4022 r4168 57 57 import="net.sf.basedb.clients.web.util.HTML" 58 58 import="net.sf.basedb.util.Values" 59 import="net.sf.basedb.clients.web.extensions.WebExtensions" 60 import="net.sf.basedb.clients.web.extensions.JspContext" 61 import="net.sf.basedb.clients.web.extensions.menu.MenuItemAction" 62 import="net.sf.basedb.util.extensions.Extension" 63 import="net.sf.basedb.util.extensions.ExtensionsInvoker" 64 import="net.sf.basedb.util.extensions.ActionIterator" 59 65 import="java.util.HashMap" 60 66 import="java.util.ArrayList" 61 67 import="java.util.List" 62 68 import="java.util.Arrays" 69 import="java.util.Iterator" 63 70 %> 64 71 <%@ taglib prefix="m" uri="/WEB-INF/menu.tld" %> … … 942 949 /> 943 950 </m:menu> 951 952 <% 953 // Extensions menu 954 JspContext context = new JspContext(sc); 955 ExtensionsInvoker<MenuItemAction> invoker = 956 (ExtensionsInvoker<MenuItemAction>)WebExtensions.useExtensions(context, 957 "net.sf.basedb.clients.web.menu.extensions"); 958 ActionIterator<MenuItemAction> items = invoker.iterate(); 959 boolean addSeparator = false; 960 %> 961 <m:menu id="extensions" style="display: none"> 962 <% 963 while (items.hasNext()) 964 { 965 MenuItemAction item = items.next(); 966 Extension extension = items.getExtension(); 967 if (item.getType() == MenuItemAction.MenuType.SEPARATOR) 968 { 969 addSeparator = false; 970 %> 971 <m:menuseparator style="<%=item.getStyle()%>" visible="<%=item.isVisible()%>" /> 972 <% 973 } 974 else if (item.getType() == MenuItemAction.MenuType.MENUITEM) 975 { 976 addSeparator = true; 977 %> 978 <m:menuitem 979 style="<%=item.getStyle()%>" 980 title="<%=item.getTitle()%>" 981 icon="<%=WebExtensions.makeAbsolutePath(item.getIcon(), extension)%>" 982 tooltip="<%=item.getTooltip()%>" 983 enabled="<%=item.isEnabled()%>" 984 visible="<%=item.isVisible()%>" 985 onclick="<%=item.getOnClick()%>" 986 /> 987 <% 988 } 989 } 990 if (addSeparator) 991 { 992 %> 993 <m:menuseparator /> 994 <% 995 } 996 %> 997 <m:menuitem 998 title="Reload" 999 onclick="<%="Main.openPopup('"+root+"extensions?reload', 'Reload', 360, 200);"%>" 1000 /> 1001 <m:menuitem 1002 title="Installed extensions" 1003 onclick="<%="Menu.openUrl('"+root+"admin/extensions/index.jsp?ID="+ID+"')"%>" 1004 /> 1005 </m:menu> 1006 944 1007 <% 945 1008 // Main menu … … 972 1035 /> 973 1036 <m:submenu 1037 subid="extensions" 1038 title="Extensions" 1039 /> 1040 <m:submenu 974 1041 subid="help" 975 1042 title="Help" -
branches/extensions/www/include/scripts/main.js
r4003 r4168 1100 1100 { 1101 1101 var url = getRoot()+'common/calendar.jsp?title='+escape(title)+'&form='+form+'&input='+input+'&format='+escape(format); 1102 url += '&ID='+ Main.getIdFromLocation();1102 url += '&ID='+getSessionId(); 1103 1103 if (callback) url += '&callback='+callback; 1104 1104 Main.openPopup(url, title.replace(/[^\w]/, ''), 350, 240); -
branches/extensions/www/views/experiments/bioassaysets/analysis_tree.jsp
r4163 r4168 63 63 import="net.sf.basedb.clients.web.formatter.FormatterFactory" 64 64 import="net.sf.basedb.clients.web.extensions.WebExtensions" 65 import="net.sf.basedb.clients.web.extensions.ActionButton" 66 import="net.sf.basedb.clients.web.extensions.ActionButtonRenderer" 65 import="net.sf.basedb.clients.web.extensions.toolbar.ButtonAction" 67 66 import="net.sf.basedb.clients.web.extensions.JspContext" 68 67 import="net.sf.basedb.util.extensions.Context" … … 237 236 final SessionControl sc = Base.getExistingSessionControl(pageContext, Permission.DENIED, itemType); 238 237 final String ID = sc.getId(); 238 final String rootPath = request.getContextPath()+"/"; 239 239 final ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, null, null); 240 240 final ItemContext tc = sc.getCurrentContext(Item.TRANSFORMATION); … … 281 281 282 282 JspContext jspContext = new JspContext(sc); 283 ExtensionsInvoker< ActionButton> invoker =284 (ExtensionsInvoker< ActionButton>)WebExtensions.REGISTRY.useExtensions(jspContext, "net.sf.basedb.clients.web.bioassayset.list.tools");283 ExtensionsInvoker<ButtonAction> invoker = 284 (ExtensionsInvoker<ButtonAction>)WebExtensions.useExtensions(jspContext, "net.sf.basedb.clients.web.bioassayset.list.tools"); 285 285 %> 286 286 <base:page type="include"> 287 287 <base:body> 288 <% 289 jspContext.setOut(out); 290 jspContext.writeScripts(rootPath); 291 %> 288 292 <script language="JavaScript"> 289 293 var submitPage = '<%=transformationId != 0 ? "../bioassaysets/index.jsp" : "index.jsp"%>';
Note: See TracChangeset
for help on using the changeset viewer.