UmprCoreRepositories

Kevin Brightwell edited this page Aug 26, 2015 · 2 revisions
Clone this wiki locally

Introduction

This page will act as a tutorial for creating a new Repository for Umpr. All code used in this tutorial can be found here. There are incremental Code markers after each section used to show progress.

Requirements

To complete this tutorial you must have the Umpr source checked out from here.

Additionally, this tutorial expects the user to use Eclipse--however the code could easily be completed via any text editor and the command-line. umpr.core is tested via TestNG and their Eclipse Plugin should be installed (if using Eclipse). TestNG is optional because Ant Tasks will automatically install TestNG for command-line testing.

For simplicity, this document assumes the Umpr source is in a workspace with the cruise.umple project available (thereby eliminating some compiler errors within Eclipse).

Creating a new Repository

In the context of Umpr, a "repository" is a collection of one or more files which UmpleImporter can handle and will be verified as working.

This tutorial will import only a single file, however this may be expanded to many files. This tutorial will download and import the ISO20022 ECore model, located here.

Within the Umpr repository, all repositories reside in the cruise.umple.umpr.core.repositories package and are to be "default" privacy to hide them outside the package's scope. All repositories must implement cruise.umple.umpr.core.Repository.

  1. Right click the cruise.umple.umpr.core.repositories package, select "New > Class"
  2. In the dialog, select the name: "ISO20022EcoreRepository"
  3. Select "package" private for the class
  4. Under Interfaces, select "Add..."
    • Find and select "cruise.umple.umpr.core.Repository"
  5. Check "Generate Comments" and "Inherited abstract methods"
  6. Click "Finish"

http://i.imgur.com/dNZ6oRS.png

Code

Implement the Repository

Now the eclipse has generated an implementation, we must complete the implementations.

In Repository.java, all definitions and requirements are laid out for each method.

Descriptive Methods

All of the "static" description methods are described below:

public String getName()
This method must return a non-null or empty unique identifier for the Repository
public String getDescription()
This method must return a non-null description of the Repository, this has no uniqueness requirement.
public DiagramType getDiagramType()
This method must return one of the static instances associated with DiagramType, e.g. CLASS, or STATE.

In our example, we will implement these methods by returning static values for simplicity.

  1. For getName(), return: "ISO20022".
  2. For getDescription() return: "ISO20022 ECore model from http://www.iso20022.org/e_dictionary.page, stored statically at: https://gist.github.com/Nava2/4ca3335224d51c185c0b"
  3. Because this is a class diagram, for getDiagramType(), DiagramType.CLASS is returned.

Code

Status Method

The method, public boolean isAccessible() can not be static. This method is used to verify that the repository is currently accessible. In this tutorial, if the Gist, here, is available, then the "repository" is available. To verify that the page is available, we will use a "ping" mechanism provided in Umpr's utility package.

  private final String URL = "https://gist.github.com/Nava2/4ca3335224d51c185c0b";

  @Override
  public boolean isAccessible() {
    return Networks.ping(URL, 200);
  }

Code

Import Method

All repositories must create a Stream of input data to parse.

Since only a single file is considered, the stream consists of a single fetch.

Umpr provides utilities for creating ImportEntitys from String instances and URLs. A URL entity will fetch the URL into a string and return the result. All ImportEntity instances rely on data not being fetched until required. This concept is done to decrease total runtime via parallelization.

In order to use the URLEntity, an instance of ImportEntityFactory is required.

Getting an instance of ImportEntityFactory

Umpr heavily uses a concept called Dependency Injection through Google Guice to manage class dependencies. This tutorial does not require in-depth knowledge of Guice, however it is an asset for complex repositories.

To get an instance of ImportEntityFactory, a field is created to hold the instance and a constructor to inject it.

  // Creates ImportEntity instances
  private final ImportEntityFactory factory;

  @Inject
  ISO20022EcoreRepository(ImportEntityFactory importEntityFactory) {
    this.factory = importEntityFactory;
  }

The import part of this definition is having the @Inject annotation on top of the constructor. It is enough to understand that the parameter will be automatically passed when the instance is created. For more information, you may see the Guice motivation page; however it is not required.

Code

Fetching the document

Using the ImportEntityFactory instance, an ImportEntity can be created that will fetch the document.

  1. Create a new URL instance: > > final URL url = new URL(GIST_URL);
    • However, this needs to be wrapped in a try-catch block, thus:
    try {
      final URL url = new URL(GIST_URL);

    } catch (MalformedURLException mue) {
      // Rethrow the exception as a RuntimeException
      throw Throwables.propagate(mue);
    }
  1. Create the ImportEntity,
final ImportEntity entity = factory.createUrlEntity(this, Paths.get(url.getPath()), 
          UmpleImportType.ECORE, url);
* `this` parameter is the current Repository
* `Paths.get(url.getPath())` creates a new instance of [Path](http://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html) which is just the file name and extension
* `UmpleImportType.ECORE` states that the file we are importing is an ECore file
* `url` is the location to download the resource from.
  1. Given that the output must be a [http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html Stream], the simplest solution is to create a List and return a Stream against it:
      // create a list
      final List<ImportEntity> out = new ArrayList<>();
      // add the import entity
      out.add(entity);
  1. Using the list, return the stream against it:
      // return a stream against the list
      return out.stream();

All code included together produces:

  @Override
  public Stream<ImportEntity> getImports() {
    try {
      final URL url = new URL(GIST_URL);

      final ImportEntity entity = factory.createUrlEntity(this, Paths.get(url.getPath()), 
          UmpleImportType.ECORE, url);

      // create a list
      final List<ImportEntity> out = new ArrayList<>();
      // add the import entity
      out.add(entity);

      // return a stream against the list
      return out.stream();
    } catch (MalformedURLException mue) {
      // rethrow as RuntimeException
      throw Throwables.propagate(mue);
    }
  }

Code

Installing the Repository for Use

All repositories must be installed into the Repository Module, cruise.umple.umpr.core.repositories.RepositoryModule. Open this file and append the following in the configure method:

mbinder.addBinding().to(ISO20022EcoreRepository.class);

This tells the entire Umpr system that the repository exists and to run it where required.

Code

Test the Repository

Each repository is tested via the cruise.umple.umpr.core.repositories.RepositoriesContractsTest unit test.

To run this class, right click on the file the Project Explorer, and select "Run As > TestNG Test".

http://i.imgur.com/o4dEGfJ.png

The test will run and will be slow. The following output should be expected in the console and TestNG tab:

http://i.imgur.com/CmFANBF.png

[TestNG] Running:
  /private/var/folders/tg/xbv4gqj101dgb0_2f1t7mflr0000gn/T/testng-eclipse--747092191/testng-customsuite.xml

Mar 31, 2015 3:54:44 PM cruise.umple.umpr.core.repositories.RepositoriesContractsTest checkURLs
INFO: Running Repository tests, these may take time depending on internet connection and repositories.
PASSED: checkDescriptions
PASSED: checkFileType
PASSED: checkNames
PASSED: checkURLs

===============================================
    Default test
    Tests run: 4, Failures: 0, Skips: 0
===============================================


===============================================
Default suite
Total tests run: 4, Failures: 0, Skips: 0
===============================================

[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@9e89d68: 7 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter2@299a06ac: 2 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@7c53a9eb: 16 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@71bc1ae4: 2 ms
[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@2e5c649: 1 ms