Skip to content

Create an Eclipse Lyo project

This document provides step-by-step instructions for creating a Java project with the necessary configurations to develop OSLC server/client applications using Lyo. The instructions assume Eclipse IDE is being used, but are equally valid for other development environments.

An alternative to the manual steps below

An alternative to the instructions on this page is to use Lyo Designer to quickly generate the project, including a very basic code skeleton. The generated project will also include the necessary setup for OpenApi/Swagger support, TRS, etc.

  1. Set up the environment for Lyo development as instructed on Eclipse Setup for Lyo-based Development.
  2. Install Lyo Designer.
  3. Follow the Create a Modelling Project instructions (Only this particular section) to create the Eclipse project.
  4. Follow the Adaptor Interface instructions (Only this particular section) to create a single Adaptor Interface in the model. Do not create additional elements, such as a Service Provider Catalog, Service Provider, etc. Set the generation settings as expected.
  5. Follow the Generate Lyo Java code instructions (Only this particular section) to generate the basic project setup.
  6. The process is complete! Lyo Designer can be used to model the complete OSLC Server/Client and generate additional project code.

Introduction

In the instructions below, the following parameters are assumed, which need to be adjusted for the particular project:

  • Eclipse Project Name: adaptor-sample-webapp
  • Base Package Name for Java Classes: com.sample.adaptor

These instructions create only the code skeleton. The Toolchain Modelling Workshop can then be used to generate the necessary code to become a fully functional server.

As a complement when following the instructions below, you can find sample projects under the Lyo Adaptor Sample Modelling git repository.

  • For Lyo 4.1.0, please refer to the main-4.x branch.
  • For Lyo 5.0.0-SNAPSHOT, please refer to the main-5.x branch.
  • For Lyo 2.4.0, please refer to the main-2.x branch.

Creating the project consists of these steps:

  1. Set up Eclipse
  2. Decide if you want to adopt JAX-RS 1.0 or 2.0?
  3. Create a Maven project
  4. Customise the project POM file
  5. Customise the web configuration
  6. (Optional) Provide OpenApi/Swagger Support
  7. (Optional) Provide TRS Support
  8. Run the server

Set up Eclipse

Set up the environment for Lyo development as instructed on Eclipse Setup for Lyo-based Development.

Create a Maven project

To create a Maven project from an archetype via Eclipse:

  1. Select File -> New -> Other.
  2. Then select Maven Project under Maven group.
  3. Leave the Create a simple project checkbox unchecked.
  4. Uncheck the Use default Workspace location option and point it to the project root.
  5. Press Next.

Next, select the maven-archetype-webapp archetype:

Next, fill in the Group Id, Artifact Id, and the Package Base.

  • The Package Base value (com.sample.adaptor on this page) will be used as a base package for the server code.

The project is now available in Eclipse with the following folder structure:

Customise the project POM file

Modify the project pom.xml file.

Set up general POM properties

Use properties to define a common version for Lyo packages:

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <maven.compiler.source>17</maven.compiler.source>
  <maven.compiler.target>17</maven.compiler.target>
  <version.lyo>6.0.0.Final</version.lyo>
</properties>

(Optional) Add Lyo repositories

Lyo release artefacts are on Maven central since 4.0.0 - no action needed.

If using the latest development snapshots is required, the following entry is needed:

<repositories>
    <repository>
        <name>Central Portal Snapshots</name>
        <id>central-portal-snapshots</id>
        <url>https://central.sonatype.com/repository/maven-snapshots/</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

SLF4J package dependencies

Lyo uses SLF4J for logging, leaving the choice of the actual logging library to use. The simplest option:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.7.36</version>
  <scope>runtime</scope>
</dependency>

Servlet dependencies

Java EE 6 or higher and JSTL are required:

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

JAX-RS implementation dependencies

Lyo depends on JAX-RS APIs and your application needs to add implementations of those APIs.

For Lyo 5.x

For Lyo release 5.0.0 and above, choose a JAX-RS 2.0 implementation. If using Jersey, use version 2.35.

Note

Starting with Jersey 2.26, HK2 is not bundled with the core artefacts (see the Jersey migration guide).

<dependency>
  <groupId>org.glassfish.jersey.core</groupId>
  <artifactId>jersey-server</artifactId>
  <version>2.35</version>
</dependency>
<dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-servlet</artifactId>
  <version>2.35</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>2.35</version>
</dependency>

Lyo dependencies

The minimal Lyo dependencies are:

<dependency>
  <groupId>org.eclipse.lyo.oslc4j.core</groupId>
  <artifactId>oslc4j-core</artifactId>
  <version>${version.lyo}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.lyo.oslc4j.core</groupId>
  <artifactId>oslc4j-jena-provider</artifactId>
  <version>${version.lyo}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.lyo.oslc4j.core</groupId>
  <artifactId>oslc4j-json4j-provider</artifactId>
  <version>${version.lyo}</version>
</dependency>

OSLC OAuth support

If your server needs to support OAuth, include the following:

<dependency>
  <groupId>org.eclipse.lyo.server</groupId>
  <artifactId>oauth-core</artifactId>
  <version>${version.lyo}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.lyo.server</groupId>
  <artifactId>oauth-consumer-store</artifactId>
  <version>${version.lyo}</version>
</dependency>
<dependency>
  <groupId>org.eclipse.lyo.server</groupId>
  <artifactId>oauth-webapp</artifactId>
  <version>${version.lyo}</version>
  <type>war</type>
</dependency>

To support OAuth, add the following JAX-RS Providers to the Application (the javax.ws.rs.core.Application subclass):

RESOURCE_CLASSES.add(Class.forName("org.eclipse.lyo.server.oauth.webapp.services.ConsumersService"));
RESOURCE_CLASSES.add(Class.forName("org.eclipse.lyo.server.oauth.webapp.services.OAuthService"));

OSLC Client support

If your OSLC server also needs to consume resources from another server, a dependency to the OSLC client package is needed:

For Lyo 4.0+

<dependency>
  <groupId>org.eclipse.lyo.clients</groupId>
  <artifactId>oslc-client</artifactId>
  <version>${version.lyo}</version>
</dependency>

Configure the Embedded Jetty server for quick debugging

Finally, use an embedded servlet container during the debugging to simplify the development process.

Replace the existing <build> entry with the Jetty configuration below, using the following customisations:

  • adaptor-sample is the context path that can be the same as the eclipse project name (or something more appropriate)
  • 8080 is the port number to run the services on.

This will make the server available under the path http://localhost:8080/adaptor-sample.

<build>
  <plugins>
    <plugin>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-maven-plugin</artifactId>
      <version>9.4.46.v20220331</version>
      <configuration>
        <webAppConfig>
          <contextPath>/adaptor-sample</contextPath>
        </webAppConfig>
        <reload>automatic</reload>
        <scanIntervalSeconds>5</scanIntervalSeconds>
        <systemProperties>
          <systemProperty>
            <name>jetty.port</name>
            <value>8080</value>
          </systemProperty>
        </systemProperties>
        <stopKey />
        <stopPort />
      </configuration>
    </plugin>
  </plugins>
</build>

Customise the web configuration

Modify the parameters in /src/main/webapp/WEB-INF/web.xml according to the template below.

  • Adaptor Sample could be the same as the eclipse project name (or something more appropriate).
  • com.sample.adaptor should be the same as the base package name for the project.
  • 8080 should match the port number specified in the POM file for Jetty configuration.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  id="WebApp_ID" version="3.0">
  <display-name>Adaptor Sample</display-name>
  <context-param>
    <description>Base URI for the adaptor.</description>
    <param-name>com.sample.adaptor.servlet.baseurl</param-name>
    <param-value>http://localhost:8080</param-value>
  </context-param>
  <listener>
    <description>Listener for ServletContext lifecycle changes</description>
    <listener-class>com.sample.adaptor.servlet.ServletListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>javax.ws.rs.Application</param-name>
      <param-value>com.sample.adaptor.servlet.Application</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
</web-app>

(Optional) Provide OpenApi/Swagger Support

With OSLC being based on REST, an OSLC Server can relatively easily be documented using OpenApi/Swagger.

The instructions below are based on Swagger Core JAX RS Project Setup 1.5.X, compiled for a typical Lyo project. The instructions are also partially based on Co-hosting Swagger UI with your Jersey REST API using Maven dependencies. The instructions provide the minimal settings necessary for a Lyo project.

Add OpenApi/Swagger Maven dependencies

Add the following Swagger dependency to the maven pom.xml file.

For Lyo 5.0.0

Assuming the Jersey implementation is adopted with the version specified above.

<dependency>
  <groupId>io.swagger.core.v3</groupId>
  <artifactId>swagger-jaxrs2</artifactId>
  <version>2.1.4</version>
  <exclusions>
    <exclusion>
      <!--should be <provided>-->
      <groupId>jakarta.activation</groupId>
      <artifactId>jakarta.activation-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>io.swagger.core.v3</groupId>
  <artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
  <version>2.1.4</version>
</dependency>

Co-host Swagger UI with the server

The following steps provide the end-user with an interactive console to the OSLC services, by integrating Swagger UI with the OSLC server.

Add the following plugins to the existing <plugins> entry of the pom.xml file. These plugins download and extract the necessary Swagger UI files from Swagger UI GitHub project onto the project:

<build>
  <plugins>
    <plugin>
    ...
    </plugin>
    <plugin>
      <!-- Download Swagger UI webjar. -->
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <version>3.1.2</version>
      <executions>
          <execution>
              <phase>prepare-package</phase>
              <goals>
                  <goal>unpack</goal>
              </goals>
              <configuration>
                  <artifactItems>
                      <artifactItem>
                          <groupId>org.webjars</groupId>
                          <artifactId>swagger-ui</artifactId>
                          <version>3.25.0</version>
                      </artifactItem>
                  </artifactItems>
                  <outputDirectory>${project.build.directory}/swagger-ui</outputDirectory>
              </configuration>
          </execution>
      </executions>
    </plugin>
    <plugin>
      <!-- Add Swagger UI resources to the war file. -->
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <version>3.2.3</version>
      <configuration>
          <webResources combine.children="append">
              <resource>
                  <directory>${project.build.directory}/swagger-ui/META-INF/resources/webjars/swagger-ui/3.25.0</directory>
                  <includes>
                      <include>**/*.*</include>
                  </includes>
                  <targetPath>/swagger-ui/dist</targetPath>
              </resource>
          </webResources>
      </configuration>
    </plugin>
  </plugins>
</build>

Add Swagger-Core's JAX-RS Providers to your Application

Add swagger-core's JAX-RS Providers to the Application class that extends javax.ws.rs.core.Application:

public class Application extends javax.ws.rs.core.Application {
  private static final Set<Class<?>> RESOURCE_CLASSES = new HashSet<Class<?>>();
    static
    {
      ...
      RESOURCE_CLASSES.add(io.swagger.jaxrs.listing.ApiListingResource.class);
      RESOURCE_CLASSES.add(io.swagger.jaxrs.listing.SwaggerSerializers.class);
      ...
    }
    ...

Configure Swagger's Servlet in the web.xml

Add the following to the web.xml:

  • swagger.api.basepath depends on the particular settings, as instructed above.
  <servlet>
    <servlet-name>DefaultJaxrsConfig</servlet-name>
    <servlet-class>io.swagger.jaxrs.config.DefaultJaxrsConfig</servlet-class>
    <init-param>
      <param-name>api.version</param-name>
      <param-value>1.0.0</param-value>
    </init-param>
    <init-param>
      <param-name>swagger.api.basepath</param-name>
      <param-value>http://localhost:8080/adaptor-sample/services/</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
  </servlet>

Add OpenApi Annotations (Almost Optional)

The OpenApi documentation can be achieved with as little as adding @Api to each REST/OSLC service in your project. This is detailed in the first step below. While the remaining instructions are optional, they are highly recommended to provide a documentation that can best reflect the OSLC services.

@Api

  1. For each REST service (i.e. OSLC Service), simply add the @Api annotation.
  2. (OPTIONAL) add the value and description details. The value is used to group the REST methods into common categories, helping in the structuring of the methods in the documentation. You can give it the same value as that of the @Path annotation, collecting all REST methods for the same service together.
@Api(value = "requirements", description = "OSLC service for resources of type" + "Requirement")
@OslcService(Oslc_rmDomainConstants.REQUIREMENTS_MANAGEMENT_DOMAIN)
@Path("requirements")

@ApiOperation (Optional)

For each REST method, add the @ApiOperation Swagger annotation.

OpenApi Operation Uniqueness

In OpenApi, an operation is considered unique based on the combination of its path and HTTP method. This means you cannot define multiple C.R.U.D. methods for the same path and method—even if they differ by parameters such as Accept or Content-Type.

Example

If your OSLC Service defines separate Java methods to handle HTML and RDF/XML content types for the same path and HTTP method, OpenApi will only recognise one of these methods and ignore the other.

Workaround: Annotate ALL methods that are identified as unique with the complete list of media types in the produces property of the @ApiOperation annotation. This way, the generated documentation correctly indicates the existence of all methods.

    @GET
    @ApiOperation(value = "GET on Requirement resources",
    produces = OslcMediaType.APPLICATION_RDF_XML + ", " + MediaType.TEXT_HTML)
    @Path("{requirementId}")
    @Produces(OslcMediaType.APPLICATION_RDF_XML)
    public Requirement getRequirement(

@ApiModel (Optional)

For each Java class that models an OSLC-resource (@OslcName annotation), add an @ApiModel annotation that refers to the Shape of the resource, since a Shape is a more accurate description of the object, than the one automatically generated by Swagger.

@ApiModel(description = "The model below is only an object structure as derived by swagger. For a more accurate RDF Description, refer to the Requirement Resource Shape.")
@OslcNamespace(Oslc_rmDomainConstants.REQUIREMENT_NAMESPACE)
@OslcName(Oslc_rmDomainConstants.REQUIREMENT_LOCALNAME)
@OslcResourceShape(title = "Requirement Resource Shape", describes = Oslc_rmDomainConstants.REQUIREMENT_TYPE)
public class Requirement
...

Access the Swagger UI interactive console

Before accessing the Swagger UI interactive console for the first time, edit the swagger-ui/index.html file, replacing the url http://petstore.swagger.io/v2/swagger.json with the URL of the YAML file http://localhost:8080/adaptor-sample/services/swagger.yaml.

The generated interactive API console can be accessed via:

http://localhost:8080/adaptor-sample/swagger-ui/

Access OpenAPI specification document (yaml file)

You can also access the OpenAPI specification document (yaml file) at:

http://localhost:8080/adaptor-sample/services/swagger.yaml

You can copy the yaml file to a Swagger Editor, to view the API documentation, as well as generate client/Server SDK code for a number of languages and platforms.

(Optional) Provide TRS Support

The TRS Server library is a set of ready-to-use classes that provide the required REST services for TRS, with minimal effort. The current implementation supports an In-memory TRS Server that does not persist its TRS resources. These classes are however designed to be extended for a persistent solution. For a thorough walkthrough of TRS solutions, which among other things ensures persisting the TRS Logs, visit the additional information on TRS.

Add Maven dependencies

Add a dependency for the TRS Server library:

<dependency>
  <groupId>org.eclipse.lyo.trs</groupId>
  <artifactId>trs-server</artifactId>
    <version>${version.lyo}</version>
</dependency>

Set up the TRS JAX-RS Provider to your Application

The TRS Server library already contains a TrackedResourceSetService class that can handle the REST calls for TRS Base and ChangeLog. For this service to work, you will only need to provide a binding to a singleton of a class that implements the PagedTrs class.

Register the TRS JAX-RS Provider TrackedResourceSetService in your Application (the javax.ws.rs.core.Application subclass):

import org.eclipse.lyo.oslc4j.trs.server.service.TrackedResourceSetService;
...
public class Application extends javax.ws.rs.core.Application {
    private static final Set<Class<?>>         RESOURCE_CLASSES                          = new HashSet<Class<?>>();
    static
    {
      ...
      RESOURCE_CLASSES.add(TrackedResourceSetService.class);
      ...
    }
    ...

Provide the necessary binding definition for the PagedTrs class:

import java.util.Collections;
import org.eclipse.lyo.oslc4j.trs.server.PagedTrs;
import com.sample.adaptor.InmemPagedTrsSingleton;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
...
public class Application extends javax.ws.rs.core.Application {
    ...
    @Override
    public Set<Object> getSingletons() {
        return Collections.singleton(new AbstractBinder() {
            @Override
            protected void configure() {
                bindFactory(new InmemPagedTrsSingleton()).to(PagedTrs.class);
            }
        });
    }

Define the InmemPagedTrsSingleton singleton class. Complete the code example below, with: * the code that populates uris with the initial set of resources to be managed by InmemPagedTrs; * the desired basePageLimit and changelogPageLimit parameters.

package com.sample.adaptor;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;

import javax.ws.rs.core.UriBuilder;
import org.eclipse.lyo.oslc4j.core.OSLC4JUtils;
import org.eclipse.lyo.oslc4j.trs.server.InmemPagedTrs;
import org.eclipse.lyo.oslc4j.trs.server.PagedTrs;
import org.eclipse.lyo.oslc4j.trs.server.service.TrackedResourceSetService;
import org.glassfish.hk2.api.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class InmemPagedTrsSingleton implements Factory<PagedTrs> {
    private final static Logger log = LoggerFactory.getLogger(InmemPagedTrsSingleton.class);
    private static InmemPagedTrs inmemPagedTrs;

    @Override
    public InmemPagedTrs provide() {
        return getInmemPagedTrs();
    }

    @Override
    public void dispose(final PagedTrs instance) {
        log.debug("{} is getting disposed", instance);
    }

    public static InmemPagedTrs getInmemPagedTrs() {
        if(inmemPagedTrs == null) {
            log.debug("Initialising 'InmemPagedTrs' instance");

            ArrayList<URI> uris = new ArrayList<URI>();

            //TODO: populate uris with the initial set of resources to be managed by the InmemPagedTrs instance
            ....
            // not thread-safe
            inmemPagedTrs = new InmemPagedTrs(<basePageLimit>, <changelogPageLimit>,
                UriBuilder.fromUri(OSLC4JUtils.getServletURI()).path(TrackedResourceSetService.RESOURCE_PATH).build(), 
                TrackedResourceSetService.BASE_PATH, TrackedResourceSetService.CHANGELOG_PATH, uris);
        }
        return inmemPagedTrs;
    }
}

The application is now ready to respond to REST requests from a TRS Client. Once running, the server will respond to requests on the relative path /trs.

Update the TRS data set

To update the set of OSLC resources that form the TRS Base and ChangeLog, call the following methods in the code:

  • InmemPagedTrsSingleton.getInmemPagedTrs().onCreated(aResource);
  • InmemPagedTrsSingleton.getInmemPagedTrs().onModified(aResource);
  • InmemPagedTrsSingleton.getInmemPagedTrs().onDeleted(aResource.getAbout());

Run the server

Once the server is developed, run it by selecting Run As ➞ Maven build ... from the project's context menu, and setting the goal to clean jetty:run-war.

Access the server from http://localhost:8080/adaptor-sample (adaptor-sample and 8080 will depend on the particular settings, as instructed above).

Pro Tip: If the error Project configuration is not up-to-date with pom.xml occurs, right click on the eclipse project and select Maven ➞ Update Project ...