com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links' is unknown.

AppDeploymentHandler

Depending on the Carbon product you are working with, you may sometimes need to deploy new artifacts such as axis archives (aar), web archives (war), composite applications (C-app or car files) or custom archives for your product. The deployment of these different types of archives use different flows.

For example, a Composite Application (C-App) is a collection of artifacts deployable on a WSO2 product instance. C-App files have CAR extensions and can be deployed to different runtimes. Each runtime will only deploy the artifacts that match the role performed by the runtime. For example, an ESB runtime will not deploy a data service in the CAR file, unless the default configuration is altered.

Therefore, it is the responsibility of deployment handlers to check the roles that are performed by the archive and perform the necessary deployment procedure. Carbon products are shipped with a set of built-in deployment handlers. However, if the users have their own archive types, they can create their custom deployment handlers and add the required deployment logic. The AppDeploymentHandler interface is provided by WSO2 Carbon as an extension point to implement your custom deployment handlers. 

The following sections will guide you on how to create your custom deployment handler:


Step 1: Implementing the AppDeploymentHandler

The code segment shown below illustrates a sample implementation of the AppDeployementHandler interface for a web archive. You can find a complete implementation of the same interface from this link.

package org.wso2.carbon.application.deployer.webapp;

import org.apache.axis2.deployment.Deployer;
import org.apache.axis2.deployment.DeploymentException;
import org.apache.axis2.deployment.repository.util.DeploymentFileData;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.application.deployer.AppDeployerConstants;
import org.wso2.carbon.application.deployer.AppDeployerUtils;
import org.wso2.carbon.application.deployer.CarbonApplication;
import org.wso2.carbon.application.deployer.config.Artifact;
import org.wso2.carbon.application.deployer.config.CappFile;
import org.wso2.carbon.application.deployer.handler.AppDeploymentHandler;
import org.wso2.carbon.application.deployer.webapp.internal.WARCappDeployerDSComponent;

import java.io.File;
import java.util.List;
import java.util.Map;

public class WARCappDeployer implements AppDeploymentHandler {

   /**
    *
    * @param carbonApp  - CarbonApplication instance to check for WAR artifacts
    * @param axisConfig - axisConfig of the current tenant
    */
   public void deployArtifacts(CarbonApplication carbonApp, AxisConfiguration axisConfig)
           throws DeploymentException {
       List<Artifact.Dependency> artifacts = carbonApp.getAppConfig().getApplicationArtifact()
               .getDependencies();

       // loop through all artifacts
       for (Artifact.Dependency dep : artifacts) {
        // your deployment logic goes here
       }
   }

   /**
    *
    * @param carbonApp  - CarbonApplication instance to check for WAR artifacts
    * @param axisConfig - AxisConfiguration of the current tenant
    */
   public void undeployArtifacts(CarbonApplication carbonApp, AxisConfiguration axisConfig) {
                  // your undeployment logic goes here
   }
}

Step 2: Registering the new handler implementation

Once the implementation is complete, you need to register this in the OSGi bundle context as a service. Then, the runtime will pick all the services registered under the AppDeploymentHandler interface and will execute the relevant methods. Now, let's register this service through WARCappDeployerDSComponent, which is a declarative service. Shown below is a sample implementation. You can find a proper implementation for WARCappDeployerDSComponent from this link.

package org.wso2.carbon.application.deployer.webapp.internal;

import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.application.deployer.AppDeployerConstants;
import org.wso2.carbon.application.deployer.AppDeployerUtils;
import org.wso2.carbon.application.deployer.Feature;
import org.wso2.carbon.application.deployer.handler.AppDeploymentHandler;
import org.wso2.carbon.application.deployer.webapp.WARCappDeployer;

import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.Map;

/**
* @scr.component name="application.deployer.war" immediate="true"
*/
public class WARCappDeployerDSComponent {

   private static Log log = LogFactory.getLog(WARCappDeployerDSComponent.class);

//    private static ApplicationManagerService applicationManager;
   private static Map<String, List<Feature>> requiredFeatures;

   private static ServiceRegistration appHandlerRegistration;

   protected void activate(ComponentContext ctxt) {
       try {
           //register war deployer as an OSGi service
           WARCappDeployer warDeployer = new WARCappDeployer();
           appHandlerRegistration = ctxt.getBundleContext().registerService(
                   AppDeploymentHandler.class.getName(), warDeployer, null);

           // read required-features.xml
           URL reqFeaturesResource = ctxt.getBundleContext().getBundle()
                   .getResource(AppDeployerConstants.REQ_FEATURES_XML);
           if (reqFeaturesResource != null) {
               InputStream xmlStream = reqFeaturesResource.openStream();
               requiredFeatures = AppDeployerUtils
                       .readRequiredFeaturs(new StAXOMBuilder(xmlStream).getDocumentElement());
           }
       } catch (Throwable e) {
           log.error("Failed to activate WAR Capp Deployer", e);
       }
   }

   protected void deactivate(ComponentContext ctxt) {
       // Unregister the OSGi service
       if (appHandlerRegistration != null) {
           appHandlerRegistration.unregister();
       }
   }

   public static Map<String, List<Feature>> getRequiredFeatures() {
       return requiredFeatures;
   }

}

Step 3: Deploying the OSGi bundle

Finally, the 2 classes explained above (AppDeployementHandler and WARCappDeployerDSComponent) need to be bundled as an OSGi bundle and deployed in your Carbon product. Add the following plugins under the build tag of the pom.xmlThe maven-src-plugin is required to create the osgi-inf content from the class level annotations. The maven-bundle-plugin is required to create the OSGi bundle.

<plugin>
   <groupId>org.apache.felix</groupId>
   <artifactId>maven-scr-plugin</artifactId>
</plugin>
<plugin>
   <groupId>org.apache.felix</groupId>
   <artifactId>maven-bundle-plugin</artifactId>

   <extensions>true</extensions>
   <configuration>
       <instructions>
           <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
           <Bundle-Name>${project.artifactId}</Bundle-Name>
           <Private-Package>org.wso2.carbon.application.mgt.webapp.internal</Private-Package>
           <Import-Package>
               org.wso2.carbon.application.deployer.*,
               *;resolution:=optional
           </Import-Package>
           <Export-Package>
               org.wso2.carbon.application.mgt.webapp
           </Export-Package>
           <DynamicImport-Package>*</DynamicImport-Package>
       </instructions>
   </configuration>
</plugin>
com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links2' is unknown.