Junos Space SDK > Developer Guides > Junos Space Application Developer Guide > Programming with the Junos Space SDK > Developing Junos Space Applications > Creating REST Services

Primary and Secondary Collections

Primary Collections

A primary collection is a collection of objects that can be accessed using a URI. For example, the URI /api/space/user-management/users gives you access to a collection termed users, containing a list of user objects.

A URI may provide PUT/POST methods, which you can use to add or remove objects from the primary collection. You cannot use these methods to delete or modify the original object state. You can only change their association with the collection.

Inside a primary collection, each object contains a URI to itself. The URI provides access to detailed information about the object. To modify the object you have to execute methods supported on this URI.

The following is an example of a primary collection "users" that is accessed through /api/space/user-management/users.

<users uri="/api/space/user-management/users">  
 <user uri="/api/space/user-management/user/518" href="/api/space/user-management/user/518">
  <id>518</id>
  <name>super</name>
  <primaryEmail>super@juniper.net</primaryEmail>
  <method href="/api/space/user-management/email-user/518" desc="email this user"/>
 </user>
 <user uri="/api/space/user-management/user/519" href="/api/space/user-management/user/519">
  <id>519</id>
  <name>test</name>
  <primaryEmail>test@juniper.net</primaryEmail>
  <method href="/api/space/user-management/email-user/519" desc="email this user"/>
 </user>
</users>

To explain how primary collections are implemented, a set of code sections comprising a REST interface, its implementation, and a Java class named Users (as a primary collection) is given below.

@Path("/user-management")  //Root level URI for the service.
public interface JSUserMgmtSvc {
  @Path("/users")
  @GET
  @Produces("application/vnd.net.juniper.space.user-management.users+json;version=1")
  public Collection<Users> getAllUsers();
}

 

public class JSUserMgmtSvcImpl implements JSUserMgmtSvc {
  public Collection getAllUsers()
  {
     UserManager userManager = (UserManager) JxServiceLocator.lookup("cmp.sm.UserManagerEJB);
     if (obj == null)
     {
       throwWebApplicationException(Status.INTERNAL_SERVER_ERROR, "Unable to locate UseManager Bean");
     }

     // Invoke UserManager API to get all the Users. As UserTO.
     // Perform transformation of UserTO to Users

     return; //Collection of users
  }
}

import net.juniper.jmp.interceptors.hateoas.HATEOAS;
import net.juniper.jmp.interceptors.hateoas.HATEOASMethodObject;
import net.juniper.jmp.interceptors.hateoas.HATEOASMethod;
import java.util.Collection;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
public class Users {
  @XmlAttribute(name = "uri")
  private String uri;

  /**
   * @return the uri
   */
  @HATEOAS(uri = "")
  public String getUri() {
    return uri;
  }

  /**
   * @param uri
   *          the uri to set
   */
  public void setUri(String uri) {
    this.uri = uri;
  }

  /**
   * Class: User Description: This is a User Bean class.
   * 
   * @author john doe
   * @version 1.0
   */
  public static class User {
    private int id;
    private String name;
    private String primaryEmail;
    private String primaryPhone;
    private String uri;

    @XmlElement(name = "method")
    @HATEOASMethod(href = "/email-user/{id}", 
                   description = "email this user", 
                   context = HATEOAS.LinkTypeEnum.APPLICATION)
    private HATEOASMethodObject emailUser;

    @XmlElement(name = "method")
    public int getId() {
      return id;
    }

    public void setId(int id) {
      this.id = id;
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public String getPrimaryEmail() {
      return primaryEmail;
    }

    public void setPrimaryEmail(String primaryEmail) {
      this.primaryEmail = primaryEmail;
    }

    public String getPrimaryPhone() {
      return primaryPhone;
    }

    public void setPrimaryPhone(String primaryPhone) {
      this.primaryPhone = primaryPhone;
    }

    /**
     * @return the uri
     */
    @XmlAttribute(name = "uri")
    public String getUri() {
      return uri;
    }

    /**
     * @param uri
     *          the uri to set
     */

    public void setUri(String uri) {
      this.uri = uri;
    }

  }

  public Users() {

  }

  public User createUser() {
    return new User();
  }

  @HATEOAS(uri = "/{id}")
  public Collection getUser() {
    return user;
  }

  public void setUser(Collection user) {
    this.user = user;
  }

  private Collection user;
}

To read more about building HATEOAS references (URI and href), see Overview of HATEOAS.

Secondary Collections (collection of references)

A secondary collection contains references to objects in a primary collection. For example, /api/space/user-management/users/{id} returns a user object that contains a list of roles assigned to it. The user object refers to the roles present in the primary collection at /api/space/user-management/roles.

Any modification/deletion done of a secondary collection do not affect the primary collection of objects. It only changes the mapping between the object and secondary collection.

Given below is a sample in XML output for a user object accessed through /api/space/user-management/user/518. Here a collection of roles for this user is a secondary collection. Executing a POST method on this API removes the mapping between the USER object and the secondary collection of roles. It does not change the primary collection of roles accessed by /api/space/user-management/roles.

<user uri="/api/space/user-management/user/518">
 <id>518</id>
 <name>super</name>
  <roles uri="/api/space/user-management/users/518/roles" >
   <role uri="/api/space/user-management/users/518/roles/555" href="/api/space/user-management/roles/555" >
    <id>555</id>
        <name>super</name> 
   </role>
   <role uri="/api/space/user-management/users/518/roles/657" href="/api/space/user-management/roles/657" >
         <id>657</id>
        <name>test</name> 
   </role>
  </roles>
</user>

In the previous example, the collection of roles is a secondary collection inside the user object. Each object in the secondary collection has a href that gives the role object from the primary collection. Similarly, the URI gives the role object from the secondary collection

To explain the implementation of secondary collections, examples are given below that comprises a REST interface, its implementation, and a Java class named User, containing a collection of roles assigned to user as a secondary collection.

@Path("/user-management")
// Root level URI for the service.
public interface JSUserMgmtSvc {

  @Path("/user/{id}")
  @GET
  @Produces("application/vnd.net.juniper.space.user-management.user+json;version=1")
  public User getUserById(@PathParam("id") int id);

}

public JSUserMgmtSvcImpl implements JSUserMgmtSvc
{
  public User getUserById( @PathParam( "id" ) int id  ) ;
  {
    UserManager userManager = (UserManager) JxServiceLocator.lookup("cmp.sm.UserManagerEJB);
    if (obj == null)
    {
      throwWebApplicationException(Status.INTERNAL_SERVER_ERROR, "Unable to locate UseManager Bean");
    }
    // Invoke UserManager API to get a user by id. As UserTO.
    // Perform transformation of UserTO to Users
    return; //Collection of users
  }
}

package net.juniper.jmp.cmp.systemService.service.dto.v1;

import net.juniper.jmp.interceptors.hateoas.HATEOASMethodObject;
import net.juniper.jmp.interceptors.hateoas.HATEOASMethod;
import net.juniper.jmp.interceptors.hateoas.HATEOAS;
import net.juniper.jmp.websvc.common.CommonConstants;
import javax.xml.bind.annotation.*;
import java.sql.Timestamp;
import java.util.Collection;

@XmlRootElement(name = "user")
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
  @XmlElement(name = "id", required = false)
  private Integer id;

  @XmlElement(name = "name", required = true)
  private String name;
  
  private Roles roles;
  
  @XmlAttribute(name = "uri")
  @HATEOAS(uri = "")
  private String uri;

  public String getUri() {
    return uri;
  }

  public void setUri(String uri) {
    this.uri = uri;
  }

  public Integer getId() {
    return id;
  }

  public void setId(Integer id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @HATEOAS(uri = "/roles")
  public Roles getRoles() {
    return roles;
  }

  public void setRoles(Roles roles) {
    this.roles = roles;
  }

  public static class Roles {

    @HATEOAS(href = "/roles/{id}", uri = "/{id}")
    private Collection userRoles;

    @XmlElement(name = "role")
    public Collection getUserRoles() {
      return userRoles;
    }

    public void setUserRoles(Collection roles) {
      this.userRoles = roles;
    }

    private String link;

    @XmlAttribute(name = "href")
    public String getLink() {
      return link;
    }

    public void setLink(String link) {
      this.link = link;
    }

    private String uri;

    @XmlAttribute(name = "uri")
    public String getUri() {
      return uri;
    }

    public void setUri(String uri) {
      this.uri = uri;
    }
    
    public static class UserRole{

      /**
       * User Role Id.
       */

      private int id;

      /**
       * Name of the user role.
       */
      private String name;

      /**
       * Link to a User Role.
       */
      private String link;

      private String uri;

      /**
       * The default constructor
       */

      public UserRole() {
      }

      /**
       * User Role Id.
       */
      public int getId() {
        return id;
      }

      public void setId(int roleId) {
        this.id = roleId;
      }

      /**
       * Name of the user role.
       */

      public String getName() {
        return name;
      }

      public void setName(String roleName) {
        this.name = roleName;
      }

      /**
       * Link to a user role.
       */
      @XmlAttribute(name = "href")
      public String getLink() {
        return link;
      }

      public void setLink(String link) {
        this.link = link;
      }

      /**
       * Link to a user role.
       */

      @XmlAttribute(name = "uri")
      public String getUri() {
        return uri;
      }

      public void setUri(String uri) {
        this.uri = uri;
      }
    }
  }
}

To read more about building HATEOAS references (URI and href), see the Overview of HATEOAS section.

HTTP Methods Supported on Primary and Secondary Collections

The HTTP methods supported by primary and secondary collections, and operations performed on the collections, are listed in the following table.

HTTP Method Supported? Primary Collection Secondary Collection
GET YES Return the collection of all objects. Return the collection of objects mapped to a particular resource.
POST YES Create a new object and add in the primary collection. Update the mappings in secondary collection between existing objects in primary collection and resource.
PUT NO NA NA
DELETE NO NA NA