Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Developer guidelines for building fluent model and collection #681

Closed
anuchandy opened this issue May 5, 2016 · 1 comment
Closed

Developer guidelines for building fluent model and collection #681

anuchandy opened this issue May 5, 2016 · 1 comment

Comments

@anuchandy
Copy link
Member

anuchandy commented May 5, 2016

This is an incomplete and changing spec for building models and collections in the new fluent SDK (master branch).

Example service

The example we use to demonstrate the guidelines is Azure Pet store management client. It has a Pets collection which supports all kinds of operations on type Pet.

Pets reside in resource group and have a location property.

Where AutoRest generated types reside?

AutoRest emits the following artifacts to implementation/api directory:

├── implementation/
│   ├── api/
│   │    ├── PetManagementClientImpl.java
│   │    ├── PetsInner.java
│   │    ├── PetInner.java
│   │    ├── Profile.java

Terminology

Top level model : Inner models that represents service request or response payload. In our example PetInner.java is a top level model.

Given below a sample payload to create a Pet entry.

{
  "id": 12345
  "name": "jacky"
  "age": 5
  "profile": {
    "homeless": true
    "weight": 25lb
  }
}

Non-top level model : These are usually simple models, the top level model composed of these models. In our example, PetInner.java composes Profile.java.

Where Fluent model and collection types reside?

interfaces

The definition of fluent interfaces for each collection and top level model should reside in the same level as implementation directory.

e.g. Pets.java (fluent collection interface) and Pet.java (fluent model interface)

├── Pets.java
├── Pet.java
├── implementation/
│   ├── api/
│   │    ├── PetManagementClientImpl.java
│   │    ├── PetsInner.java
│   │    ├── PetInner.java
│   │    ├── Profile.java

Note that Profile.java is a non-top level model so there is no fluent model interface for this.

implementations

Implementation for fluent model and collection interfaces should reside under implementation directory.

e.g. PetsImpl.java (fluent collection implementation) and PetImpl.java (fluent model implementation)

├── Pets.java
├── Pet.java
├── implementation/
│   ├── api/
│   │    ├── PetManagementClientImpl.java
│   │    ├── PetsInner.java
│   │    ├── PetInner.java
│   │    ├── Profile.java
│   ├── PetStoreManager.java
│   ├── PetsImpl.java
│   ├── PetImpl.java

Authoring fluent types

  • Fluent Models
  • Fluent Collections
  • Fluent Manager

Fluent models

Pet.java

// public access
public interface Pet
        extends GroupableResource {
}

PetImpl.java

// internal accessed impl
class PetImpl implements Pet {
    // internal accessed constructor
    // takes an inner model and inner collection
    PetImpl(PetInner innerModel, PetsInner client, ResourceGroups resourceGroups) {
        super(innerModel.id(), innerModel, resourceGroups);
    }

    /* Some other methods to implement */

    @Override
    public void refresh() throws CloudException, IOException {
        this.setInner(client.get(innerModel.id()));
        return this;
    }
}

Fluent collections

Pets.java

// public access
public interface Pets extends
        SupportsCreating<Pet.DefinitionBlank>,
        SupportsListing<Pet>,
        SupportsListingByGroup<Pet>,
        SupportsGetting<Pet>,
        SupportsGettingByGroup<Pet>,
        SupportsDeleting,
        SupportsDeletingByGroup {
    // public access from external will be 
    public interface InGroup extends
            SupportsListing<Pet>,
            SupportsGetting<Pet>,
            SupportsCreating<Pet.DefinitionWithGroup>,
            SupportsDeleting  {
    }
}

Pets interface represents the operations that can be performed on the Pets collection across all resource groups in the service.

Pets.InGroup represents the operations that can be performed on the Pets collection in a specific resource group.

Since the most common operations that can be performed on a collection are CRUD, these operations are extracted out as runtime interfaces. The fluent collection interface extends from these runtime interfaces. Refer the section Runtime CRUD interfaces for details.

PetsImpl.java

// internal accessed class
final class PetsImpl implements Pets {
    // internal constructor
    PetsImpl(PetsInner client, ResourceGroups resourceGroups) {
    }

   // Implementation of CRUD interfaces
   ....
}

PetsInGroupImpl.java

// internal accessed class
final class PetsInGroupImpl implements Pets.InGroup {
    // internal constructor
    PetsInGroupImpl(Pets pets, ResourceGroup resourceGroup) {
    }

   // implementation of Group-level CRUD interfaces
   ....
}

Fluent manager

Manager serve as a container for all fluent collections associated with a service. Each manager will have 3 static methods that consumers can use to authenticate and get an instance of manager.

public final class PetStoreManager {

   // authenticate with configuration
   public static Configurable configurable() {
     return new PetStoreManager().new ConfigurableImpl(); }
   }

    // authenticate with default configuration
    public static PetStoreManager authenticate(ServiceClientCredentials credentials, String subscriptionId) {
       return new PetStoreManager(credentials, subscriptionId);
    }

    // authenticate using pre-configured RestClient
    public static PetStoreManager authenticate(RestClient restClient, String subscriptionId) {
       return new PetStoreManager(restClient, subscriptionId);
    }

    public interface Configurable extends AzureConfigurable<Configurable> {
       PetStoreManager authenticate(ServiceClientCredentials credentials, String subscriptionId);
    }

    final class ConfigurableImpl extends AzureConfigurableImpl<Configurable> implements  Configurable {
        public PetStoreManager authenticate(ServiceClientCredentials credentials, String subscriptionId)   {
          buildRestClient(credentials);
          return PetStoreManager.authenticate(restClient, subscriptionId);
        }
    }

    // PetStoreManager constructors
    ....

    // The fluent collection getters
    public Pets pets() {
      ...
    } 
}

Runtime CRUD interfaces

Each fluent collection interface (e.g. Pets.java) should expose methods that allows users to perform C (Create), R (Read), U (Update) and D (Delete) operations on the collection. Exposing one of these method depends on whether service supports corresponding operation or not.

Create interface

public interface SupportsCreating<T> {
    T define(String name) throws Exception;
}

Read interfaces

public interface SupportsListing<T> {
    PagedList<T> list() throws CloudException, IOException;
}
public interface SupportsGetting<T> {
    T get(String name) throws CloudException, IOException;
}
public interface SupportsListingByGroup<T> {
    PagedList<T> list(String groupName) throws CloudException, IOException;
}
public interface SupportsGettingByGroup<T> {
    T get(String groupName, String name) throws CloudException, IOException;
}

Update interface

public interface SupportsUpdating<T> {
    T update(String name);
}

Delete interface

public interface SupportsDeleting {
    void delete(String id) throws Exception;
}
public interface SupportsDeletingByGroup {
     void delete(String groupName, String name) throws Exception;
}

Example

@Azure Azure locked and limited conversation to collaborators May 5, 2016
@Azure Azure unlocked this conversation May 5, 2016
@jianghaolu
Copy link
Contributor

Closing as 1.0.0-beta2 released.

@github-actions github-actions bot locked and limited conversation to collaborators Apr 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants