How to Setup Maven 3.5 on macOS 10 and Create a Java Project from Archetype

  • This post shows how to setup Maven and how to create, build and run a new Maven Java project on macOS 10.
  • Before continuing, make sure that a Java SDK 1.7 or greater is installed and that the commands are available in your PATH environment variable. In a terminal window, run the following command to confirm this:
java -version

MacBookPro:opt admin$ java -version
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
MacBookPro:opt admin$
 
  • For a related post on installing a Java SDK and seting up a Java EE development environment refer to the below post on this site:

Summary

  1. Installing and Configuring Maven 3.5 on macOS 10
  2. Creating a Maven Java Project from an Archetype
  3. Adding Project Dependencies in the POM File
  4. Execute the Java Application with the Maven exec Plugin

  • In this example, Maven 3.5 is used. It can be downloaded as a binary distribution from the Apache Maven Website.

Download Maven Binary Distribution from Apache Maven Website

  • Unzip the Maven 3.5 files into some folder on the local disk. In this example, the Maven files are unzipped into the ${maven.home} folder at:
/opt/apache-maven-3.5.0

Maven Home Folder Contents

  • For instructions on how to add the Maven commands from the ${maven.home}\bin folder to the PATH environment variable on macOS see:
  • Open a terminal window and verify that maven is installed properly by executing the below command to view the Maven version:
mvn -version
  • The output should look like the example below, showing the Java version and Java home folder:

Last login: Wed Oct 11 01:07:07 on ttys000
MacBookPro:~ admin$ /opt/apache-maven-3.5.0/bin/mvn -version
Apache Maven 3.5.0 (ff8f5e7444045639af65f6095c62210b5713f426; 2017-04-03T15:39:06-04:00)
Maven home: /opt/apache-maven-3.5.0
Java version: 1.8.0_77, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.12.5", arch: "x86_64", family: "mac"
MacBookPro:~ admin$

  • If a proxy is needed to connect to the Internet, edit ${maven.home}/.m2/conf/settings.xml:
  <!-- proxies
   | This is a list of proxies which can be used on this machine to connect to the network.
   | Unless otherwise specified (by system property or command-line switch), the first proxy
   | specification in this list marked as active will be used.
   |-->
  <proxies>
    <!-- proxy
     | Specification for one proxy, to be used in connecting to the network.
     |-->
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>domain\username</username>
      <password>password</password>
      <host>proxy.host.com</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
  </proxies>
  • When a Maven project is built, Maven will download all dependent artifacts (JAR files) from a remote repository to a local repository. By default, Maven will create the local repository in:
${user.home}/.m2/repository
  • The Maven local repository contains all downloaded artifacts and looks like the example below:

Default Maven Local Repository Location on macOS

  • To change the location of the local repository, edit ${maven.home}/.m2/conf/settings.xml:
  <!-- localRepository
   | The path to the local repository maven will use to store artifacts.
   | Default: ${user.home}/.m2/repository
   |-->
  <localRepository>/my/local/repository</localRepository>

  • To create a Maven Java project with JUnit support, using the archetype maven-archetype-quickstart, execute the command:
mvn archetype:generate -DgroupId=com.company.app -DartifactId=my-app 
    -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
  • When Maven first downloads required dependencies to the local repository, the build may take a while.
  • The output should look like below and result in a BUILD SUCCESS message.
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/archetype/maven-archetype-parent/1/maven-archetype-parent-1.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/archetype/maven-archetype-parent/1/maven-archetype-parent-1.pom (1.3 kB at 8.7 kB/s)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/4/maven-parent-4.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/4/maven-parent-4.pom (10.0 kB at 54 kB/s)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/archetypes/maven-archetype-quickstart/1.0/maven-archetype-quickstart-1.0.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/archetypes/maven-archetype-quickstart/1.0/maven-archetype-quickstart-1.0.jar (4.3 kB at 28 kB/s)
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: /Users/admin/Desktop/MyProjects/pegaxchange.com/posts/3506
[INFO] Parameter: package, Value: com.company.app
[INFO] Parameter: groupId, Value: com.company.app
[INFO] Parameter: artifactId, Value: my-app
[INFO] Parameter: packageName, Value: com.company.app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Users/admin/Desktop/MyProjects/pegaxchange.com/posts/3506/my-app
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.639 s
[INFO] Finished at: 2017-10-18T18:07:10-04:00
[INFO] Final Memory: 19M/308M
[INFO] ------------------------------------------------------------------------
MacBookPro:3506 admin$ 
  • Maven will create a folder using the artifactId and create the standard project structure based on the groupId:
my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- company
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- company
                    `-- app
                        `-- AppTest.java
  • The root folder of the Maven project contains a POM file (Project Object Model). Here, the file contains:
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.company.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>my-app</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
  • To compile and package the Java project, execute in the project root folder (containing the pom.xml file):
mvn clean compile package
[INFO] Compiling 1 source file to /Users/admin/my-app/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ my-app ---
[INFO] Surefire report directory: /Users/admin/my-app/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.company.app.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ my-app ---
[INFO] Building jar: /Users/admin/my-app/target/my-app-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.568 s
[INFO] Finished at: 2017-10-18T19:12:04-04:00
[INFO] Final Memory: 16M/186M
[INFO] ------------------------------------------------------------------------
MacBookPro:my-app admin$
  • The resulting JAR file is located in the target folder of the project:

Maven Java Standard Project Structure

  • It can be executed from the project folder with the java command:
java -cp target/my-app-1.0-SNAPSHOT.jar com.company.app.App
  • Which will produce the below output:
MacBookPro:my-app admin$ java -cp target/my-app-1.0-SNAPSHOT.jar com.company.app.App
Hello World!
MacBookPro:my-app admin$ 
  • As per the App.java source file:
package com.company.app;

public class App {

    public static void main( String[] args ) {
        System.out.println( "Hello World!" );
    }
}

  • The Maven Central Repository is used to find and add dependencies to a project’s POM file.
  • For example, to add support for JSON processing to the project, Google’s GSON API can be used.
  • Search for "GSON" in the Maven Central Repository to find the Maven dependency information.

Maven Central Repository - Search for Artifact

  • Click on the version link, here 2.8.2, to view the dependency information:

Maven Central Repository - GSON 2.8.2 Artifact Details

  • Copy and paste the dependency information from the Apache Maven section into the project’s POM file:
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.company.app</groupId>
    <artifactId>my-app</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>my-app</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <!-- Support for JSON Processing -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.2</version>
        </dependency>
    </dependencies>
</project>
  • The scope of the new dependency is not specified. It is compile by default. See Dependency Scope for more information.
  • The GSON API can now be used in the App.java source file to serialize Java objects:
package com.company.app;

import com.google.gson.Gson;

public class App {

    public static void main( String[] args ) {
        Car car = new App().new Car();
        car.setMake("BMW");
        car.setModel("335i");

        System.out.println(new Gson().toJson(car));
    }

    class Car {

        private String make;
        private String model;

        public String getMake() {
            return make;
        }

        public void setMake(String make) {
            this.make = make;
        }

        public void setModel(String model) {
            this.model = model;
        }

        public String getModel() {
            return model;
        }
    }
}

  • Maven can be used to compile and then execute the App class using the exec plugin:
mvn compile exec:java -Dexec.mainClass="com.company.app.App"
  • The output will be a JSON representation of the Car object:
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ my-app ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/admin/my-app/target/classes
[INFO] 
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ my-app ---
{"make":"BMW","model":"335i"}
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.421 s
[INFO] Finished at: 2017-10-19T12:52:29-04:00
[INFO] Final Memory: 18M/301M
[INFO] ------------------------------------------------------------------------
{"make":"BMW","model":"335i"}

Create a REST Service in Pega 7.1.9 with Service REST Rule

This post shows how to create a REST web service in Pega 7.1.9 for consumption by external applications. In essence:

  • A Pega 7.1.9 application is the REST service provider.
  • External applications are the REST service consumers (or clients).

For examples on how to consume REST and SOAP web services from a Pega 7 application (i.e. Pega is the client), see the related posts section. For this post, the Pega 7.1.9 exercise system was used as described in: Running Pega 7 Exercise System on Tomcat 9 and PostgreSQL – without VMWare or VirtualBox.

Summary

  1. Quick Description of Sample Application
  2. Create New Access Group and Access Role Rules
  3. Create Data Model for REST Request and Response Mappings
  4. Create New Service Package Rule
  5. Create New Service REST Rule
  6. Create New Service Activity Rule
  7. Test the REST Service

Related Posts

  • In this example, an application called MyStore contains a Data Type named Phone.
  • 13 records have been created in the local data storage. The records are shown below.

Data Type - PGX-MyStore-Data-Phone

  • This post shows how a A REST service is built to query Phone records by name as shown below:

Postman - Call REST Phone Service

  • A access group and a access role rule need to be created.
  • The access group will be assigned to the Service REST rule and used for handling client requests.
  • In the Designer Studio, click on the plus icon and select Security > Access Group.

Pega 7 Designer Studio Menu - Access Group

  • Here, the access group is named MyStore:Services. Click on Create and open to continue.

Pega 7 - Create Access Group Rule

  • On the Definition tab, enter the application name and version. Here it is MyStore and 01.01.01.
  • Enter a new role name under Available roles and click on the plus icon next to it to create the role.
  • Here the role is named MyStore:ServiceClient.

Pega 7 - Edit Access Group Definition

  • When creating the Access Role, select the context and the ruleset and click on Create and open.

Pega 7 - Create Access Role

  • Add a role to provide access to the PGX-MyStore-Data-Phone data type class.
  • Here, the REST service needs to be able to read instances of that class.

Pega 7 - Edit Access Role - Set Class Privileges

  • Similarly, add access to Rule-Obj-Activity and PGX-MyStore-Int for executing activities.

Pega 7 - Access Role - View all roles

  • The service activity that will be created later, will have an applies-to class that is a subclass of PGX-MyStore-Int.

  • In order to map the incoming request data and the outgoing response data, 2 page-type properties were created in PGX-MyStore-Int-REST-Phone.
  • A single page property with a definition of PGX-MyStore-Int-REST-Phone-Request is used to map the request parameters such as ID and Name.

REST Service Request data model

  • The page list property PGX-MyStore-Int-REST-Phone-Response-Phones is used to hold the matching phone records and will be converted into the REST service response data (JSON format).

REST Service Response data model

  • The conversion from incoming JSON to the request page property and from the Pega Response.Phones page list rule to a JSON string is done automatically by the Service REST rule.

  • In the Pega 7 Designer Studio, click on the plus icon in the main header menu and select Integration-Resources > Service Package to create a new Service Package rule.

Pega 7 Designer Studio Menu - Service Package

  • Enter a description and a name for the new service package and click on Create and open.
  • Here, the Service Package Name is MyStoreRESTServices.

Pega 7 - Create Service Package

  • On the Context tab, set the processing mode to Stateless and enter the access group, MyStore:Services, that was created earlier.
  • In this example, Requires authentication is not checked, so that any unauthenticated client can call the service.

Edit Service Package - Context Form

  • Click on Save to complete the Service Package setup.

  • In the Pega 7 Designer Studio, click on the plus icon in the main header menu and select Integration-Services > Service REST to create a new Service REST rule.

Pega 7 Designer Studio Menu - Service REST

  • Enter a service name in the label field, here it is PhoneRESTService.
  • Select the service package MyStoreRESTServices in the Customer Package Name field.
  • The Customer Class Name has to be a valid Java identifier and is used to group related service methods. This name is unrelated to Rule-Obj-Class instances.
  • Click on Create and open to continue.

Pega 7 - Create New Service REST Rule

  • On the Service tab, enter the Primary page class. Here it is PGX-MyStore-Int-REST-Phone.
  • The Page name specifies the name of the service page that will be passed to service activities so they can access the -Request and -Response properties. Here, it is MyServicePage.
  • Here, the service accepts one input property that is passed as part of the URL in the Resource Path.
  • The {name} resource property is mapped to the .Request.Name property of the service page.

Edit Service REST Rule - Service Tab

  • The Execution Mode is set to Execute synchronously so that the request is handled immediately instead of being queued for later processing.
  • Switch to the Methods tab to configure the HTTP GET method as shown below.

Edit Service REST Rule - Methods Tab

  • Enter the Service Activity. Here it is GetPhones and its implementation is shown in section 6 below.
  • Leave Default for the Condition and enter application/json for the content type.
  • Under Message data, select to map from JSON and enter the page list property MyServicePage.Response.Phones, which will hold the result records.
  • The service rule will convert the page list property to a JSON array.
  • Save the Service REST rule. The method should now show up in the Service Package rule.

Service Package - Context Tab - View all Methods

  • Clicking on the endpoint URL will result in an empty JSON object at this point, since the service activity has not yet been implemented.

  • The GetPhones service activity needs to be created to query the phone records and generate the response page list.
  • The Apply to class is the same as the class of the primary page of the Service REST rule.

Pega 7 - Create New Service Activity GetPhones

  • Click on Create and open to edit the activity steps.
  • The Service Activity uses the Obj-Browse method as shown below to query phone records by name.
  • The service page MyServicePage is passed to the activity and the Request.Name property contains the {name} parameter passed in the request URL. The results are sorted in ascending order by price.

Pega 7 - Acticity Steps Tab - Obj-Browse

  • The second step uses the Property-Set method to set the Response.Phones page list of the service page using the Phones.pxResults (Code-Pega-List) populated by the Obj-Browse method.

Pega 7 - Acticity Steps Tab - Property-Set

  • The Phones and MyServicePage need to be listed on Pages and Classes as shown below.

Pega 7 - Activity Pages and Classes Tab

  • The Show-Page method can be used to test the service activity. Click on Actions > Run to execute the activity and view the PGX-MyStore-Int-REST-Phone-Response page.

Pega 7 - Run GetPhones Activity

  • The default settings on the Security tab of the service activity can be kept.

Pega 7 - GetPhones Activity Security Tab

  • Save the service activity.

  • The URL for accessing the REST service is a combination of the following elements:
http://<hostname>:<port>/prweb/PRRestService/<packageName>/<className>/<methodName>/<resourcePath>
  • The endpoint URL is also shown on the Service Package rule.

Service Package - View REST Service Endpoint URL

  • Here, the URL is:
localhost:8080/prweb/PRRestService/MyStoreRESTServices/PGX-MyStore-Phone-REST/PhoneRESTService/{name}
  • A REST service client such as Postman or a browser can be used to call the service. In the below example, the service returns all phones where the name contains Apple.

Postman - Call Pega 7 REST Service to get Apple Phones

  • Clicking on the endpoint URL on the Service Package rule form will make a call with no parameters and show all records as a JSON array in a new browser window.

Call Pega 7 REST Service from Browser

  • Use the Pega logs to debug service problems. If the service fails to return any data, make sure the Access Role is configured properly as shown in section 2.

Pega 7 Logs - Access to REST Service Activity Denied