Action API

Last modified by Vincent Massol on 2024/07/05 17:43

cogAPI to execute Resources
TypeJAR
Category
Developed by

XWiki Development Team

Rating
0 Votes
LicenseGNU Lesser General Public License 2.1
Bundled With

XWiki Standard

Compatibility

Since 6.0M1

Description

This module has been removed in XWiki 6.1M2. It has been folded into the Resource module.

This module is the entry point for all UIs and in charge of calling the correct backend code to display what the user has asked for (it's the Controller in MVC terminology).

Right now most Actions are still implemented the old way in the oldcore module without Components and using Struts. The goal is to progressively rewrite them using this new Action API.

This API supports the following use cases:

  • UC1: Actions should be able to be added without touching at the existing platform code (i.e. someone could write a new action in java and plug it in)
  • UC2: It should be possible to execute something before or after an Action's execution.
  • UC3: It should be possible to completely replace an Action with another implementation.
  • UC4: It should be possible to add Actions without stopping the running XWiki instance
  • UC5: Actions should not know about each other
  • UC6: Actions should be independent of the URL formats used
  • UC7: Actions should work for both Entity Resources and other Resources (such as static resources, skin resources, etc)
  • UC8: It should be possible for an Action to be registered for one action, a list of actions or all actions

API

Here  are the main API classes and methods (check the Resource API which is tied to this module):

  • ActionManager: Its main execute(Resource) method is in charge of executing the passed Resource by locating the Action Components for the Action Id associated to the Resource.
  • Action:  Executes the Action for the passed Resource.
    @Role
    public interface Action extends Comparable<Action>
    {
       /**
         * The priority of execution relative to the other Actions. The lowest values have the highest priorities and
         * execute first. For example a Action with a priority of 100 will execute before one with a priority of 500.
         *
         * @return the execution priority
         */

       int getPriority();

       /**
         * @return the list of Action Ids supported by this Action
         */

        List<ActionId> getSupportedActionIds();

       /**
         * Executes the Action on the passed Resource.
         *
         * @param resource the Resource on which to execute the Action
         * @param chain the Action execution chain, needed to tell the next Action in the chain to execute (similar to the
         *        Filter Chain in the Servlet API)
         * @throws ActionException if an error happens during the Action execution
         */

       void execute(Resource resource, ActionChain chain) throws ActionException;
    }

Action Example

@Component
@Named("webjars")
public class WebJarsAction extends AbstractAction
{
   /**
     * The WebJars Action Id.
     */

   public static final ActionId WEBJARS = new ActionId("webjars");

   /**
     * Prefix for locating JS resources in the classloader.
     */

   private static final String WEBJARS_RESOURCE_PREFIX = "META-INF/resources/webjars/";

   @Inject
   private Container container;

   @Override
   public List<ActionId> getSupportedActionIds()
   {
       return Arrays.asList(WEBJARS);
   }

   @Override
   public void execute(Resource resource, ActionChain chain) throws ActionException
   {
        EntityResource entityResource = (EntityResource) resource;
        String resourceName = entityResource.getParameterValue("value");
        String resourcePath = String.format("%s%s", WEBJARS_RESOURCE_PREFIX, resourceName);

        InputStream resourceStream = getClassLoader().getResourceAsStream(resourcePath);

       if (resourceStream != null) {
           try {
                IOUtils.copy(resourceStream, this.container.getResponse().getOutputStream());
           } catch (IOException e) {
               throw new ActionException(String.format("Failed to read resource [%s]", resourceName), e);
           } finally {
                IOUtils.closeQuietly(resourceStream);
           }
       }
   }

   /**
     * @return the Class Loader from which to look for WebJars resources
     */

   protected ClassLoader getClassLoader()
   {
       // Load the resource from the context class loader in order to support webjars located in XWiki Extensions
       // loaded by the Extension Manager.
       return Thread.currentThread().getContextClassLoader();
   }
}

Get Connected