JSON XML with JSON Example

JSON XML with JSON Example

Understanding JSON XML with JSON Example

JSON is one of the newest, yet most widely used forms of media for sending communications between two or more machines. In expanded form, it stands for JavaScript Object Notation. In the planning stages for Java 9, there were plans to include a standard JSON processing (JSON-P) API with the release, however, the enhancement proposal did not make it int o the release.

 

Instead, it is still very easy to work with JSON data by simply including the JSON-P library, which is currently included in Java EE. Part of the plan for an upcoming release of JSON-P is to provide direct support for Java SE.

 

XML APIs have always been available to the Java developer, usually supplied as third-party libraries that could be added to the runtime class path. Beginning in Java 7, the Java API for XML Processing (JAXP), Java API for XML Binding (JAXB), and the Java API for XML Web Services (JAX-WS) were included in the core runtime libraries.

 

The most fundamental XML processing tasks that you will encounter involve only a few use cases: writing and reading XML documents, validating those documents, and using JAXB to assist in marshalling/unmarshalling Java objects.

 

This blog provides recipes for performing JSON XML and JSON-P tasks with JSON examples. The JSON-P recipes will require inclusion of the JSON-P API, which can be done by adding the dependencies to a maven application. In this blog, you will learn how to create JSON, as well as write it to disk and perform parsing.

 

Note The source code for this blog’s examples is available in the org.java9recipes.blog20 package.

 

Writing an XML File

Writing an XML File

Problem: You want to create an XML document to store application data.

Solution

To write an XML document, use the javax.xml.stream.XMLStreamWriter class. The following code iterates over an array of Patient objects and writes the data to an .xml file. This sample code comes from the org. java9recipes.blog20.recipe20_1.DocWriter example:

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
...
public void run(String outputFile) throws FileNotFoundException, XMLStreamException, IOException {
List<Patient> patients = new ArrayList<>(); Patient p1=new Patient(); Patient p2=new Patient(); Patient p3=new Patient(); p1.setId(BigInteger.valueOf(1)); p1.setName("John Smith"); p1.setDiagnosis("Common Cold"); p2.setId(BigInteger.valueOf(2)); p2.setName("Thesis"); p2.setDiagnosis("Broken Ankle"); p3.setId(BigInteger.valueOf(3)); p3.setName("Jack Brown"); p3.setDiagnosis("Food Allergy"); patients.add(p1); patients.add(p2); patients.add(p3); XMLOutputFactory factory=XMLOutputFactory.newFactory(); try (FileOutputStream fos=new FileOutputStream(outputFile)) { XMLStreamWriter writer=factory.createXMLStreamWriter(fos, "UTF-8"); writer.writeStartDocument(); writer.writeCharacters("\n"); writer.writeStartElement("patients"); writer.writeCharacters("\n"); for (Patient p : patients) { writer.writeCharacters("\t"); writer.writeStartElement("patient"); writer.writeAttribute("id", String.valueOf(p.getId())); writer.writeCharacters("\n\t\t"); writer.writeStartElement("name"); writer.writeCharacters(p.getName()); writer.writeEndElement(); writer.writeCharacters("\n\t\t"); writer.writeStartElement("diagnosis"); writer.writeCharacters(p.getDiagnosis()); writer.writeEndElement(); writer.writeCharacters("\n\t"); writer.writeEndElement(); writer.writeCharacters("\n"); } writer.writeEndElement(); writer.writeEndDocument(); writer.close(); } } The previous code writes the following file contents: <?xml version="1.0" ?>
<patients>
<patient id="1">
<name>John Smith</name>
<diagnosis>Common Cold</diagnosis>
</patient>
<patient id="2">
<name>Thesis</name>
<diagnosis>Broken ankle</diagnosis>
</patient>
<patient id="3">
<name>Jack Brown</name>
<diagnosis>Food allergy</diagnosis>
</patient>
</patients>

 

How It Works

JSON XML

The Java standard library provides several ways to write XML documents. One model is the Simple API for XML (SAX). The newer, simpler, and more efficient model is the Streaming API for XML (StAX). This recipe uses StAX defined in the javax.xml.stream package. Writing an XML document takes five steps:

  • \1.\ Create a file output stream.
  • \2.\ Create an XML output factory and an XML output stream writer.
  • \3.\ Wrap the file stream in the XML stream writer.
  • \4.\ Use the XML stream writer’s write methods to create the document and write the XML elements.
  • \5.\ Close the output streams.

 

Create a file output stream using the java.io.FileOutputStream class. You can use a try-block to open and close this stream.

The javax.xml.stream.XMLOutputFactory provides a static method that creates an output factory. Use the factory to create a javax.xml.stream.XMLStreamWriter.

 

Once you have the writer, wrap the file stream object in the XML writer instance. You will use the various write methods to create the XML document elements and attributes. Finally, you simply close the writer when you finish writing to the file. Some of the more useful methods of the XMLStreamWriter instance are these:

writeStartDocument()
writeStartElement()
writeEndElement()
writeEndDocument()
writeAttribute()

 

After creating the file and XMLStreamWriter, you always should begin the document by calling the writeStartDocumentMethod() method. Follow this by writing individual elements using the writeStartElement() and writeEndElement() methods in combination. Of course, elements can have nested elements.

 

You have the responsibility to call these in proper sequence to create well-formed documents. Use the writeAttribute() method to place an attribute name and value into the current element. You should call writeAttribute() immediately after calling the writeStartElement() method. Finally, signal the end of the document with the writeEndDocument() method and close the Writer instance.

 

One interesting point of using the XMLStreamWriter is that it does not format the document output. Unless you specifically use the writeCharacters() method to output space and newline characters, the output will stream to a single unformatted line. Of course, this doesn’t invalidate the resulting XML file, but it does make it inconvenient and difficult for humans to read.

 

Therefore, you should consider using the writeCharacters() method to output spacing and newline characters as needed to create a human readable document. You can safely ignore this method of writing additional whitespace and line breaks if you do not need a document for human readability. Regardless of the format, the XML document will be well formed because it adheres to correct XML syntax.

 

The command-line usage pattern for this example code is this:

java org.java9recipes.blog20.recipe20_1.DocWriter <outputXmlFile>
Invoke this application to create a file named patients.xml in the following way:
java org.java9recipes.blog20.recipe20_1.DocWriter patients.xml

 

Reading an XML File

JSON XML

 

Problem: You need to parse an XML document, retrieving known elements and attributes.

 

Solution 1

Use the javax.xml.stream.XMLStreamReader interface to read documents. Using this API, your code will pull XML elements using a cursor-like interface similar to that in SQL to process each element in turn. The following code snippet from org.java9recipes.DocReader demonstrates how to read the patients.xml file that was generated in the previous recipe:

public void cursorReader(String xmlFile)
throws FileNotFoundException, IOException, XMLStreamException {
XMLInputFactory factory = XMLInputFactory.newFactory(); try (FileInputStream fis = new FileInputStream(xmlFile)) {
XMLStreamReader reader = factory.createXMLStreamReader(fis);
boolean inName = false;
boolean inDiagnosis = false;
String id = null;
String name = null;
String diagnosis = null;
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
String elementName = reader.getLocalName();
switch (elementName) {
case "patient":
id = reader.getAttributeValue(0);
break;
case "name":
inName = true;
break;
case "diagnosis":
inDiagnosis = true;
break;
default:
break;
}
break;
case XMLStreamConstants.END_ELEMENT:
String elementname = reader.getLocalName();
if (elementname.equals("patient")) {
System.out.printf("Patient: %s\nName: %s\nDiagnosis: %s\n\n",id, name, diagnosis);
id = name = diagnosis = null;
inName = inDiagnosis = false;
}
break;
case XMLStreamConstants.CHARACTERS:
if (inName) {
name = reader.getText();
inName = false;
} else if (inDiagnosis) { diagnosis = reader.getText(); inDiagnosis = false;
}
break;
default:
break;
}
}
reader.close();
}
}

 

Solution 2

Use the XMLEventReader to read and process events using an event-oriented interface. This API is called an iterator-oriented API as well. The following code is much like the code in Solution 1, except that it uses the event-oriented API instead of the cursor-oriented API. This code snippet is available from the same org.java9recipes.blog20.recipe20_1.DocReader class used in Solution 1:

public void eventReader(String xmlFile)
throws FileNotFoundException, IOException, XMLStreamException { XMLInputFactory factory = XMLInputFactory.newFactory(); XMLEventReader reader = null;
try(FileInputStream fis = new FileInputStream(xmlFile)) { reader = factory.createXMLEventReader(fis); boolean inName = false;
boolean inDiagnosis = false;
String id = null;
String name = null;
String diagnosis = null;
while(reader.hasNext()) {
XMLEvent event = reader.nextEvent();
String elementName = null;
switch(event.getEventType()) {
case XMLEvent.START_ELEMENT:
StartElement startElement = event.asStartElement(); elementName = startElement.getName().getLocalPart(); switch(elementName) {
case "patient":
id = startElement.getAttributeByName(QName.valueOf("id")).getValue(); break;
case "name":
inName = true;
break;
case "diagnosis":
inDiagnosis = true;
break;
default:
break;
}
break;
case XMLEvent.END_ELEMENT:
EndElement endElement = event.asEndElement(); elementName = endElement.getName().getLocalPart(); if (elementName.equals("patient")) {
System.out.printf("Patient: %s\nName: %s\nDiagnosis: %s\n\n",id, name, diagnosis);
id = name = diagnosis = null;
inName = inDiagnosis = false;
}
break;
case XMLEvent.CHARACTERS:
String value = event.asCharacters().getData(); if (inName) {
name = value;
inName = false;
} else if (inDiagnosis) { diagnosis = value;
inDiagnosis = false;
}
break;
}
}
}
if(reader != null) {
reader.close();
}
}

 

How It Works

XMLEvent objects

Java provides several ways to read XML documents. One way is to use StAX, a streaming model. It is better than the older SAX API because it allows you to both read and write XML documents. Although StAX is not quite as powerful as a DOM API, it is an excellent and efficient API that is less taxing on memory resources.

 

StAX provides two methods for reading XML documents: a cursor API and an iterator API. The cursor-oriented API utilizes a cursor that can walk an XML document from start to finish, pointing to one element at a time, and always moving forward.

 

The iterator API represents an XML document stream as a set of discrete event objects, provided in the order that they are read in the source XML. The event-oriented, iterator API is preferred over the cursor API at this time because it provides XMLEvent objects with the following benefits:

 

The XMLEvent objects are immutable and can persist even though the StAX parser has moved on to subsequent events. You can pass these XMLEvent objects to other processes or store them in lists, arrays, and maps.

 

You can subclass XMLEvent, creating your own specialized events as needed. You can modify the incoming event stream by adding or removing events, which is more flexible than the cursor API.

 

To use StAX to read documents, create an XML event reader on your file input stream. Check that events are still available with the hasNext() method and read each event using the nextEvent() method. The nextEvent() method will return a specific type of XMLEvent that corresponds to the start and stop elements, attributes, and value data in the XML file. Remember to close your readers and file streams when you’re finished with those objects.

 

You can invoke the example application like this, using the patients.xml file as your <xmlFile> argument:

java org.java9recipes.blog20.recipe20_2.DocReader <xmlFile>

 

Transforming XML

Transforming XML

Problem You want to convert an XML document to another format, for example to HTML.

Solution

Use the javax.xml.transform package to transform an XML document to another document format. The following code demonstrates how to read a source document, apply an Extensible Stylesheet Language (XSL) transform file, and produce the transformed, new document.

 

Use the sample code from the org.java9recipes.blog20.recipe20_3.TransformXml class to read the patients.xml file and create a patients.html file. The following snippet shows the important pieces of this class:

import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.Transformer; import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; ...
public void run(String xmlFile, String xslFile, String outputFile) throws FileNotFoundException, TransformerConfigurationException, TransformerException {
InputStream xslInputStream = new FileInputStream(xslFile); Source xslSource = new StreamSource(xslInputStream); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(xslSource); InputStream xmlInputStream = new FileInputStream(xmlFile); StreamSource in = new StreamSource(xmlInputStream); StreamResult out = new StreamResult(outputFile); transformer.transform(in, out); ...
}

 

How It Works

javax.xml.transform package

The javax.xml.transform package contains all the classes you need to transform an XML document into any other document type. The most common use case is to convert data-oriented XML documents into user-readable HTML documents.

 

Transforming from one document type to another requires three files:

  • An XML source document
  • An XSL transformation document that maps XML elements to the new document elements

 

A target output file

XML source document

The XML source document is, of course, your source data file. It will most often contain data-oriented content that is easy to parse programmatically. However, people don’t easily read XML files, especially complex, data-rich files. Instead, people are much more comfortable reading properly rendered HTML documents.

 

The XSL transformation document specifies how an XML document should be transformed into a different format. An XSL file will usually contain an HTML template that specifies dynamic fields that will hold the extracted contents of a source XML file.

 

In this example’s source code, you’ll find two source documents:

blog20/recipe20_3/patients.xml
blog20/recipe20_3/patients.xsl
The patients.xml file is short and contains the following data:
<?xml version="1.0" encoding="UTF-8"?>
<patients>
<patient id="1">
<name>John Smith</name>
<diagnosis>Common Cold</diagnosis>
</patient>
<patient id="2">
<name>Thesis</name>
<diagnosis>Broken ankle</diagnosis>
</patient>
<patient id="3">
<name>Jack Brown</name>
<diagnosis>Food allergy</diagnosis>
</patient>
</patients>

 

The patients.xml file defines a root element called patients. It has three nested patient elements.

  • The patient elements contain three pieces of data:
  • Patient identifier, provided as the id attribute of the patient element
  • Patient name, provided as the name subelement
  • Patient diagnosis, provided as the diagnosis subelement

 

The transformation XSL document (patients.xsl) is quite small as well, and it simply maps the patient data to a more user-readable HTML format using XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head>
<title>Patients</title>
</head>
<body>
<table border="1">
<tr>
<th>Id</th>
<th>Name</th>
<th>Diagnosis</th>
</tr>
<xsl:for-each select="patients/patient">
<tr>
<td>
<xsl:value-of select="@id"/>
</td>
<td>
<xsl:value-of select="name"/>
</td>
<td>
<xsl:value-of select="diagnosis"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

 

Using this style sheet, the sample code transforms the XML into an HTML table containing all the patients and their data.

The process for using this XSL file to convert the XML to an HTML file is straightforward, but every step can be enhanced with additional error checking and processing. For this example, refer to the previous code in the solution section.

 

The most basic transformation steps are these:

  • \1.\ Read the XSL document into your Java application as a Source object.
  • \2.\ Create a Transformer instance and provide your XSL Source instance for it to use during its operation.
  • \3.\ Create a SourceStream that represents the source XML contents.
  • \4.\ Create a StreamResult instance for your output document, which is an HTML file in this case.
  • \5.\ Use the Transformer object’s transform() method to perform the conversion.
  • \6.\ Close all the relevant streams and file instances, as needed.

 

If you choose to execute the sample code, you should invoke it in the following way, using patients.

xml, patients.xsl, and patients.html as arguments:

java org.java9recipes.blog20.recipe20_3.TransformXml <xmlFile><xslFile><outputFile>

 

Validating XML

Validating XML

Problem You want to confirm that your XML is valid—that it conforms to a known document definition or schema.

Solution

Validate that your XML conforms to a specific schema by using the javax.xml.validation package. The following code snippet from org.java9recipes.blog20.recipe20_4.ValidateXml demonstrates how to validate against an XML schema file:

import java.io.File;
import java.io.IOException;
import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.xml.sax.SAXException;
...
public void run(String xmlFile, String validationFile) { boolean valid = true;
SchemaFactory sFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
Schema schema = sFactory.newSchema(new File(validationFile)); Validator validator = schema.newValidator();
Source source = new StreamSource(new File(xmlFile)); validator.validate(source);
} catch (SAXException | IOException | IllegalArgumentException ex) { valid = false;
}
System.out.printf("XML file is %s.\n", valid ? "valid" : "invalid");
}
...

 

How It Works

XML schema

When utilizing XML, it is important to validate it to ensure that the correct syntax is in place, and to ensure that an XML document is an instance of the specified XML schema. The validation process involves comparing the schema and the XML document to find any discrepancies.

 

The javax.xml.validation package provides all the classes needed to reliably validate an XML file against a variety of schemas. The most common schemas that you will use for XML validation are defined as constant URIs within the XMLConstants class:

 

XMLConstants.W3C_XML_SCHEMA_NS_URI

XMLConstants.RELAXNG_NS_URI

 

Begin by creating a SchemaFactory for a specific type of schema definition. A SchemaFactory knows how to parse a particular schema type and prepares it for validation. Use the SchemaFactory instance to create a Schema object. The Schema object is an in-memory representation of the schema definition grammar.

 

You can use the Schema instance to retrieve a Validator instance that understands this grammar. Finally, use the validate() method to check your XML. The method call will generate several exceptions if anything goes wrong during the validation. Otherwise, the validate() method returns quietly, and you can continue to use the XML file.

 

Note The XML Schema was the first to receive “Recommendation” status from the World Wide Web consortium (W3C) in 2001. Competing schemas have since become available. One competing schema is the Regular Language for XML Next Generation (RELAX NG) schema. RELAX NG may be a simpler schema and its specification also defines a non-XML, compact syntax. This recipe’s example uses the XML schema.

 

Run the example code using the following command-line syntax, preferably with the sample .xml file and validation files provided as resources/patients.xml and patients.xsl, respectively:

java org.java9recipes.blog20.recipe20_4.ValidateXml <xmlFile><validationFile>

 

Creating Java Bindings for an XML Schema

Java Bindings for an XML Schema

Problem You want to generate a set of Java classes (Java bindings) that represent the objects in an XML schema.

 

Solution

The JDK provides a tool that can turn schema documents into representative Java class files. Use the <JDK_HOME>/bin/xjc command-line tool to generate Java bindings for your XML schemas. To create the Java classes for the patients.xsd file from Recipe 20-3, you could issue the following command from within a console: xjc –p org.java9recipes.blog20.recipe20_5 patients.xsd

 

This command will process the patients.xsd file and create all the classes needed to process an XML file that validates with this schema. For this example, the patients.xsd file looks like the following:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="patients">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="patient" type="Patient"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="Patient">
<xs:sequence>
<xs:element name="name" type="xs:string"/> <xs:element name="diagnosis" type="xs:string"/> </xs:sequence>
<xs:attribute name="id" type="xs:integer" use="required"/>
</xs:complexType>
</xs:schema>
Executed on the previous xsd file, the xjc command creates the following files in the org.
java9recipes.blog20.recipe20_5 package:
ObjectFactory.java
Patients.java
Patient.java

 

How It Works

Java binding files

The JDK includes the <JDK_HOME>/bin/xjc utility. The xjc utility is a command-line application that creates Java bindings from schema files. The source schema files can be several types, including XML Schemas, RELAX NG, and others.

 

The xjc command has several options for performing its work. Some of the most common options specify the source schema file, the package of the generated Java binding files, and the output directory that will receive the Java binding files.

 

You can get detailed descriptions of all the command-line options by using the tools’ –help option: xjc –help

 

A Java binding contains annotated fields that correspond to the fields defined in the XML Schema file. These annotations mark the root element of the schema file and all other subelements. This is useful during the next step of XML processing, which involves either unmarshalling or marshalling these bindings.

 

Unmarshalling XML to a Java Object

Unmarshalling XML to a Java Object

Problem: You want to unmarshall an XML file and create its corresponding Java object tree.

Solution

Unmarshalling is the process of converting a data format, in this case XML, into a memory representation of the object so that can be used to perform a task. JAXB provides an unmarshalling service that parses an XML file and generates the Java objects from the bindings.

 

The following code can read the file patients.xml from the org.java9recipes.blog20.recipe20-6 package to create a Patients root object and its list of Patient objects:

public void run(String xmlFile, String context) throws JAXBException, FileNotFoundException {
JAXBContext jc = JAXBContext.newInstance(context); Unmarshaller u = jc.createUnmarshaller(); FileInputStream fis = new FileInputStream(xmlFile); Patients patients = (Patients)u.unmarshal(fis); for (Patient p: patients.getPatient()) {
System.out.printf("ID: %s\n", p.getId());
System.out.printf("NAME: %s\n", p.getName());
System.out.printf("DIAGNOSIS: %s\n\n", p.getDiagnosis());
}
}

 

If you run the sample code on the blog20/recipe20_6/patients.xml file and use the org. java9recipes.blog20 context, the application will print the following to the console as it iterates over the Patient object list:

ID: 1

NAME: John Smith

DIAGNOSIS: Common Cold

ID: 2

NAME: Thesis

DIAGNOSIS: Broken ankle

ID: 3

NAME: Jack Brown

DIAGNOSIS: Food allergy

Note The previous output comes directly from instances of the Java Patient class that was created from XML representations. The code does not print the contents of the XML file directly. Instead, it prints the contents of the Java bindings after the XML has been marshalled into appropriate Java binding instances.

 

How It Works

 well-formed and valid XML file

Unmarshalling an XML file into its Java object representation has at least two criteria:

  • A well-formed and valid XML file
  • A set of corresponding Java bindings

 

The Java bindings don’t have to be autogenerated from the xjc command. Once you’ve gained some experience with Java bindings and the annotation features, you may prefer to create and control all aspects of Java binding by handcrafting your Java bindings. Whatever your preference, Java’s unmarshalling service utilizes the bindings and their annotations to map XML objects to a target Java object and to map XML elements to target object fields.

 

Execute the example application for this recipe using this syntax, substituting patients.xml and org.

  • java9recipes.blog20.recipe20_6 for the respective parameters:
  • java org.java9recipes.blog20.recipe20_6.UnmarshalPatients <xmlfile><context>

 

Building an XML Document with JAXB

Building an XML Document with JAXB

Problem You need to write an object’s data to an XML representation.

Solution

Assuming you have created Java binding files for your XML schema as described in Recipe 20-4, you use a JAXBContext instance to create a Marshaller object. You then use the Marshaller object to serialize your Java object tree to an XML document. The following code demonstrates this:

public void run(String xmlFile, String context) throws JAXBException, FileNotFoundException {
Patients patients = new Patients();
List<Patient> patientList = patients.getPatient();
Patient p = new Patient();
p.setId(BigInteger.valueOf(1));
p.setName("John Doe");
p.setDiagnosis("Schizophrenia");
patientList.add(p);
JAXBContext jc = JAXBContext.newInstance(context); Marshaller m = jc.createMarshaller(); m.marshal(patients, new FileOutputStream(xmlFile));
}

 

The previous code produces an unformatted but well-formed and valid XML document. For readability, the XML document is formatted here:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <patients>
<patient id="1">
<name>John Doe</name>
<diagnosis>Schizophrenia</diagnosis>
</patient>
</patients>

 

Note  The getPatient() method in the previous code returns a list of patient objects instead of a single patient. This is a naming oddity of the JAXB code generation from the XSD schema in this example.

 

How It Works

JAXB annotations

A Marshaller object understands JAXB annotations. As it processes classes, it uses the JAXB annotations to provide the context needed to create the object tree in XML.

You can run the previous code from the org.java9recipes.blog.recipe.MarshalPatients application using the following command line:

java org.java9recipes.blog.recipe.MarshalPatients <xmlfile><context>

 

The context argument refers to the package of the Java classes that you will marshal. In the previous example, because the code marshals a Patients object tree, the correct context is the package name of the Patients class. In this case, the context is org.java9recipes.blog.

 

Parsing an XML Catalog

 Parsing an XML Catalog

Problem  You need to parse an XML catalog in order to direct remote external references to a local catalog for security purposes, or some other need.

Solution

Utilize the standard XML Catalog API that is part of Java 9. In this example, a local catalog is read and parsed using the API.

public static void main(String[] args) {
// Create a CatalogFeatures object
CatalogFeatures defaults = CatalogFeatures.defaults();
Resolve using properties
System.setProperty("javax.xml.catalog.files", "catalog.xml");
Resolve by passing
Catalog catalog = CatalogManager.catalog(defaults, "catalog.xml", "catalog-alt.xml");
Use CatalogFeatures to specify catalog files and/or additional features
CatalogFeatures catalogFeatures = CatalogFeatures.builder()
.with(Feature.FILES, "catalog.xml")
.with(Feature.RESOLVE, "ignore")
.build();
Stream and filter to find the catalog matching your specification Optional<Catalog> cat = catalog.catalogs()
.filter((c)->c.matchURI("calstblx.dtd") != null)
.findFirst();
Do something with catalog
}

 

How It Works

CatalogManager

The JDK has historically had an XML resolver as part of its core. However, this resolver was private and utilized only by the JDK. As time moved on, the need to implement a public XML resolver became evident, so the private resolver was revamped into a new public API.

 

The API allows one to manage the creation of XML Catalogs and resolvers, it implements the OASIS XML Catalogs 1.1 specification, and it implements the existing JAXP interfaces.

 

There are a number of key interfaces and classes that comprise the Catalog API. The Catalog interface can be used to represent an entity catalog. A CatalogManager is used to parse a Catalog by passing a CatalogFeatures configuration object, along with a variable argument containing the paths to the XML catalog files.

 

It can also be used to generate CatalogResolvers. It is also possible to pass paths to one or many catalog files by specifying the “javax.xml.catalog.files” property, as seen in the example. System.setProperty("javax.xml.catalog.files", "catalog.xml");

 

The CatalogFeatures object holds a number of properties and features, and a default implementation can be obtained calling upon the CatalogFeatures.defaults() method. To specify different values for a CatalogFeatures object, you can utilize the builder pattern to indicate values for each of the different features.

 

For more information on CatalogFeatures, refer to the JavaDoc

(http://download.java.net/java/ jdk9/docs/api/javax/xml/catalog/CatalogFeatures.html).

 

The Catalog.catalogs() method can be called upon to generate a Stream of alternative Catalogs using the nextCatalog entries within the current catalog. This parsing can used to match the entries that reside within the XML catalog.

 

The XML Catalog API is a nice addition to the JDK, making it easy to utilize local catalogs, rather than remote, when needed. Java has long had a resolver for catalogs, but it was not accessible for use outside of the internals of the JDK. The new API is a rejuvenated form of the older private API, and it is fully compliant with the OASIS XML Catalogs 1.1 specification.

 

Working with JSON

Working with JSON

Problem You are interested in working with JSON in your Java SE 9 application.

Solution

Add the JSON-P API as a dependency to your Java SE 9 application. There are a couple of options for adding the dependency. One can download the JAR and place it into the CLASSPATH, or if using a build tool such as Maven, simply add the coordinates of the project repository. The following lines are excerpted from the POM file (Project Object Module for Maven), indicating how to add the dependency.

<dependencies>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0.4</version>
</dependency>
...
</dependencies>


How It Works

The JavaScript Object Notation (JSON-P) API was added to the Java Enterprise platform with the release of Java EE 7. JSON-P, also referred to as “JSON Processing,” has become the standard way to build JSON objects using Java. Since Java 9 does not come bundled with a JSON building and parsing API, one must pull in the required dependencies to utilize the standardized JSON-P API.

 

JSON-P is part of Java EE, but support has been left out of Java SE at this point. As such, it is easy to include the API by adding the downloaded JAR files to the CLASSPATH, or adding the Maven coordinates to the project POM file. In the solution, I covered how to utilize the Maven coordinates. However, be sure to update the version accordingly.

 

Building a JSON Object

Building a JSON Object

Problem You would like to build a JSON object within your Java application.

Solution

Utilize the JSON-P API to build a JSON object. In the following code, a JSON object pertaining to a blog is built.

public JsonObject buildBlogObject() {
JsonBuilderFactory factory = Json.createBuilderFactory(null); JsonObject obj = factory.createObjectBuilder()
.add("title", "Java 9")
.add("author", "Thesis Scientist")
.add("projectCoordinator", "Bill gates")
.add("editor", "Kim Jobs")
.build();
return obj;
}

 

How It Works

The JSON-P API includes a helper class that can be used to create JSON objects using the builder pattern. Using the JsonObjectBuilder, JSON objects can be built using a series of method calls, each building upon each other—hence, the builder pattern. Once the JSON object has been built, the JsonObjectBuilder. build() method can be called to return a JsonObject.

 

In the example to this recipe, you construct a JSON object that provides details regarding a blog. The JsonObjectBuilder.beginObject() method is used to denote that a new object is being created.

 

The add method is used to add more a name/value properties, much like that of a Map. Therefore, the following line adds a property named title with a value of “Java 9 Recipes”:

.add("title", "Java 9")

 

Objects can be embedded inside of each other, creating a hierarchy of subsections within one JsonObject. For example, after the first call to add(), another object can be embedded inside the initial JsonObject by calling JsonBuilderFactory.createObjectBuilder() as the value to an add() operation, and passing the name of the embedded object.

 

Embedded objects can also contain properties; so to add properties to the embedded object, call the add() method within the embedded object. JsonObjects can embody as many embedded objects as needed.

 

The following lines of code demonstrate the beginning and end of an embedded object definition if we were to modify the sources in the example to break down the author by first and last name:

add("author", factory.createObjectBuilder()
.add("first", "Thesis")
.add("last", "Scientist"))
.add("projectCoordinator", "Bill Gates")

It is also possible that a JsonObject may have an array of related subobjects. To add an array of subobjects, call the JsonBuilderFactory.createArrayBuilder() method, passing the name of the array as an argument. Arrays can consist of objects, and even hierarchies of objects, arrays, and so forth.

 

Once a JsonObject has been created, it can be passed to a client. WebSockets work well for passing JsonObjects back to a client, but there is a bevy of different technologies available for communicating with JSON.

 

Writing a JSON Object to File

Writing a JSON Object to File

 

Problem: You’ve generated or parsed a JSON object, and you would like to store it on disk in file format.

Solution

Utilize the JSON-P API to build a JSON object, and then store it to the file system. The JsonWriter class makes it possible to create a file on disk, and then write the JSON to that file. In the following example, the JsonObject that was generated in Recipe 20-10 is written to disk using this technique.

public static void writeJson() {
JsonObject jsonObject = buildBlogObject();
try (javax.json.JsonWriter jsonWriter = Json.createWriter(new FileWriter("Blog.json"))) { jsonWriter.writeObject(jsonObject);
} catch (IOException ex) { System.out.println(ex);
}
}

 

How It Works

The JsonWriter class can be utilized to write a JsonObject to a Java writer object. A JsonWriter is instantiated by passing a Writer object as an argument to the Json.createWriter() method. After that JsonWriter has been created, the JsonWriter.writeObject() method can be invoked, passing the JsonObject that is to be written.

Once the JsonObject has been written, the JsonWriter can be closed by calling its close() method. These are the only steps that are necessary for writing a JSON object to a Java Writer class type.

 

Parsing a JSON Object

Parsing a JSON Object

Problem: The application you’ve created requires the ability to read a JSON object and parse it accordingly.

Solution

Utilize a JsonReader object to read a JSON object, and then make use of a JsonParser object to perform actions against the JSON data. The following example demonstrates how to read a file from disk, and then parse it to display some content.

 style="margin: 0px; width: 975px; height: 146px;">public void parseObject() {
Reader fileReader = new InputStreamReader(getClass().getResourceAsStream("Blog.json")); JsonParser parser = Json.createParser(fileReader); while (parser.hasNext()) {
Event ev = parser.next();
System.out.println(ev);
if (ev.equals(Event.VALUE_STRING)) {
System.out.println(parser.getString());
}
}
}

 

In the example, the Json file named Blog.json is read and parsed. When a VALUE_STRING event is encountered during the parsing, the String is printed. Each encountered event is also printed. The following output is the result:

START_OBJECT

KEY_NAME

VALUE_STRING

Java 9

KEY_NAME

VALUE_STRING

Thesis Scientist

KEY_NAME

VALUE_STRING

Bill gates

KEY_NAME

VALUE_STRING

jobs

END_OBJECT

 

How It Works

JSON object

Once a JSON object has been persisted to disk, it will later need to be read back in for utilization. The JsonReader object takes care of this task. To create a JsonReader object, call the Json.createReader() method, passing either an InputStream or Reader object. Once a JsonReader object has been created, it can produce a JsonObject by calling its readObject method.

 

In order to perform some tasks, a JSON object must be parsed to find only the content that is desired and useful for the current task. Utilizing a JSON parser can make jobs such as these easier, as a parser is able to break the object down into pieces so that each different piece can be examined as needed, to produce the desired result.

 

The javax.json.Json class contains a static factory method, createParser(), that accepts a bevy of input and returns an iterable JsonParser.

 

Once a JsonParser has been created, it can be made into an Iterator of Event objects. Each Event correlates to a different structure within the JSON object. For instance, when the JSON object is created, a START_OBJECT event occurs, adding a name/value pair will trigger both a KEY_NAME and VALUE_STRING event.

 

These events can be utilized to obtain the desired information from a JSON object. In the example, the event names are merely printed to a server log. However, in a real-life application, a conditional would most likely test each iteration to find a particular event and then perform some processing. Tablelists the different JSON events, along a description of when each occurs.

 

JSON Object Events

START_OBJECT Start of an object.
END_OBJECT End of an object.
START_ARRAY Start of an array.
END_ARRAY End of an array.
KEY_NAME Name of a key.
VALUE_STRING Value of a name/value pair in String format.
VALUE_NUMBER Value of a name/value pair in numeric format.
VALUE_TRUE Value of a name/value pair in Boolean format.
VALUE_FALSE Value of a name/value pair in Boolean format.
VALUE_NULL Value of a name/value pair as NULL.

 

Networking

Networking

Today, writing an application that does not communicate over the Internet in some fashion is rare. From sending data to another machine, to scraping information off remote web pages, networking plays an integral part in today’s computing world.

 

Java makes it easy to communicate over a network using the New I/O (NIO) and more new I/O features for the Java platform (NIO.2) APIs. Java SE 7 included a few new features, enabling easier multicasting among other things.

 

With the addition of these new features, the Java platform contains a plethora of programming interfaces to help accomplish network tasks. Java 9 introduces the new HTTP/2 client, which provides a simple and concise API, as well as performance improvements over the older HTTP/1.1 client.

 

This blog does not attempt to cover every networking feature that is part of the Java language, as the topic is quite large. However, it does provide a handful of recipes that are the most useful to a broad base of developers.

 

You learn about a few of the standard networking concepts, such as sockets, as well as some newer concepts that were introduced with the latest release of the Java language. If you find this blog interesting and want to learn more about Java networking, you can find lots of resources online.

 

Perhaps the best place to go for learning more is the Oracle documentation at http://download.oracle.com/javase/ tutorial/networking/index.html.

 

Listening for Connections on the Server

Listening for Connections on the Server

Problem You want to create a server application that will listen for connections from a remote client.

 

Solution

Set up a server-side application that makes use of java.net.ServerSocket to listen for requests on a specified port. The following Java class is representative of one that would be deployed onto a server, and it listens for incoming requests on port 1234. When a request is received, the incoming message is printed to the command line and a response is sent back to the client.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String a[]) {
final int httpd = 1234;
ServerSocket ssock = null;
try {
ssock = new ServerSocket(httpd); System.out.println("have opened port 1234 locally");
Socket sock = ssock.accept(); System.out.println("client has made socket connection");
communicateWithClient(sock);
System.out.println("closing socket");
} catch (Exception e) { System.out.println(e); } finally {
try{
ssock.close();
} catch (IOException ex) { System.out.println(ex);
}
}
}
public static void communicateWithClient(Socket socket) { BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(
new InputStreamReader(socket.getInputStream())); out = new PrintWriter(
socket.getOutputStream(), true);
String s = null;
out.println("Server received communication!"); while ((s = in.readLine()) != null) {
System.out.println("received from client: " + s);
out.flush();
break;
}
} catch (Exception e) { e.printStackTrace();
} finally {
try {
in.close();
out.close();
} catch (IOException ex) { ex.printStackTrace();
}
}
}
}

Executing this program will simply print “have opened port 1234 locally,” but executing it along with the client that is built in Recipe will result in the following output from the SocketServer:

  • have opened port 1234 locally
  • client has made socket connection
  • received from client: Here is a test.
  • closing socket

 

Note To run the two recipes so that they work with each other, first start the SocketServer program so that the client can create a socket using the port that is opened in the server program. After the SocketServer starts, initiate the SocketClient program to see the two work together.

 

Caution This SocketServer program opens a port on your machine (1234). Be sure that you have a firewall set running on your machine; otherwise, you will be opening port 1234 to everyone. This could result in your machine being attacked. Open ports create vulnerabilities for attackers to break into machines, kind of like leaving a door in your house open.

 

Note that the example in this recipe has a minimal attack profile because the server is run through only one pass and will print only a single message from the client before the session is closed.

 

How It Works

SocketServer program

Server applications can be used to enable work to be performed on a server via direct communication from one or more client applications. Client applications normally communicate to the server application, send messages or data to the server for processing, and then disconnect.

 

The server application typically listens for client applications, and then performs some processing against a client request once a connection is received and accepted. In order for a client application to connect to a server application, the server application must be listening for connections and then processing the connection data somehow.

 

You cannot simply run a client against any given host and port number combination because doing so would likely result in a refused connection error. The server-side application must do three things: open a port, accept and establish client connections, and then communicate with the client connection in some way. In the solution to this recipe, the SocketServer class does all three.

 

Starting with the main() method, the class begins by opening a new socket on port 1234. This is done by creating a new instance of ServerSocket and passing a port number to it. The port number must not conflict with any other port that is currently in use on the server.

 

It is important to note that ports below 1024 are usually reserved for operating system use, so choose a port number above that range. If you attempt to open a port that is already in use, the ServerSocket will not successfully be created, and the program will fail.

 

Next, the ServerSocket object’s accept() method is called, returning a new Socket object. Calling the accept() method will do nothing until a client attempts to connect to the server program on the port that has been set up. The accept() method will wait idly until a connection is requested and then it will return the new Socket object bound to the port that was set up on the ServerSocket.

 

This socket also contains the remote port and hostname of the client attempting the connection, so it contains the information on two endpoints and uniquely identifies the Transmission Control Protocol (TCP) connection.

 

At this point, the server program can communicate with the client program, and it does so using the PrintWriter and BufferedReader objects. In the solution to this recipe, the communicateWithClient() method contains all the code necessary to accept messages from the client program, sends messages back to the client, and then returns control to the main() method that closes the ServerSocket.

 

A new BufferedReader object can be created by generating a new InputStreamReader instance using the socket’s input stream. Similarly, a new PrintWriter object can be created using the socket’s output stream. Notice that this code must be wrapped in a try-catch block in case these objects are not successfully created.

in = new BufferedReader(
new InputStreamReader(socket.getInputStream())); out = new PrintWriter(
socket.getOutputStream(), true);
Once these objects have been successfully created, the server can communicate with the client. It uses a loop to do so, reading from the BufferedReader object (the client input stream) and sending messages back to the client using the PrintWriter object. In the solution to this recipe, the server closes the connection by issuing a break, which causes the loop to end. Control then returns to the main() method.
out.println("Server received communication!"); while ((s = in.readLine()) != null) {
System.out.println("received from client: " + s);
out.flush();
break;
}

 

In a real-life server program, the server would most likely listen endlessly without using a break to end communication. To handle multiple concurrent clients, each client connection would spawn a separate Thread to handle communication. The server would do something useful with the client communication as well.

 

In the case of an HTML server, it would send back an HTML message to the client. On an SMTP server, the client would send an e-mail message to the server, and the server would then process the e-mail and send it. Socket communication is used for just about any TCP transmission, and both the client and servers create new sockets to perform a successful communication.

 

Defining a Network Connection to a Server

Defining a Network Connection to a Server

Problem You need to establish a connection to a remote server.

Solution

Create a Socket connection to the remote server using its name and port number where the server is listening for incoming client requests. The following example class creates a Socket connection to a remote server. The code then sends a textual message to the server and receives a response. In the example, the server that the client is attempting to contact is named server-name and the port number is 1234.

 

Tip To create a connection to a local program running on the client machine, set the server-name equal to 127.0.0.1. This is done within the source listing for this recipe. Usually local connections such as this are used for testing purposes only.

public class SocketClient {
public static Socket socket = null;
public static PrintWriter out;
public static BufferedReader in;
public static void main(String[] args) {
createConnection("127.0.0.1", 1234);
}
public static void createConnection(String host, int port) {
try {
//Create socket connection
socket = new Socket(host, port);
// Obtain a handle on the socket output
out = new PrintWriter(socket.getOutputStream(), true);
// Obtain a handle on the socket input
in = new BufferedReader(new InputStreamReader( socket.getInputStream()));
testConnection();
System.out.println("Closing the connection...");
out.flush();
out.close();
in.close();
socket.close();
System.exit(0);
} catch (UnknownHostException e) { System.out.println(e); System.exit(1);
} catch (IOException e) { System.out.println(e); System.exit(1);
}
}
public static void testConnection() {
String serverResponse = null;
if (socket != null && in != null && out != null) { System.out.println("Successfully connected, now testing...");
try {
Send data to server out.println("Here is a test.");
Receive data from server while((serverResponse = in.readLine()) != null) System.out.println(serverResponse);
} catch (IOException e) { System.out.println(e); System.exit(1);
}
}
}
}

If you’re testing this client against a server that successfully accepts the request, you will see the following result:

Successfully connected, now testing...

 

Note This program will do nothing on its own. To create a server-side socket application that will accept this connection for a complete test, see Recipe 21-1. If you attempt to run this class without specifying a server host that is listening on the provided port, you will receive this exception: http://java.net.ConnectException: Connection refused.

 

How It Works

client/server connection

 

Every client/server connection occurs via a socket, which is an endpoint in a communication link between two different programs. Sockets have port numbers assigned to them, which act as an identifier for the TCP/ IP layer to use when attempting a connection. A server program that accepts requests from client machines typically listens for new connections on a specified port number.

 

When a client wants to make a request to the server, it creates a new socket utilizing the hostname of the server and the port on which the server is listening and attempts to establish a connection with that socket. If the server accepts the socket, then the connection is successful.

 

This recipe discusses the client side of the socket connection, so we will not go into the details of what occurs on the server side at this time. The example class in the solution to this recipe is representative of how a client-side program attempts and establishes connections to a server-side program. In this recipe, a method named createConnection() performs the actual connection.

 

It accepts a server hostname and port number, which will be used to create the socket. Within the createConnection() method, the server hostname and port number are passed to the Socket class constructor, creating a new Socket object. Next, a PrintWriter object is created using the Socket object’s output stream, and a BufferedReader object is created using the Socket object’s input stream.

//Create socket connection
socket = new Socket(host, port);
// Obtain a handle on the socket output
out = new PrintWriter(socket.getOutputStream(), true);
// Obtain a handle on the socket input
in = new BufferedReader(new InputStreamReader( socket.getInputStream()));

 

After creating the socket and obtaining the socket’s output stream and input stream, the client can write to the PrintWriter in order to send data to the server. Similarly, to receive a response from the server, the client reads from the BufferedReader object. The testConnection() method is used to simulate a conversation between the client and the server program using the newly created socket.

 

To do this, the socket, in, and out variables are checked to ensure that they are not equal to null. If they are not equal to null, the client attempts to send a message to the server by sending a message to the output stream using out.println("Here is a test.").

 

A loop is then created to listen for a response from the server by calling the in.readLine() method until nothing else is received. It then prints the messages that are received.

if (socket != null && in != null && out != null) { System.out.println("Successfully connected, now testing...");
try {
Send data to server out.println("Here is a test.");
Receive data from server while((serverResponse = in.readLine()) != null)
System.out.println(serverResponse); } catch (IOException e) {
System.out.println(e);
System.exit(1);
}
}

 

The java.net.Socket class is true to the nature of the Java programming language. It enables developers to code against a platform-independent API in order to communicate with network protocols that are specific to different platforms. It abstracts the details of each platform from the developer and provides a straightforward and consistent implementation for enabling client/server communications.

 

Bypassing TCP for InfiniBand to Gain Performance Boosts

Sockets Direct Protocol

 

Problem

Your application, which is deployed on Linux or Solaris, needs to move data very quickly and efficiently, and you need to remove any bottlenecks that could slow things down.

 

Solution

Use the Sockets Direct Protocol (SDP) to bypass TCP, a possible bottleneck in the process. In order to do this, create an SDP configuration file and set the system property to specify the configuration file location.

 

Note The SDP was added to the Java SE 7 release for applications deployed in the Solaris or Linux operating systems only. SDP was developed to support stream connections over InfiniBand fabric, which Solaris and Linux both support. The Java SE 7 release supports the 1.4.2 and 1.5 versions of OpenFabrics Enterprise Distribution (OFED).

 

This configuration file is an example of one that could be used to enable the use of SDP:

  • Use SDP when binding to 192.0.2.1 bind 192.0.2.1 *
  • Use SDP when connecting to all application services on 192.0.2.*
  • connect 192.0.2.0/24 1024-*
  • Use SDP when connecting to the HTTP server or a database on myserver.org connect myserver.org 8080
  • connect myserver.org 1521

 

The following excerpt is taken from the terminal. It is the execution of a Java application named

SDPExample, specifying the SDP system property:

% java -Dcom.sun.sdp.conf=sdp.conf -http://Djava.net.preferIPv4Stack=true SDPExample

 

How It Works

Sometimes it is essential that an application be as fast as possible while performing network communications. Transfers over TCP can sometimes decrease performance, so bypassing TCP can be beneficial. Since the release of Java SE 7, support for the SDP has been included for certain platforms.

 

The SDP supports stream connections over InfiniBand fabric. Both Solaris and Linux include support for InfiniBand, so SDP can be useful on those platforms.

 

You don’t need to make any programmatic changes to your applications in order to support SDP. The only differences when using SDP are that you must create an SDP configuration file, and the JVM must be told to use the protocol by passing a flag when running the application.

 

Because the implementation is transparent, applications can be written for any platform, and those that support SDP can merely include the configuration file and bypass TCP.

 

The SDP configuration file is a text file that is composed of bind and connect rules. A bind rule indicates that the SDP protocol transport should be used when a TCP socket binds to an address and port that match the given rule. A connect rule indicates that the SDP protocol transport should be used when an unbound TCP socket attempts to connect to an address and port that match the given rule.

 

The rule begins with either the bind or connect keyword indicating the rule type, followed by the hostname or IP address, and a single port number or range of port numbers. Per the online documentation, a rule has the following form:

 

("bind"|"connect")1*LWSP-char(hostname|ipaddress)["/"prefix])1*LWSP-char("*"|port)&#x00C9; ["-"("*"|port)]

 

In the rule format shown here, 1*LWSP-char means that any number of tabs or spaces can separate the tokens. Anything contained within square brackets indicates optional text, and quotes indicate literal text. In the solution to the recipe, the first rule indicates that SDP can be used for any port (* indicates a wildcard) on the IP address of 192.0.2.1, a local address.

 

Each local address that is assigned to an InfiniBand adaptor should be specified with a bind rule in the configuration file. The first connect rule in the configuration file specifies that SDP should be used whenever connecting to the IP address of 192.0.2.*, using a port of 1024 or greater.

connect 192.0.2.0/24 1024-*

 

This rule uses some special syntax that should be noted. Specifically, the /24 suffix of the IP address indicates that the first 24 bits of the 32-bit IP address should match a specified address. Because each portion of an IP address is eight bits, this means that the 192.0.2 should match exactly, and the final byte can be any value.

 

The dash -* within the port identifier specifies the range of 1024 or greater because the wildcard character is used. The third and fourth connect rules in the configuration file specify that SDP should be used with the hostname of myserver.org and a port of 8080 or 1521.

 

Next, in order to enable SDP, the –Dcom.sun.sdp.conf property should be specified along with the location to the SDP configuration file when starting the application. Also, notice in the solution that the property -http://Djava.net.preferIPv4Stack is set to true. This indicates that the IPv4 address format will be used. This is necessary because IPv4 addresses mapped to IPv6 are currently not available in the Solaris OS or under Linux.

 

Although the SDP is available only with Solaris or Linux, it is a nice addition to the JDK for users of those platforms. Any performance booster is always viewed as a bonus, and the solution to this recipe certainly falls into that category.

 

Broadcasting to a Group of Recipients

Problem: You want to broadcast datagrams to zero or more hosts identified by a single address.

 

Solution

Make use of datagram multicasting using the DatagramChannel class. The DatagramChannel class enables more than one client to connect to a group and listen for datagrams that have been broadcasted from a server. The following sets of code demonstrate this technique using a client/server approach. The class demonstrates a multicast client.

package org.java9recipes.blog21.recipe21_4;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.MembershipKey;
public class MulticastClient {
public MulticastClient() {
}
public static void main(String[] args) {
try {
Obtain Supported network Interface NetworkInterface networkInterface = null;
java.util.Enumeration<NetworkInterface> enumNI = NetworkInterface.getNetworkInterfaces();
java.util.Enumeration<InetAddress> enumIA;
NetworkInterface ni; InetAddress ia;
ILOOP:
while (enumNI.hasMoreElements()) {
ni = enumNI.nextElement(); enumIA = ni.getInetAddresses(); while (enumIA.hasMoreElements()) {
ia = enumIA.nextElement();
if (ni.isUp() && ni.supportsMulticast()
!ni.isVirtual() && !ni.isLoopback()
!ia.isSiteLocalAddress()) { networkInterface = ni;
break ILOOP;
}
}
}
Address within range int port = 5239;
InetAddress group = InetAddress.getByName("226.18.84.25");
final DatagramChannel client = DatagramChannel.open(StandardProtocolFamily.INET);
client.setOption(StandardSocketOptions.SO_REUSEADDR, true);
client.bind(new InetSocketAddress(port));
client.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);
System.out.println("Joining group: " + group + " with network interface " + networkInterface); // Multicasting join
MembershipKey key = client.join(group, networkInterface); client.open();
// receive message as a client
final ByteBuffer buffer = ByteBuffer.allocateDirect(4096); buffer.clear();
System.out.println("Waiting to receive message");
Configure client to be passive and non.blocking
client.configureBlocking(false);
client.receive(buffer); System.out.println("Client Received Message:"); buffer.flip();
byte[] arr = new byte[buffer.remaining()]; buffer.get(arr, 0, arr.length);
System.out.println(new String(arr));
System.out.println("Disconnecting...performing a single test pass only"); client.disconnect();
} catch (IOException ex) { ex.printStackTrace();
}
}
}
Next, a server class can be used to broadcast datagrams to the address that multicast clients are connected to. The following code demonstrates a multicast server:
package org.java9recipes.blog21.recipe21_4;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class MulticastServer extends Thread {
protected ByteBuffer message = null;
public MulticastServer() {
}
public static void main(String[] args) {
MulticastServer server = new MulticastServer(); server.start();
}
@Override
public void run() {
try {
send the response to the client at "address" and "port" InetAddress address = InetAddress.getByName("226.18.84.25"); int port = 5239;
DatagramChannel server = DatagramChannel.open().bind(null); System.out.println("Sending datagram packet to group " + address + " on port " + port); message = ByteBuffer.wrap("Hello to all listeners".getBytes()); server.send(message, new InetSocketAddress(address, port));
server.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}

 

The server can broadcast a message to each client that is a member of the group. The client should be initiated first, followed by the server. Once the server is started, it will broadcast the message, and the client will receive it.

 

How It Works

Multicasting is the ability to broadcast a message to a group of listeners in a single transmission. A good analogy of multicasting is radio. Thousands of people can tune into a single broadcast event and listen to the same message. Computers can do similar things when sending messages to listeners.

 

A group of client machines can tune into the same address and port number to receive a message that a server broadcasts to that address and port. The Java language provides multicasting functionality via datagram messaging. Datagrams are independent, nonguaranteed messages that can be delivered over the network to clients.

 

(Being nonguaranteed means that the arrival, arrival time, and content are not predictable.) Unlike messages sent over TCP, sending a datagram is a nonblocking event, and the sender is not notified of the receipt of the message. Datagrams are sent using the User Datagram Protocol (UDP) rather than TCP.

 

The ability to send multicast messages via UDP is one benefit over TCP, as long as the ordering, reliability, and data integrity of the message are not mission-critical.

 

Java facilitates multicast messaging via the MulticastChannel interface. Classes that implement the MulticastChannel interface have multicasting enabled and can therefore broadcast to groups and receive group broadcasts. One such class is the DatagramChannel, which is a selectable channel for datagram-oriented sockets.

 

In the solution to this recipe, both a client and a server program are used to communicate via multicast messaging, and the DatagramChannel class is used on both sides of the communication.

 

A DatagramChannel must be configured in a specific way if it is to be used for accepting multicast messages. Specifically, there are options that need to be set on the DatagramChannel client that is opened. We will discuss those options shortly. The following steps are required for creating a client that receives multicast messages.

 

  • \1.\ Open a DatagramChannel.
  • \2.\ Set the DatagramChannel options that are required to multicast.
  • \3.\ Join the client to a multicast group and return a MembershipKey object.
  • \4.\ Open the client.

 

In the solution to this recipe, the client application begins by obtaining a reference to the network interface that will be used for receiving the broadcast messages. Setting up a NetworkInterface is required for multicasting.

 

Next, a port number is chosen, as well as a multicasting IP address. The group or registered listeners will use the IP address in order to listen for broadcasts. The port number must not be in use or an exception will be thrown. For IPv4 multicasting, the IP address must range from 224.0.0.0 to 239.255.255.255, inclusive.

 

This port and IP address is the same one used by a server to broadcast the message. Next, a new DatagramChannel is opened using StandardProtocolFamily.INET. The choices for opening a DatagramChannel are StandardProtocolFamily.INET or StandardProtocolFamily.INET6, corresponding to IPv4 and IPv6, respectively.

 

The first option that is set on the DatagramChannel is StandardSocketOptions.SO_REUSEADDR, and it is set to true. This indicates that multiple clients will be able to “reuse” the address or use it at the same time. This needs to be set for a multicast to occur. The client is then bound to the port using a new InetSocketAddress instance.

 

Last, the StandardSocketOptions.IP_MULTICAST_IF option is set to the network interface that is used. This option represents the outgoing interface for multicast datagrams sent by the datagram-oriented socket.

client.setOption(StandardSocketOptions.SO_REUSEADDR, true);
client.bind(new InetSocketAddress(port));
client.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);

 

Once these options have been set and the port has been bound to the DatagramChannel, it is ready to join the group of listeners. This can be done by calling the DatagramChanneljoin(InetAddress, NetworkInterface) method, passing the group address and network interface that will be used by the client.

 

As a result, a java.nio.channels.MembershipKey object is produced, which is a token that represents the membership of an IP multicast group. Last, the DatagramChannelopen() method is called, which opens the channel to listen for broadcasts. At this point, the client is ready to receive multicast messages and it waits for a message to be received.

 

MembershipKey key = client.join(group, networkInterface); client.open();

 

The next lines of code in the client take care of receiving messages from the server. In order to receive a broadcasted message, a ByteBuffer is created and then eventually passed to the DatagramChannel’s receive() method. Once the receive() method is called, the client will pause until a message is received.

 

You can disable this feature by calling the DatagramChannel configureBlocking(boolean) method and passing a false value. Next, the ByteBuffer is converted to a String value and printed out by repositioning the buffer index at 0 using the flip() method, and then pulling the text starting at index 0 to the last index into a byte[]. Finally, be sure to disconnect the client when you’re finished. That wraps up the client code portion.

 

Configure client to be passive and non.blocking

client.configureBlocking(false);
client.receive(buffer);
client pauses until a message is received... in this case System.out.println("Client Received Message:"); buffer.flip();
byte[] arr = new byte[buffer.remaining()]; buffer.get(arr, 0, arr.length);
System.out.println(new String(arr));
System.out.println("Disconnecting...performing a single test pass only"); client.disconnect();

 

Note In the example to this recipe, a single pass is performed, and the client is then disconnected. For extended listening, you would need a loop with a timeout and provide tests for an ending state.

 

The server code is fairly basic. You can see that the MulticastServer class extends Thread. This means that this server application could run in a thread separate from other code within an application. If there were another class that initiated the MulticastServer class’s run() method, it would run in a thread separate from the class that initiated it. The run() method must exist in any class that extends Thread.

 

The bulk of the server code resides in the run() method. A new InetAddress object is created using the same IP address that the client registered with in order to join the multicast group. The same port number is also declared in the server code, and these two objects will be used later in the code block to send the message.

 

A new DatagramChannel is opened and bound to null. The null value is important because by setting the SocketAddress equal to null, the socket will be bound to an address that is assigned automatically. Next, a ByteBuffer is created that contains a message that will be broadcast to any listeners.

 

The message is then sent using the DatagramChannel’s send(ByteBuffer, InetSocketAddress) method. The send() method in the solution accepts the message as a ByteBuffer object, as well as a new InetSocketAddress that is created by using the address and port, which was declared at the beginning of the block. Told you we’d get back to those!

server.send(message, new InetSocketAddress(address, port));

 

At this point, the client would receive the message that was sent by the server. As for the client that is demonstrated in the solution to this recipe, it would then disconnect. Normally in a real-world scenario, a different class would most likely initiate the server, and its run() method would contain a loop that would continue to execute until all messages have been broadcast or the loop was told to stop. The client would probably not disconnect until after a user initiated a shutdown.

 

Note If your laptop or server is using a different network protocol other than standard IPv4, then results may vary. Please be sure to do a sufficient amount of testing before sending your code to a production environment.

 

Generating and Reading from URLs

Problem

You want to generate URLs programmatically in your application. Once the URLs have been created, you’d like to read data from them for use in your application.

 

Solution

Make use of the http://java.net.URL class in order to create a URL. There are a few different ways to generate a URL depending on the address you are attempting to work with. This solution demonstrates some of these options for creating URL objects, along with comments indicating the differences. Once the URL objects have been created, one of the URLs is read into a BufferedReader and printed to the command line.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
public class GenerateAndReadUrl {
public static void main(String[] args) {
try {
// Generate absolute URL
URL url1 = new URL("http://www.java.net");
System.out.println(url1.toString());
Generate URL for pages with a common base URL url2 = new URL(url1, "search/node/jdk8");
Generate URL from different pieces of data
URL url3 = new URL("http", "java.net", "search/node/jdk8");
readFromUrl(url1);
} catch (MalformedURLException ex) { ex.printStackTrace();
}
}
/**
Open URL stream as an input stream and print contents to command line.
@param url
*/
public static void readFromUrl(URL url) {
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(
url.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
} catch (IOException ex) { ex.printStackTrace();
}
}
}

Running this program will result in the HTML from the URL resource identified as url1 being printed to the command line.

 

How It Works

Creating URLs in Java code is fairly straightforward thanks to the http://java.net.URL class, which does all of the heavy lifting. A URL is a character String that points to a resource on the Internet.

 

Sometimes it is useful to create URLs in Java code so that you can read content from, or push content to, the Internet resource that the URL is pointing to. In the solution to this recipe, a few different URL objects are created, demonstrating the different constructors that are available for use.

 

The easiest route to use for creating a URL is to pass the standard readable URL String for a resource that is located on the Internet to the http://java.net.URL class to create a new instance of the URL. In the solution, an absolute URL is passed to the constructor to create the url1 object. URL url1 = new URL("http://www.java.net");

 

Another useful way to create a URL is to pass two arguments to the URL constructor and create a relative URL. It is useful to base relative URLs on the location of another URL. For instance, if a particular site has a number of different pages, you could create a URL pointing to one of the subpages relative to the URL of the main site. Such is the case with the url2 object in the solution to this recipe.

URL url2 = new URL(url1, "search/node/jdk8");

 

As you can see, the path search/node/jdk8 is relative to the URL that is known as url1. In the end, the human-readable format of the url2 object is represented as http://www.java.net/search/node/jdk8. There are a couple more constructors for creating URL objects that take more than two arguments. Those constructors are as follows:

new URL (String protocol, String host, String port, String path); new URL (String protocol, String host, String path);

 

In the solution, the second of the two constructors shown here is demonstrated. The protocol, hostname, and path of the resource are passed to the constructor to create the url3 object. These last two constructors are usually most useful when you’re dynamically generating a URL.

 

Parsing a URL

Problem You want to programmatically gather information from a URL for use within your application.

Solution

Parse the URL using the built-in URL class methods. In the following example class named ParseUrl, a URL object is created and then parsed using the built-in URL class methods to gather information regarding the URL. After the information has been retrieved from the URL, it is printed to the command line and then used to create another URL.

import java.net.MalformedURLException;
import java.net.URL;
public static void main(String[] args) {
URL url1 = null;
URL url2 = null;
try {
// Generate absolute URL
url1 = new URL("http://www.ThesisScientist.com/catalogsearch/result/?q=juneau");
String host = url1.getHost();
String path = url1.getPath();
String query = url1.getQuery();
String protocol = url1.getProtocol();
String authority = url1.getAuthority();
String ref = url1.getRef();
System.out.println("The URL " + url1.toString() + " parses to the following:\n");
System.out.println("Host: " + host + "\n");
System.out.println("Path: " + path + "\n");
System.out.println("Query: " + query + "\n");
System.out.println("Protocol: " + protocol + "\n");
System.out.println("Authority: " + authority + "\n");
System.out.println("Reference: " + ref + "\n");
url2 = new URL(protocol + "://" + host + path + "?q=java");
} catch (IOException ex) { ex.printStackTrace();
}
}
When this code is executed, the following lines will be displayed:
The URL http://www.ThesisScientist.com/catalogsearch/result/?q=juneau parses to the following:
Host: www.ThesisScientist.com
Path: /catalogsearch/result/
Query: q=juneau
Protocol: http
Authority: www.ThesisScientist.com
Reference: null

 

How It Works

When constructing and working with URLs in an application, it is sometimes beneficial to extract information pertaining to a URL. This can be easily done using the URL built-in class methods, which can call a given URL and return Strings of information. Table 21-1 explains the accessor methods available in the URL class for obtaining information.

 

Accessor Methods for Querying URLs

  • getAuthority() Authority component
  • getFile() File name component
  • getHost() Hostname component
  • getPath() Path component
  • getProtocol() Protocol identifier component
  • getRef() Reference component
  • getQuery() Query component

 

Each of these accessor methods returns a String value that can be used for informational purposes or for constructing other URLs dynamically, as was done in the example. If you take a look at the results from the solution to this recipe.

 

Most of the accessors are self-explanatory. However, a couple of them could use further explanation. The getFile() method returns the file name of the URL. The file name is the same as the result of concatenating the value returned from getPath() with the value returned from getQuery(). The getRef() method may not be very straightforward.

 

The reference component that is returned by calling the getRef() method refers to the “fragment” that may be appended to the end of a URL. For instance, a fragment is indicated using the pound character (#), followed by a String that usually corresponds to a subsection on a particular web page.

 

Although it’s not always needed, the ability to parse a URL to obtain information can come in very handy at times. Because the Java language has helper methods built into the http://java.net.URL class, it makes gathering information pertaining to URLs a piece of cake.

 

Making HTTP Requests and Working with HTTP Responses

Making HTTP Requests and Working with HTTP Responses

Problem You would like to initiate an HTTP request from within an application, and process the response accordingly

Solution

Make use of the HTTP/2 client API and make requests in either a synchronous or asynchronous manner. In the following example code, a request is made to the ThesisScientist website. The example demonstrates a synchronous request, so the code will block until a response is received.

public static void synchronousRequest() {
try {
HttpResponse resp = HttpRequest.create(
new URI("http://www.ThesisScientist.com/us/")).GET().response(); int statusCode = resp.statusCode();
String body = resp.body(HttpResponse.asString()); System.out.println("Status Code: " + statusCode);
// Do something with body text
} catch (URISyntaxException | IOException | InterruptedException ex) { Logger.getLogger(HttpClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
The output from running this example should be as follows, unless the site is down or there are network communication issues:
Status Code: 200
To perform an asynchronous request, simply call upon the responseAsync() method, rather than response(). Doing so will return a CompleteableFuture, upon which you can check status to determine whether or not the response has returned.
public static void asynchronousRequest() {
try {
CompletableFuture<HttpResponse> cf = HttpRequest.create(
new URI("http://www.ThesisScientist.com/us/")).GET().responseAsync(); System.out.println("Request made...");
System.out.println("Check if done...");
while (!cf.isDone()) {
System.out.println("Perform some other tasks while waiting..."); // Periodically check CompletableFuture.isDone()
}
System.out.println("Response Received:");
HttpResponse response = cf.get();
int statusCode = response.statusCode(); System.out.println("Status Code: " + statusCode); String body = response.body(HttpResponse.asString());
// Do something with body text
} catch (URISyntaxException | InterruptedException | ExecutionException ex) { Logger.getLogger(HttpClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
The output from the asynchronous example would resemble the following:
Request made...
Check if done...
Perform some other tasks while waiting...
Perform some other tasks while waiting...
Perform some other tasks while waiting...
...
Response Received:
Status Code: 200

 

How It Works

The HTTP/1.1 client had been a part of the JDK for years. In fact, it has remained largely unchanged since its inception in JDK 1.1. HTTP/1.1 has become outdated, and is no longer the preferred method of communicating via HTTP. The newer standard, HTTP/2 resolves many issues that have been around for years as part of working with HTTP/1.1.

 

In Java 9, a new HTTP/2 client API has been added, allowing developers to easily make use of newer methodologies, while still remaining backward compatible.

 

Performance was oftentimes an issue with HTTP/1.1 due to issues such as head-of-line blocking and numerous request/response cycles. The HTTP/2 protocol was introduced in 2015, and it resolves many of these older issues. For instance, binary frames are now used when sending messages, reducing the complexity of parsing messages.

 

Everything can now be sent over one TCP connection, rather than creating multiple TCP connections to send numerous messages. This only scratches the surface, and there have been many more improvements in HTTP/2…but this provides a sound understanding of why the changes were needed.

 

As mentioned previously, in Java 9 a new HTTP/2 client API has been added, making it easy to perform HTTP requests and receive HTTP responses either synchronously or asynchronously. In the first example, the synchronous API is demonstrated, invoking the HttpRequest.create() method, and passing a URI, followed by calling GET() and response() methods in a builder-style pattern. This returns an HttpResponse object.

 

HttpResponse resp = HttpRequest.create(

new URI(");

 

This is a blocking call, of course, as one will need to wait until a response is received before further processing can be completed. Once received, the HttpResponse object can be used to return the body, HTTP status code, and a number of other items. In this example, the HTTP status code is merely printed out, and in many cases the status code is used along with a conditional to determine how to perform processing.

 

Taking a look at the second asynchronous example, it is easy to notice the differences in code when the HttpRequest.create() method is invoked. After the URI is passed to the create() method, the GET() method is called again, followed by the responseAsync() method.

 

The call to responseAsync() returns a CompletableFuture, and in this case generics are used to enforce that HttpResponse is returned. The CompletableFuture can then be checked to determine if the response has been returned by using the isDone() method.

 

Appropriate actions can be taken to maintain a check again at a later time if the response has not yet been returned, or handle a received response accordingly. In this example, a while loop is used to continue looping until the response is finally returned. To make this code more production ready, a conditional could be used to halt the loop after a certain number of iterations have been completed.

 

The updated HTTP/2 client brings a more modern API for handling HTTP to Java. The updated API ensures that one can perform synchronous or asynchronous request/response lifecycles.