Friday, August 5, 2022

Quiz yourself: Sealed class true-or-false questions

Core Java, Oracle Java Tutorial and Material, Oracle Java Preparation, Oracle Java Certification, Oracle Java Skills, Java Jobs

Five statements about sealed classes, but not all of them are true


Which statement is true about a sealed class? Choose one.

A. All its subtypes must be in the same package.
B. Under some conditions, it can have direct subclasses that are not listed in a permits clause.
C. The sealed class is implicitly final.
D. The sealed class is implicitly immutable.
E. The sealed class may not be instantiated directly.

Answer. Option A is incorrect because a sealed class can be extended by a class in a different package. However, there are two limitations.

◉ The subclass must be listed in the permits section of the sealed class.
◉ The subclass must be in the same named module as the sealed class.

Option B is correct. If the entirety of a sealed-type hierarchy is coded in a single compilation unit (source file) and the base sealed type does not have a permits clause, some of the types in the source file can declare that they are subtypes of the base sealed type. Such types must conform to the other rules for members of a sealed-type hierarchy, notably that they must themselves be sealed, non-sealed, or final.

Two points are worth making here.

First, if a permits clause exists on a sealed type, the only permitted direct subtypes will be those listed in that clause. The ability to have direct subtypes that are not listed in a permits clause is specifically allowed when no permits clause exists and all children are in the same source file as the parent.

Second, if a sealed type has a direct subtype that is declared sealed, the children of that subtype are not listed in the parent sealed type’s permits clause; instead they’re listed in any such clause on the subtype. Similarly, if the child type is non-sealed, it can have any number of children not listed in any permits clause.

Option C is incorrect because a sealed class can be extended, as mentioned above.

Option D is also incorrect because the “sealedness” of a class does not impact its immutability. Immutability or lack of immutability is a consequence of the logic defined in the implementation.

In addition, option E is incorrect. A sealed class can be directly instantiated (unless some other feature prevents this, for example, if the class is also abstract).

Conclusion. The correct answer is option B.

Source: oracle.com

Wednesday, August 3, 2022

Quiz yourself: The allowable subtypes in sealed classes

Core Java, Oracle Java Certification, Oracle Java Exam, Oracle Java Preparation, Oracle Java Career, Java Skills, Java Jobs

You should know what the rules say about subclasses being public, protected, and final.

Given the sealed Bird class

public sealed class Bird permits Sparrow {}

Which Sparrow class definitions, when used independently, are valid? Choose two.

A. non-sealed class Sparrow extends Bird { }

B. public class Sparrow extends Bird { }

C. protected class Sparrow extends Bird { }

D. final class Sparrow extends Bird { }

Answer. The normal syntax for a sealed type requires that the type define in the permits section the list of allowed direct subtypes. In this question, the Bird class enumerates only one allowed direct subclass, which is Sparrow.

The direct subtypes of a sealed type are subject to some constraints; they must carry one of the following three listed modifiers, which cause the effects noted:

◉ non-sealed, in which case the non-sealed type can itself have arbitrary subtypes

◉ sealed, in which case this subtype must also declare a nonempty permits clause enumerating at least one existent subtype

◉ final, in which case the type must be a concrete class and no further subclasses are allowed

In the code of the question, only options A and D fulfill these requirements; thus, those options are correct.

Option B would be valid as a regular subclass of a Bird if the Bird class were not sealed. Since Bird is sealed, however, Sparrow is unacceptable because it fails to satisfy the constraints listed above. From this, you know that option B is incorrect.

Option C is also incorrect because the constraints listed are not met: The protected modifier does not satisfy the constraints. In addition, in the question it appears that the classes listed are all top-level classes, and the protected modifier may be applied only to fields, methods, constructors, or nested types, not to top-level types.

Conclusion. The correct answers are options A and D.

Source: oracle.com

Monday, August 1, 2022

JVM

Design and document for inheritance—or else prohibit it. Here’s how.

It is dangerous to subclass a “foreign” class that was not designed and documented for inheritance.

Oracle Java, Java Exam Prep, Oracle Java Career, Java Skills, Java Jobs, Java Tutorial and Materials

In other words, a subclass depends on the implementation details of its superclass for its proper function. The superclass’s implementation may change from release to release, and if it does, the subclass may break, even though its code has not been touched.

That begs the question: What does it mean for a class to be designed and documented for inheritance?

First, document

A class designed and documented for inheritance must precisely document the effects of overriding any method. In other words, the class must document its self-use of overridable methods.

For each public or protected method, the documentation must indicate which overridable methods the method invokes, in what sequence, and how the results of each invocation affect subsequent processing. (The term overridable means a method is nonfinal and either public or protected.)

More generally, a class must document any circumstances under which it might invoke an overridable method. For example, invocations might come from background threads or static initializers.

A method that invokes overridable methods contains a description of these invocations at the end of its documentation comment. The description is in a special section of the specification, labeled “Implementation Requirements,” which is generated by the @implSpec Javadoc tag. This section describes the inner workings of the method. The following is an example copied from the java.util.AbstractCollection specification:

public boolean remove(Object o)

Removes a single instance of the specified element from this collection, if it is present (optional operation). More formally, removes an element e such that Objects.equals(o, e), if this collection contains one or more such elements. Returns true if this collection contained the specified element (or equivalently, if this collection changed as a result of the call)…

Implementation Requirements: This implementation iterates over the collection looking for the specified element. If it finds the element, it removes the element from the collection using the iterator’s remove method. Note that this implementation throws an UnsupportedOperationException if the iterator returned by this collection’s iterator method does not implement the remove method and this collection contains the specified object.

The specification documentation leaves no doubt that overriding the iterator method will affect the behavior of the remove method. The documentation also describes exactly how the behavior of the Iterator returned by the iterator method will affect the behavior of the remove method. Contrast this to the situation described in the article “You should favor composition over inheritance in Java. Here’s why.” In that article, the programmer subclassing HashSet simply could not say whether overriding the add method would affect the behavior of the addAll method.

Wait: Doesn’t this violate the dictum that good API documentation should describe what a given method does and not how it does it? Yes; it does! This is an unfortunate consequence of the fact that inheritance violates encapsulation. To document a class so that it can be safely subclassed, you must describe implementation details that should otherwise be left unspecified.

By the way, the @implSpec tag was added in Java 8 and is used heavily in Java 9. This tag should be enabled by default, but as of Java 9, Javadoc ignores the tag unless you pass the command line switch -tag "implSpec:a:Implementation Requirements:".

Second, design

Designing for inheritance involves more than just documenting patterns of self-use. To allow programmers to write efficient subclasses without undue pain, a class may have to provide hooks into its internal workings in the form of judiciously chosen protected methods or, in rare instances, protected fields.

For example, consider the following documentation for the removeRange method from the java.util.AbstractList specification:

protected void removeRange(int fromIndex, int toIndex)

Removes from this list all of the elements whose index is between fromIndex, inclusive, and toIndex, exclusive. Shifts any succeeding elements to the left (reduces their index). This call shortens the list by (toIndex – fromIndex) elements. (If toIndex == fromIndex, this operation has no effect.)

This method is called by the clear operation on this list and its sublists. Overriding this method to take advantage of the internals of the list implementation can substantially improve the performance of the clear operation on this list and its sublists.

Implementation Requirements: This implementation gets a list iterator positioned before fromIndex and repeatedly calls ListIterator.next followed by ListIterator.remove, until the entire range has been removed. Note: If ListIterator.remove requires linear time, this implementation requires quadratic time.

Parameters:

fromIndex - index of first element to be removed.

toIndex - index after last element to be removed.

The removeRange method is of no interest to end users of a List implementation; it is provided solely to make it easy for subclasses to provide a fast clear method on sublists. In the absence of the removeRange method, subclasses would have to make do with quadratic performance when the clear method was invoked on sublists or rewrite the entire subList mechanism from scratch—not an easy task!

How do you decide which protected members to expose when you design a class for inheritance? Unfortunately, there is no magic bullet. The best you can do is to think hard, take your best guess, and then test it by writing subclasses. You should expose as few protected members as possible because each one represents a commitment to an implementation detail. On the other hand, you must not expose too few because a missing protected member can render a class practically unusable for inheritance.

Write subclasses

The only way to test a class designed for inheritance is to write subclasses. If you omit a crucial protected member, trying to write a subclass will make the omission painfully obvious. Conversely, if several subclasses are written and none uses a protected member, you should probably make the class private. Experience shows that three subclasses are usually sufficient to test an extendable class. One or more of these subclasses should be written by someone other than the superclass author.

When you design for inheritance a class that is likely to achieve wide use, realize that you are committing forever to the self-use patterns that you document and to the implementation decisions implicit in its protected methods and fields. These commitments can make it difficult or impossible to improve the performance or functionality of the class in a subsequent release. Therefore, you must test your class by writing subclasses before you release it.

Also, note that the special documentation required for inheritance clutters up normal documentation, which is designed for programmers who create instances of your class and invoke methods on them.

Class restrictions

There are a few more restrictions that a class must obey to allow inheritance.

Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected. To make this concrete, the following is a class that violates this rule:

public class Super {

    // Broken - constructor invokes an overridable method

    public Super() {

        overrideMe();

    }

    public void overrideMe() {

    }

}

Here’s a subclass that overrides the overrideMe method, which is erroneously invoked by the Super class’s sole constructor.

public final class Sub extends Super {

    // Blank final, set by constructor

    private final Instant instant;

    Sub() {

        instant = Instant.now();

    }

    // Overriding method invoked by superclass constructor

    @Override public void overrideMe() {

           System.out.println(instant);

    }

    public static void main(String[] args) {

        Sub sub = new Sub();

        sub.overrideMe();

    }

}

You might expect this program to print out the value of Instant twice—but instead it prints null the first time because overrideMe is invoked by the Super constructor before the Sub constructor has a chance to initialize the instant field.

Note that this program observes a final field in two different states!

Note also that if overrideMe had invoked any method on instant, it would have thrown a NullPointerException when the Super constructor invoked overrideMe. The only reason this program doesn’t throw a NullPointerException as it stands is that the println method tolerates null parameters.

By the way, it is safe to invoke private methods, final methods, and static methods, none of which are overridable, from a constructor.

The Cloneable and Serializable interfaces present special difficulties when you are designing for inheritance. It is generally not a good idea for a class designed for inheritance to implement either of these interfaces because they place a substantial burden on programmers who extend the class. (There are, however, special actions that you can take to allow subclasses to implement these interfaces without mandating that they do so, but that is beyond the scope of this article.)

If you do decide to implement either Cloneable or Serializable in a class that is designed for inheritance, you should be aware that because the clone and readObject methods behave a lot like constructors, another restriction applies: Neither clone nor readObject may invoke an overridable method, directly or indirectly.

In the case of readObject, the overriding method will run before the subclass’s state has been deserialized. In the case of clone, the overriding method will run before the subclass’s clone method has a chance to fix the clone’s state. In either case, a program failure is likely to follow. In the case of clone, the failure can damage the original object as well as the clone! This can happen, for example, if the overriding method assumes it is modifying the clone’s copy of the object’s deep structure, but the copy hasn’t actually been made yet.

Important note: If you decide to implement Serializable in a class designed for inheritance and the class has a readResolve or writeReplace method, you must make those methods protected rather than private. If these methods are private, they will be silently ignored by subclasses. This is one more case where an implementation detail becomes part of a class’s API to permit inheritance.

Prohibit subclassing where it’s unsafe

By now it should be apparent that designing a class for inheritance requires great effort and places substantial limitations on the class. Designing for inheritance is not a decision to be undertaken lightly.

However, there are some situations where it is clearly the right thing to do, such as for abstract classes, including skeletal implementations of interfaces. There are other situations where it is clearly the wrong thing to do, such as for immutable classes.

But what about ordinary concrete classes? Traditionally, they are neither final nor designed and documented for subclassing, but this state of affairs is dangerous. Each time a change is made in such a class, there is a chance that subclasses extending the class will break. This is not just a theoretical problem. It is not uncommon to receive subclassing-related bug reports after modifying the internals of a nonfinal concrete class that was not designed and documented for inheritance.

The best solution to this problem is to prohibit subclassing in classes that are not designed and documented to be safely subclassed. There are two ways to prohibit subclassing. The easier of the two is to declare the class final. The alternative is to make all the constructors private or package-private and to add public static factories in place of the constructors. Either approach is acceptable.

This advice may be somewhat controversial because many programmers have grown accustomed to subclassing ordinary concrete classes to add facilities—such as instrumentation, notification, and synchronization—or to limit functionality. If a class implements some interface that captures its essence, such as Set, List, or Map, you should feel no compunction about prohibiting subclassing. Using a wrapper class provides a superior alternative to inheritance for augmenting the functionality.

If a concrete class does not implement a standard interface, you may inconvenience some programmers by prohibiting inheritance. If you feel that you must allow inheritance from such a class, one reasonable approach is to ensure that the class never invokes any of its overridable methods and to document this fact. In other words, eliminate the class’s self-use of overridable methods entirely. In doing so, you’ll create a class that is reasonably safe to subclass. Overriding a method will never affect the behavior of any other method.

You can eliminate a class’s self-use of overridable methods mechanically, without changing its behavior. To do so, move the body of each overridable method to a private “helper method” and have each overridable method invoke its private helper method. Then replace each self-use of an overridable method with a direct invocation of the overridable method’s private helper method.

Source: oracle.com

Wednesday, July 27, 2022

Advanced topics for using the Constrained Application Protocol (CoAP)

Use CoAP and the Observer design pattern to work with IoT devices.

The first article in this series on the Constrained Application Protocol (CoAP) covered the basics and explored how to add CoAP messaging in your own Java applications. This article concludes the discussion by exploring advanced topics such as the Observer design pattern, device discovery, and cross-protocol proxies.

CoAP meets the Observer pattern


CoAP, a basic REST-like request/response protocol, facilitates extensions. One example is the CoAP extension for observing resources via the Observer pattern.

To register interest in updates to a resource without polling for it continually, the CoAP client simply adds an OBSERVE entry in the request header with a value of 0. The Observer extension to CoAP supports confirmable and nonconfirmable registrations for resource updates. The sequence diagram in Figure 1 is a sample confirmable (CON) observer registration request with updates.

Core Java, Java Exam Prep, Java Materials, Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Preparation

Figure 1. A CON request with observer registration

First, client 1 makes a request to client 2 with the OBSERVE option in the header set to 0. This indicates a registration request. Client 2 sends an update with current data, echoing the token client 1 sent with the request, and it continues to use this token with each update. Since the request was a CON message, each response with data requires an ACK.

As time passes and the observed value changes, client 2 sends the new value in an updated CON response. Again, these updates contain the same token as the initial request, and client 1 must send an ACK. If an ACK is not sent, client 2 deregisters client 1 after the timeout period.

With the Californium CoAP library on the server side, the observation is implemented by marking the resource as observable, as shown in Listing 1.

Listing 1.  Marking a CoAP server resource as observable

public class CoapObserveServer extends CoapResource {
  // ...
  public CoapObserveServer(String name) {
    super(name);
    // enable observations and set type to CONS
    setObservable(true);
    setObserveType(Type.CON);

    // mark observable in the Link-Format
    getAttributes().setObservable();

    // schedule a periodic update timer
    // alternatively, call changed() as needed
    new Timer().schedule(new UpdateTask(), 0, 1000);
   }

For a client application, setting up the Observer pattern is like an asynchronous resource request (see Listing 2). You can download the complete client application from my GitHub repository.

Listing 2. Implementing the CoAP Observer pattern

class AsynchListener implements CoapHandler {
   @Override
   public void onLoad(CoapResponse response) {
       System.out.println( response.getResponseText() );
   }
@Override
   public void onError() { /*...*/ }
}
//...
CoapClient client =
   new CoapClient("coap://10.0.1.97:5683/temp");

// observer pattern uses asynchronous listener
AsynchListener asynchListener =
   new AsynchListener();

CoapObserveRelation observation =
   client.observe(asynchListener);
// ...
observation.proactiveCancel();

As with an asynchronous GET request, the first step is to supply a callback in the call to CoapClient.observe(). From that point onward, the callback receives updates as the data changes (such as measured temperature changes), according to the server resource.

On the server, calling the CoapResource.changed() method causes this CoAP server to automatically send a subsequent response (a temperature update) to the initial GET request for data on the observable resource, as shown in Listing 3.

Listing 3. Periodic updates cause a GET response to be sent to all observers.

private class UpdateTask extends TimerTask {
   @Override
   public void run() {
       changed(); // notify all observers
   }
}
@Override
public void handleGET(CoapExchange exchange) {
   // the Max-Age value should match the update interval
   exchange.setMaxAge(1);
   exchange.respond("Current temperature: " +
                    getCurrentTemp() );
}

For each active observer, the onload method is called, and the latest data value (temperature, in this example) is sent in the response. As shown at the end of Listing 2, you can cancel the observation and stop the updates by calling CoapObserveRelation.proactiveCancel(). This method sends a RESET message to the server in response to the next update. The server then removes this client from the list of observers for the associated resource.

Device discovery using CoAP


CoAP supports dynamic device discovery, which is useful in an Internet of Things (IoT) environment of changing networks of devices and sensors. To discover another CoAP server, the client is required to either know about the resource ahead of time or to support multicast CoAP via User Datagram Protocol (UDP) messaging on a multicast address and port. Servers that wish to be discoverable must listen and reply to requests on the “all CoAP nodes” multicast address to let other clients or servers know of its existence and addressable URI.

The multicast “all CoAP nodes” address is 224.0.1.187 for IPv4 and FF05::FD for IPv6. Sending a request for the CoAP resource directory name /.well-known/core should result in a reply from every reachable CoAP resource on the local network segment listening on the multicast address (see Listing 4).

Listing 4.  Listening for “all CoAP nodes” multicast requests

CoapServer server = ...
InetAddress addr = InetAddress.getByName("224.0.1.187");
bindToAddress = new InetSocketAddress(addr, COAP_PORT);
CoapEndpoint multicast = 
    CoapEndpoint.builder()
        .setInetSocketAddress(bindToAddress)
        .setPort(5683)
        .build();
server.addEndpoint(multicast);

In Listing 4, the multicast address is set as a CoapEndpoint to the Californium CoapServer object. You can create a CoAP GET request to discover CoAP servers and their resources, as shown in Listing 5, this time using the IPv6 multicast address.

Listing 5. A CoAP GET request to discover CoAP servers and resources on a local network

CoapClient client =
   new CoapClient("coap://FF05::FD:5683/.well-known/core");
client.useNONs();
CoapResponse response = client.get();
if ( response != null ) {
   // get server's IP address
   InetSocketAddress addr = 
       response.advanced()
           .getSourceContext()
           .getPeerAddress();
   int port = addr.getPort();
   System.out.println("Source address: " +
                       addr + ":" + port);
}

Note that the request must be a NON GET request, hence the call to client.useNONs() in the second line. Additionally, making a request to the base URI coap://FF05::FD:5683 yields basic information about the server, such as the resources and associated URIs it supports.

Dynamic resource discovery is useful when you’re building a dynamic IoT application; in that case, it’s not desired to hardcode or manually configure available CoAP servers and their resources.

For instance, if you have a single controller application that allows all lights (or other appliances) within a room or building floor to be turned off and on together, you can use a resource discovery to locate all available smart lighting devices. Using the results of the discovery, you can send CoAP commands to each smart lighting device to turn off and on, as appropriate. If new lighting devices are added at some future date, the controller code continues to work on all lighting devices with no change needed.

The CoAP resource directory


To better enable resource discovery for constrained devices — that is, some devices that are sleeping or noncommunicative at times — a CoAP resource directory was defined. This entity maintains descriptions of CoAP servers and resources within your distributed application. Specifically, devices can register themselves as servers, along with their resources, in a well-known resource directory node.

CoAP client applications can subsequently refer to the resource directory to learn about resources as they become available and then become part of the distributed application.

CoAP endpoints register themselves with the resource directory via its registration interface (see Figure 2). CoAP client applications then use the lookup or CoAP group interfaces  (more on groups in the next sections)  to learn about available resources.

Core Java, Java Exam Prep, Java Materials, Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Preparation

Figure 2. The CoAP resource directory interfaces

Endpoints register their resources by sending a POST request with the resource path (such as /temp), the endpoint name, and optional data such as a domain, the endpoint type, and other data. If the POST request is successful, the response code is 2.01, and a resource identifier is returned (such as /rd/1234). This identifier can be used to access the CoAP resource through the resource directory server. For example, the code in Listing 6 registers a pulse oximeter’s heart rate and oxygen saturation telemetry resources.

Listing 6. The client code to register CoAP endpoint resources with a resource directory server

String host = "coap://10.0.1.111/";
CoapClient rd;
System.out.println("Registering resource: heart rate ");
rd = new CoapClient(host+"rd?ep=pulseoximeter/heartrate/");
resp = rd.post("</pulseoximeter/heartrate>;"
               + "ct=41;rt=\"Heartrate Resource\";"
               + "if=\"sensor\"",
              MediaTypeRegistry.APPLICATION_LINK_FORMAT);
System.out.println("--Response: " +
                  resp.getCode() + ", " +
                  resp.getOptions().getLocationString());
System.out.println("Registering resource: oxygen-saturation ");
rd = new CoapClient(host+"rd?ep=pulseoximeter/oxygen-saturation/");
resp = rd.post("</pulseoximeter/oxygen-saturation>;"
               + "ct=41;rt=\"Oxygen Saturation Resource\";"
               + "if=\"sensor\"",
              MediaTypeRegistry.APPLICATION_LINK_FORMAT);
System.out.println("--Response: " +
                  resp.getCode() + ", " +
                  resp.getOptions().getLocationString());

First, the code connects to a CoAP resource directory server running on node 10.0.1.111 (an arbitrary address for this example). It connects using a resource endpoint name of /pulseoximeter/heartrate because that’s the resource it registers first. Next, a POST request is made using that endpoint, a URI path of /pulseoximeter/heartrate, a name of Heartrate Resource, and an endpoint type sensor. The same is done for the other resource, /pulseoximeter/oxygen-saturation. When this is executed successfully, you should see output like Listing 7.

Listing 7.  The result of a successful resource registration

Registering resource: heartrate
--Response: 2.01, /rd/pulseoximeter/heartrate
Registering resource: oxygen-saturation
--Response: 2.01, /rd/pulseoximeter/oxygen-saturation

To further illustrate the results of registration, Listing 8 adds code to make a resource discovery request to the resource directory server.

Listing 8. Sending a resource discovery request to the resource directory server

CoapClient q = new CoapClient("coap://10.0.1.111/.well-known/core");
CoapResponse resp = q.get();
System.out.println( "--Registered resources: " +
                   resp.getResponseText());

Adding this code both before the endpoint registration requests and after yields the complete set of output shown in Listing 9.

Listing 9. The results of endpoint registration

--Registered resources: </rd>;rt="core.rd",</rd-lookup>;rt="core.rd-lookup",</rd-lookup/d>,</rd-lookup/ep>,</rd-lookup/res>,</.well-known/core>,</tags>
Registering resource: heartrate
--Response: 2.01, /rd/pulseoximeter/heartrate
Registering resource: oxygen-saturation
--Response: 2.01, /rd/pulseoximeter/oxygen-saturation
--Registered resources: </rd>;rt="core.rd",</rd/pulseoximeter/heartrate/>,</rd/pulseoximeter/oxygen-saturation/>,</rd-lookup>;rt="core.rd-lookup",</rd-lookup/d>,</rd-lookup/ep>,</rd-lookup/res>,</.well-known/core>,</tags>

Note that the result from the resource discovery request, made after the endpoint registration POST requests, now includes the two added pulse oximeter endpoint resources, as expected.

CoAP resource group definitions


To further enable CoAP device group communication, the CoAP CoRE Working Group defined the “Group Communication for the Constrained Application Protocol” specification (RFC 7390). (CoRE stands for constrained RESTful environments.) This specification outlines methods to define and subsequently communicate with groups of devices.

For instance, for a CoAP server that supports RFC 7390, a POST request to the resource /coap-group with a group name and index provided as form data would create a new CoAP resource group. An example is shown in Listing 10.

Listing 10.  CoAP resource group creation as a POST message

POST /coap-group
Content-Format: application/coap-group+json
{
 "n": "lights.floor1.example.com",
 "a": "[ff15::4200:f7fe:ed37:abcd]:1234"
}

If the action is successful, the response is like that shown in Listing 11.

Listing 11. The response for a POST request to create a new CoAP resource group

2.01 Created
Location-Path: /coap-group/12

Sending a GET request to /coap-group returns JSON data indicating all members of the group. A sample response is shown in Listing 12.

Listing 12. A CoAP GET response for a CoAP group request

2.05 Content
Content-Format: application/coap-group+json
{
   "8" : { "a": "[ff15::4200:f7fe:ed37:14ca]" },
   "11": { "n": "sensors.floor1.example.com",
           "a": "[ff15::4200:f7fe:ed37:25cb]" },
   "12": { "n": "lights.floor1.example.com",
           "a": "[ff15::4200:f7fe:ed37:abcd]:1234" }
}

Subsequently, you can make requests to a specific group, such as /coap-group/12, to control or read the status of the devices within that group as a whole.

Cross-protocol proxying (CoAP and HTTP)


Because CoAP is a REST-based protocol based on the underlying HTTP implementation, it’s straightforward to map CoAP methods to HTTP. As such, it’s straightforward to proxy CoAP requests to and from HTTP so CoAP clients can access resources available on an HTTP server or allow HTTP clients (such as JavaScript code) to make requests to CoAP servers.

For example, the code in Listing 13 is from the Californium sample code and shows how to implement a simple CoAP-to-CoAP and CoAP-to-HTTP proxy.

Listing 13. A simple CoAP-to-HTTP proxy from the Californium sample applications

private static class TargetResource extends CoapResource {
   private int counter = 0;
   public TargetResource(String name) {
       super(name);
   }
   @Override
   public void handleGET(CoapExchange exchange) {
       exchange.respond(
           "Response " + (++counter) +
           " from resource " + getName() );
   }
}
public coap_cross_proxy() throws IOException {
   ForwardingResource coap2coap =
       new ProxyCoapClientResource("coap2coap");
   ForwardingResource coap2http =
       new ProxyHttpClientResource("coap2http");
   // Create CoAP Server with proxy resources
   // from CoAP to CoAP and HTTP
   targetServerA = new CoapServer(8082);
   targetServerA.add(coap2coap);
   targetServerA.add(coap2http);
   targetServerA.start();
   ProxyHttpServer httpServer =
       new ProxyHttpServer(8080);
   httpServer.setProxyCoapResolver(
       new DirectProxyCoapResolver(coap2coap) );
   System.out.println(
       "CoAP resource \"target\" available over HTTP at: " +
       "http://localhost:8080/proxy/coap://localhost:PORT/target");
}

Running a resource named helloWorld as coap://localhost:5683/helloWorld and browsing to the proxy URL, as specified in the code, results in the payload being displayed in the browser; see Figure 3.

Core Java, Java Exam Prep, Java Materials, Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Preparation

Figure 3. The result of a CoAP-to-HTTP proxy, with the response text displayed in the browser

By the way, CoAP can be proxied to other protocols, such as the Session Initiation Protocol (SIP) and the Extensible Messaging and Presence Protocol (XMPP).

The Californium CoAP implementation and cf-browser


The Eclipse Californium project provides an open source CoAP implementation you can use to enable CoAP communication in your applications. The project can be downloaded from the GitHub repository.

You need Maven to build and install Californium. To use Maven, set your JAVA_HOME and M2_HOME environment variables, and then run the following Maven command:

> mvn clean install -DskipTests

You can include Californium in your projects by adding the following to your Maven pom.xml file:

<dependency>
    <groupId>org.eclipse.californium</groupId>
    <artifactId>californium-core</artifactId>
    <version>3.5.0</version>
</dependency>

Californium comes with a set of tools to help you code and debug CoAP applications. One of the most useful is a JavaFX-based browser, cf-browser, that you can use to visually discover, explore, and interact with CoAP devices on your network. It’s a useful tool that I recommend for learning and debugging CoAP endpoint programming.

First, clone the GitHub repository:

> git clone https://github.com/eclipse/californium.tools.git

Next, install OpenJFX. For Windows, download the binary from OpenJFX. For Linux, install it with Aptitude using the following command:

> sudo apt install openjfx

Next, within the californium.tools directory, build the tools with the following command:

> mvn clean install

To run the CoAP browser change into the cf-browser directory, and run the following command:

> mv javafx:run

Once cf-browser is installed and running, browse to the address of a CoAP node on your network. For instance, Figure 4 shows the result of typing coap://localhost:5683 into the Target address textbox and then clicking the DISCOVERY button in the upper right.

Core Java, Java Exam Prep, Java Materials, Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Preparation

Figure 4. The cf-browser tool visually displays and interacts with CoAP instances.

You can interact with the tool by discovering the resources available on your network and sending data to resources you select via the buttons labeled GET, POST, and so on. You can even receive continuous CoAP updates for observable resources by selecting the OBSERVE button. The resulting data is displayed in the Response section, as shown in Figure 5.

Core Java, Java Exam Prep, Java Materials, Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Preparation

Figure 5. Interacting with CoAP resources to discover and debug them with cf-browser

Other tools included with Californium are a command-line client (cf-client) you can use to easily listen on CoAP resources and a standalone CoAP server.

Source: oracle.com

Friday, July 22, 2022

BYOTE, Part 1: Build your own custom test engine for JUnit 5

The standard JUnit tests are fine, but sometimes you want to try something specific. Here’s how.

Repeat after us: JUnit 5 is not a test runner. JUnit 5 is a platform. The JUnit 5 platform was designed from the ground up to solve one problem: to separate the development of test runners from their integration with IDEs and build tools. To this end, JUnit 5 introduces the concept of a test engine. This two-part series will answer the following questions:

◉ What is a JUnit test engine, and why would you want to build one?

◉ How do you build a very simple one?

◉ What do you have to do to integrate your engine with IDEs and build tools? (spoiler: almost nothing)

In part 1 of this “build your own test engine” (BYOTE) series, you will see how a minimal test engine can be implemented, and in part 2, you will see how it can be tested. To learn from the authors of several well-known test engines, part 2 of this series will contain interviews about their experiences in building real-world engines.

Why would anyone build a custom test engine?

Have you ever wanted to build your own test engine? On the JUnit platform, this is easier than you might think. To show off the flexibility of the JUnit platform, you will develop a completely declarative test engine.

Developing functionality is all fun and games, but how do you actually test a test engine? It turns out that the JUnit platform brings tools for exactly that.

But what good is your custom engine if it is hard to execute and get reports for the results? No one will want to use it—probably not even you. Fortunately, the JUnit platform was designed from the ground up to solve this exact problem: Your test engine will be executable in all major IDEs and build tools without almost any effort on your part!

So, apart from curiosity, why would you even want to create a custom engine? Here are three possible reasons.

◉ You want a different testing model than what you can find elsewhere, such as one that focuses on performance, mutation, or property-based testing.

◉ You want improved support for the idioms of a different JVM language such as Groovy, Kotlin, or Clojure.

◉ You want a Java-based tool but with a custom syntax to support the specific requirements of a certain problem domain.

You, of course, might have other reasons, so let’s see how to build a custom engine. Before that, however, a bit of architectural background about JUnit 5 is essential.

JUnit 5 101

Contrary to public opinion, JUnit 5 is a platform rather than a simple test runner. To understand the need for such a platform, it is helpful to take a look at some JUnit history.

Early versions of JUnit were not designed with tool integration in mind. Due to the wild success of those early versions, however, IDEs and build tools began integrating JUnit into their environments quite soon. However, because JUnit was not designed to be executed from third-party processes, integrators sometimes had to rely on dangerous mechanisms, such as reflection, to make things work.

Such integrations were naturally brittle and were very hard to change and maintain because the outside world relied upon, and was coupled to, JUnit’s internals—even private members. An infamous example for this coupling is the breaking of the integration in a widely used IDE when a JUnit 4.x version changed the name of a private field. This situation was only exacerbated by other test libraries and frameworks mimicking JUnit’s structure to leverage JUnit’s IDE integration.

Therefore, while planning and designing the new generation of JUnit, the JUnit team took special care to avoid such coupling. As a matter of fact, the team invited representatives from all major IDEs and build tools to a kick-off meeting in October 2015 to discuss a solid foundation for an integration architecture. The main goal was to provide different APIs for different groups of users, namely

◉ An engine service provider interface (SPI) (junit-platform-engine) for integrators of existing test engines and authors of new test engines

◉ A launcher API (junit-platform-launcher) for IDEs and build tools to provide stable and transparent means of integrating all test engines

◉ An annotation-based API (junit-jupiter-api) for test authors, which would be similar in look and feel to the JUnit 4.x generation but with a more flexible extension model

The first two are the core components of the JUnit 5 platform, and Figure 1 shows the essential parts of the JUnit 5 platform and several engines built upon it.

Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Learning, Oracle Java Preparation, Oracle Java Career, Java Skills, Java Jobs, Java Tutorial and Material
Figure 1. The JUnit 5 platform architecture

This clear separation of concerns is fundamental to the new architecture and has so far served well to avoid the problematic coupling. As a consequence, the JUnit platform has been integrated into all major IDEs and build tools using the launcher API.

Similarly, the platform engine SPI has been used to integrate various test engines with the JUnit 5 platform. This allows test engine authors to concentrate on the test definition and execution concerns and completely disregard the aspect of launching their test cases from IDEs and build tools. A special case is, of course, JUnit’s own Jupiter test engine, which uses the new JUnit 5 test model. However, even this built-in engine uses only the public API and has no secret access to other parts of JUnit 5.

To show how easy it is for engine authors to integrate tools with the JUnit platform, you’ll develop a (very) small test engine from scratch, named WebSmokeTest.

WebSmokeTest: The world’s smallest test engine


For most JVM languages, basing the test model on classes and methods seems a natural fit. However, other test definition models are possible in principle—as long as individual tests can be described unambiguously by an org.junit.platform.engine.TestDescriptor implementation.

Typically, a test descriptor implementation has to be provided by the test engine author and represents a testable element of the given programming model, such as a single test (FieldTestDescriptor) or a container of tests (ClassTestDescriptor).

For the purpose of this article, we want to implement an engine that is both small and lightweight. Hence, we could contemplate alternatives to a method-based test model. One option might be to use lambdas assigned to fields—because lambdas can be considered a form of lightweight methods. This is possible, since we could use java.util.function.Predicate implementations using the aptly named method boolean test(T t) for test execution and the boolean as a success/failure indicator.

While such lambdas might be a bit more lightweight than full-blown methods, maybe we can take this a bit further. We will do so soon, but let’s consider the domain in detail first.

The problem domain: Web smoke testing


As mentioned in the introduction, there can be different reasons for creating a custom engine. Here, you want to support the requirements of a special domain in such a way that creating tests becomes very simple for the test author. As a simple yet still useful example, we pick the domain of HTTP-based smoke tests—in this case, a test that merely tests whether a URL works. Specifically, you need

◉ A succinct way to define the URL against which the smoke test should be executed
◉ A simple means to specify the expected HTTP status code

Consider the test successful if an HTTP GET request against the specified URL results in the specified HTTP status code. As for behavior, the degrees of freedom are extremely limited: WebSmokeTest always does the same thing, namely, execute an HTTP request against a certain server.

Since this test does not need variations in behavior, you can get rid of methods with explicitly programmed statements entirely (or lambdas, for that matter). You can choose a completely declarative approach: The HTTP URLs will be fields of type String. Because you might want to add support for POST and other verbs later, model the HTTP verb as an annotation, and model the expected status code as an argument of the annotation. Hence, a complete smoke test would look like as follows:

@GET(expected = 200)
String shouldReturn200 = "https://blogs.oracle.com/javamagazine/";

The actual implementation described below adds the public and static modifiers—but this is for implementation simplicity only and has no real bearing on the test model.

Agreements must be kept


When you design a custom test engine, it is important to understand the contract between a test engine and the JUnit platform. This contract is defined by the org.junit.platform.engine.TestEngine interface, would looks as follows:

String getId();

TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId);

void execute(ExecutionRequest request);

Apart from some optional metadata, this interface contains three core responsibilities of a test engine. These core responsibilities are

◉ Identification: The engine must provide a unique string by which it can be referenced and differentiated from other engines on the classpath. For example, Jupiter’s ID is junit-jupiter.

◉ Discovery: The engine must be able to inform the JUnit platform about everything it considers its own test cases. These are arranged in a tree structure, with the returned TestDescriptor being the root node.

◉ Execution: When requested by the platform, the engine must be able to execute a given ExecutionRequest. This request contains a TestDescriptor referencing the tests to be run and provides an EngineExecutionListener to the engine. The former was previously returned by the engine’s own discover method. The latter is then used by the engine’s implementation to fire test lifecycle events, such as executionStarted() or executionFinished().

In many cases, test engines will support a hierarchical test definition model—mirroring Java’s hierarchical structure of packages, classes, and methods. The JUnit platform provides special support for such hierarchical engines in the form of the org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine base class. JUnit’s own Jupiter test engine is itself an extension of this base class. By using this support, advanced features, such as parallel execution, can be readily reused by custom engines. However, for the sake of simplicity and clarity WebSmokeTest will not use this base class; it will implement the required interfaces directly.

Implementing the minimal test engine


A test engine usually consists of the engine class itself and one or more TestDescriptor implementations. In this example, there are also two annotations. This is in no way mandatory—when designing this exercise, we happened to choose an annotation-based testing model. For such implementations, the JUnit platform provides good support with the org.junit.platform.commons.support.AnnotationSupport utility. Listing 1 shows the implementation of the custom test engine.

Listing 1. Implementation of the custom test engine

public class WebSmokeTestEngine implements TestEngine {

    private static final Predicate<Class<?>> IS_WEBSMOKE_TEST_CONTAINER
            = classCandidate -> AnnotationSupport.isAnnotated(classCandidate, WebSmokeTest.class);


    @Override
    public String getId() {
        return "websmoke-test";
    }


    @Override
    public TestDescriptor discover(EngineDiscoveryRequest request, UniqueId uniqueId) {
        TestDescriptor engineDescriptor = new EngineDescriptor(uniqueId, "Web Smoke Test");

        request.getSelectorsByType(ClasspathRootSelector.class).forEach(selector -> {
            appendTestsInClasspathRoot(selector.getClasspathRoot(), engineDescriptor);
        });

        request.getSelectorsByType(PackageSelector.class).forEach(selector -> {
            appendTestsInPackage(selector.getPackageName(), engineDescriptor);
        });

        request.getSelectorsByType(ClassSelector.class).forEach(selector -> {
            appendTestsInClass(selector.getJavaClass(), engineDescriptor);
        });

        return engineDescriptor;
    }

    private void appendTestsInClasspathRoot(URI uri, TestDescriptor engineDescriptor) {
        ReflectionSupport.findAllClassesInClasspathRoot(uri, IS_WEBSMOKE_TEST_CONTAINER, name -> true) //
                .stream() //
                .map(aClass -> new ClassTestDescriptor(aClass, engineDescriptor)) //
                .forEach(engineDescriptor::addChild);
    }

    private void appendTestsInPackage(String packageName, TestDescriptor engineDescriptor) {
        ReflectionSupport.findAllClassesInPackage(packageName, IS_WEBSMOKE_TEST_CONTAINER, name -> true) //
                .stream() //
                .map(aClass -> new ClassTestDescriptor(aClass, engineDescriptor)) //
                .forEach(engineDescriptor::addChild);
    }

    private void appendTestsInClass(Class<?> javaClass, TestDescriptor engineDescriptor) {
        if (AnnotationSupport.isAnnotated(javaClass, WebSmokeTest.class)) {
            engineDescriptor.addChild(new ClassTestDescriptor(javaClass, engineDescriptor));
        }
    }

    @Override
    public void execute(ExecutionRequest request) {
        TestDescriptor root = request.getRootTestDescriptor();

        new SmokeTestExecutor().execute(request, root);
    }

}

In Listing 1, you can see integration, discovery, and execution at work. The discover(EngineDiscoveryRequest, UniqueId) method creates an engine descriptor and adds test descriptors hierarchically, while the EngineDiscoveryRequest gives access to several implementations of org.junit.platform.engine.DiscoverySelector. Such selectors can reference various structural elements of Java (such as methods, classes, packages, and the whole classpath) or the file system (files, directories), as well as JUnit’s own UniqueId instances. The test engine uses these to indicate to the requesting tool (such as an IDE) what it considers test cases associated with every such element according to its specific test model.

The last method in Listing 1 takes care of test execution: execute(ExecutionRequest request) accepts an ExecutionRequest and delegates most of the actual work to a helper class named SmokeTestExecutor. In this class, the various TestDescriptor variants are handled and the individual tests are executed. The most important parts are shown in Listing 2.

Listing 2. The execution of a single test

private void executeTest(ExecutionRequest request, FieldTestDescriptor fieldTestDescriptor) {
    request.getEngineExecutionListener().executionStarted(fieldTestDescriptor);
    TestExecutionResult executionResult = executeTestField(fieldTestDescriptor);
    request.getEngineExecutionListener().executionFinished(fieldTestDescriptor, executionResult);
}

private TestExecutionResult executeTestField(FieldTestDescriptor descriptor) {

    Field testField = descriptor.getTestField();

    try {
        int expected = getExpectedStatusCode(testField);
        String url = getUrl(testField);

        HttpResponse<String> response = this.executeHttpRequest(url);
        int actual = response.statusCode();
        if (expected != actual) {
            var message = String.format("expected HTTP status code %d but received %d from server", expected, actual);
            return TestExecutionResult.failed(new AssertionFailedError(message, expected, actual));
        }

    } catch (Exception e) {
        return TestExecutionResult.failed(new RuntimeException("Failed to execute HTTP request", e));
    }

    return TestExecutionResult.successful();
}

The executeTest method is responsible for sandwiching the actual execution call between lifecycle events. The executeTestField method retrieves the URL and the expected status code, and then it actually executes the HTTP request via a (purely technical) helper method. If a response is received, the method checks the actual status code and creates a TestExecutionResult.failed() with an AssertionFailedError in case the response does not meet the expectation. If sending the request throws an exception, it is wrapped in a more technical RuntimeException and a TestExecutionResult.failed() result. If all goes well, the method returns a TestExecutionResult.successful() result. This basically is the complete custom test engine.

The following example annotates the test class with @WebSmokeTest to identify the test classes. It contains three separate test cases defined by simple fields, and each field is annotated with @GET denoting the need to execute an HTTP GET request. (Supporting POST or other HTTP verbs would be just as simple.)

The target URL of the request is specified in the value of the field. As mentioned above, you have complete freedom in the new test engine regarding how to design a test model. You might have used methods, as most traditional test engines do. Or you might have specified the expected value as a method return type. All are perfectly valid options. Listing 3 shows three test cases.

Listing 3. Three test cases for the new engine

@WebSmokeTest
public class ExampleWebSmokeTests {

    @GET(expected = 200)
    public static String shouldReturn200 = "https://blogs.oracle.com/javamagazine/";

    @GET(expected = 401)
    public static String shouldReturn401 = "https://httpstat.us/401";

    @GET(expected = 201)
    public static String expect201ButGet404 = "https://httpstat.us/404";

}

Now that you have an engine implementation and a number of sample tests in place, you only need to let the platform (and hence, IDEs and build tools) know about the new test engine.

Test engine integration


This test engine class can be immediately executed in an IDE such as IntelliJ IDEA if two conditions are fulfilled. First, you need the test engine code on the classpath (typically in a Maven/Gradle dependency). Second, the new engine must be registered with the JUnit platform. This is done via Java’s well-known SPI. To this end, a special file must be present on the classpath, as you can see in Figure 2.

Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Learning, Oracle Java Preparation, Oracle Java Career, Java Skills, Java Jobs, Java Tutorial and Material
Figure 2. The JUnit configuration file using the Java SPI mechanism

For the SPI mechanism to work, the filename must specify the SPI, here named org.junit.platform.engine.TestEngine. The file contains only one line, the fully qualified name (FQN) of the main engine class, which in this case is org.example.websmoke.engine.WebSmokeTestEngine. This FQN must refer to a class implementing the interface specified by the filename. When the main engine class is executed in the IDE, the test result should look as shown in Figure 3.

Oracle Java Certification, Oracle Java Tutorial and Materials, Oracle Java Learning, Oracle Java Preparation, Oracle Java Career, Java Skills, Java Jobs, Java Tutorial and Material
Figure 3. Execution of the main engine class in the IDE

As can be seen in Figure 3, the project uses domain-specific custom display names to reference the individual test cases in the GUI of the executing IDE. Thus, in this case, you can even display the whole test definition (the URL and the expected status code) right next to the IDE symbol indicating success or failure. Such flexibility is enabled by the TestDescriptor model, freeing the IDE from the need to mechanically display plain method or field names in all cases.

Source: oracle.com