Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

2. Create a pom.xml in cloudstack/plugins/api/timeofday. Make sure your "parent" relative path points back to plugins/pom.xml, otherwise it won't build. The main entries that matter are the artifactId (cloud-plugin-timeofday), as well as the dependencies.

Code Block
borderStylesolid
langxml
titleplugins/api/timeofday/pom.xml
borderStylesolid
langxml
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <artifactId>cloud-plugin-api-timeofday</artifactId>
      <name>Apache CloudStack Plugin - TimeOfDay</name>
      <parent>
        <groupId>org.apache.cloudstack</groupId>
        <artifactId>cloudstack-plugins</artifactId>
        <version>4.1.0-SNAPSHOT</version>
        <relativePath>../../pom.xml</relativePath>
      </parent>
      <dependencies>
        <dependency>
          <groupId>org.apache.cloudstack</groupId>
          <artifactId>cloud-api</artifactId>
          <version>${project.version}</version>
        </dependency>
        <dependency>
          <groupId>org.apache.cloudstack</groupId>
          <artifactId>cloud-utils</artifactId>
          <version>${project.version}</version>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>${cs.mysql.version}</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
      <build>
        <defaultGoal>install</defaultGoal>
        <sourceDirectory>src</sourceDirectory>
        <testSourceDirectory>test</testSourceDirectory>
        <plugins>
          <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
              <skipTests>true</skipTests>
            </configuration>
            <executions>
              <execution>
                <phase>integration-test</phase>
                <goals>
                  <goal>test</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </project>

...

6. Create an interface that extends from PluggableService

Code Block
borderStylesolid
langjava
titleplugins/api/timeofday/src/com/cloud/test/TimeOfDayManager.java
borderStylesolid
langjava
package com.cloud.test;

import com.cloud.utils.component.PluggableService;

public interface TimeOfDayManager extends PluggableService { }

7. Create an implementation of your newly created interface, overriding the getCommands method, and populating it with the classes of each command you want to expose.

Code Block
borderStylesolid
langjava
titleplugins/api/timeofday/src/com/cloud/test/TimeOfDayManagerImpl.java
borderStylesolid
langjava
package com.cloud.test;

import com.cloud.utils.component.PluggableService;
import java.util.List;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import com.cloud.test.GetTimeOfDayCmd;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import javax.ejb.Local;

@Component
@Local(value = { TimeOfDayManager.class })
public class TimeOfDayManagerImpl implements TimeOfDayManager {
    private static final Logger s_logger = Logger.getLogger(TimeOfDayManagerImpl.class);

    public TimeOfDayManagerImpl() {
        super();
    }

    @Override
    public List<Class<?>> getCommands() {
        List<Class<?>> cmdList = new ArrayList<Class<?>>();
        cmdList.add(GetTimeOfDayCmd.class);
        return cmdList;
    }
}

8. Write a command class that implements the correct annotations for a command:: (Note: (1) by using authorized annotation, we can enabled this API by default for a given set of role types, (2) by using the validations annotation on @Parameter field we can perform ApiArgValidator.NotNullOrEmpty checks on string types and ApiArgValidator.PositiveNumber on number types such as short, int, long.)

Code Block
borderStylesolid
langjava
titleplugins/api/timeofday/src/com/cloud/test/GetTimeOfDayCmd.java
package com.cloud.test;

import javax.inject.Inject;
import org.apache.log4j.Logger;

import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.acl.RoleType;
 
@APICommand(name = "getTimeOfDay", description="Get Cloudstack's time of day", responseObject = GetTimeOfDayCmdResponse.class, includeInApiDoc=true, authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class GetTimeOfDayCmd extends BaseCmd {
    public static final Logger s_logger = Logger.getLogger(GetTimeOfDayCmd.class.getName());
    private static final String s_name = "gettimeofdayresponse";

    @Parameter(name="example", type=CommandType.STRING, required=false, description="Just an example string that will be uppercased",  validations = {ApiArgValidator.NotNullOrEmpty})
    private String example;

    public String getExample() {
        return this.example;
    }

    @Override
    public void execute()
    {
        GetTimeOfDayCmdResponse response = new GetTimeOfDayCmdResponse();
        response.setExampleEcho(example);
     
        response.setObjectName("timeofday"); // the inner part of the json structure
        response.setResponseName(getCommandName()); // the outer part of the json structure

        this.setResponseObject(response);
    }

    @Override
    public String getCommandName() {
        return s_name;
    }

    @Override
    public long getEntityOwnerId() {
        return 0;
    }
}

9. Write a Response class for the command:

Code Block
borderStylesolid
langjava
titleplugins/api/timeofday/src/com/cloud/test/GetTimeOfDayCmdResponse.java
package com.cloud.test;

import org.apache.cloudstack.api.ApiConstants;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;

import java.util.Date;
import java.text.SimpleDateFormat;

@SuppressWarnings("unused")
public class GetTimeOfDayCmdResponse extends BaseResponse {
    @SerializedName(ApiConstants.IS_ASYNC) @Param(description="true if api is asynchronous")
    private Boolean isAsync;
    @SerializedName("timeOfDay") @Param(description="The time of day from CloudStack")
    private String  timeOfDay;
    @SerializedName("exampleEcho") @Param(description="An upper cased string")
    private String  exampleEcho;

    public GetTimeOfDayCmdResponse(){
Code Block
titleplugins/api/timeofday/src/com/cloud/test/GetTimeOfDayCmd.java
borderStylesolid
langjava
package com.cloud.test;

import javax.inject.Inject;
import org.apache.log4j.Logger;

import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.Parameter;

@APICommand(name = "getTimeOfDay", description="Get Cloudstack's time of day", responseObject = GetTimeOfDayCmdResponse.class, includeInApiDoc=true)
public class GetTimeOfDayCmd extends BaseCmd {
    public static final Logger s_logger = Logger.getLogger(GetTimeOfDayCmd.class.getName());
    private static final String s_name = "gettimeofdayresponse";

    @Parameter(name="example", type=CommandType.STRING, required=false, description="Just an example string that will be uppercased")
    private String example;

    public String getExample() {
        return this.example;
    }

    @Override
    public void execute()
    {
        GetTimeOfDayCmdResponse response = new GetTimeOfDayCmdResponse();
        if ( this.example != null ) {
            response.setExampleEcho(example);
        }

        response.setObjectName("timeofday"); // the inner part of the json structure
this.isAsync   = false;

        SimpleDateFormat dateformatYYYYMMDD = new response.setResponseName(getCommandName()); // the outer part of the json structure

        this.setResponseObject(responseSimpleDateFormat("yyyyMMdd hh:mm:ss");
        this.setTimeOfDay( (new StringBuilder( dateformatYYYYMMDD.format( new Date() ) )).toString() );
    }

    @Override
    public Stringvoid getCommandNamesetAsync(Boolean isAsync) {
        this.isAsync return= s_nameisAsync;
    }

    @Override

    public longboolean getEntityOwnerIdgetAsync() {
        return 0;
    }
}

9. Write a Response class for the command:

   return isAsync;
    }

    public void setTimeOfDay(String timeOfDay) {
        this.timeOfDay = timeOfDay;
    }

    public void setExampleEcho(String exampleEcho) {
        this.exampleEcho = exampleEcho.toUpperCase();
    }
}

10. Update client/tomcatconf/componentContext.xml.in and add your new manager to its configuration:

Code Block
borderStylesolid
langxml
<bean id="timeOfDayManagerImpl" class="com.cloud.test.TimeOfDayManagerImpl"> </bean>

The above is now obsolete (at least since 4.5.0, please fix the exact version here). Instead in your plugin folder you need to add this context, for example in this case:

  a. Add modules.properties under plugins/api/timeofday/resources/META-INF/cloudstack/timeofday with following content:

Code Block
        name=timeofday
        parent=api

b. Add spring-timeofday-context.xml under plugins/api/timeofday/resources/META-INF/cloudstack/timeofday with following content:

Code Block
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
   
Code Block
titleplugins/api/timeofday/src/com/cloud/test/GetTimeOfDayCmdResponse.java
borderStylesolid
langjava
package com.cloud.test;

import org.apache.cloudstack.api.ApiConstants;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;

import java.util.Date;
import java.text.SimpleDateFormat;

@SuppressWarnings("unused")
public class GetTimeOfDayCmdResponse extends BaseResponse {
    @SerializedName(ApiConstants.IS_ASYNC) @Param(description="true if api is asynchronous")
    private Boolean isAsync;
    @SerializedName("timeOfDay") @Param(description="The time of day from CloudStack")
    private String  timeOfDay;
    @SerializedName("exampleEcho") @Param(description="An upper cased string")
    private String  exampleEcho;

    public GetTimeOfDayCmdResponse(){
        this.isAsync   = false;

        SimpleDateFormat dateformatYYYYMMDD = new SimpleDateFormat("yyyyMMdd hh:mm:ss");
        this.setTimeOfDay( (new StringBuilder( dateformatYYYYMMDD.format( new Date() ) )).toString() );
    }
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    public void setAsync(Boolean isAsync) {
        this.isAsync = isAsync;
    }

    public boolean getAsync() {http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        return isAsync;
    }

    public void setTimeOfDay(String timeOfDay) {
        this.timeOfDay = timeOfDay;
    }
 http://www.springframework.org/schema/context
    public void setExampleEcho(String exampleEcho) {
        this.exampleEcho = exampleEcho.toUpperCase();
    }
}

10. Update client/tomcatconf/componentContext.xml.in and add your new manager to its configuration:

Code Block
borderStylesolid
langxml
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="timeOfDayManagerImpl" class="com.cloud.test.TimeOfDayManagerImpl"> </bean>

The above is now obsolete. Instead in your plugin folder you need to add this context, for example in this case:

 

 

 

</beans>

11. For CloudStack version 4.8.x and below update 11. Update client/tomcatconf/commands.properties.in, and add the command name (for the example this would be getTimeOfDay as stated in the @APICommand annotation). For CloudStack 4.9.x and above, the commands.properties.in way has been deprecated and API authors are encouraged to enable their API by default using authorized annotation as in the example above which can be used to enable the API for a given set of user role types.

12. Along with this you need to add your plugin as a dependency to client/pom.xml. You will see examples within the pom, you will require your plugins artifact ID.

...