javax.ejb.TimerService
) in Enterprise JavaBeans™ can be requested by components
beyond the dependency on clocks of physical machines or distributed JVMs (Java Virtual Machines).
@javax.annotation.Resource
private javax.ejb.TimerService _timer_service = null;
…
// A timer object is created for a specific usage, e.g., after 1000 ms, only one time, the “my_business_method” Java method is called:
assert(_timer_service != null);
_timer_service.createSingleActionTimer(1000L, new javax.ejb.TimerConfig("Data passed to timed task", false));
…
// The timed task:
@javax.ejb.Timeout
public void my_business_method(javax.ejb.Timer timer) {
String s = (String)timer.getInfo();
assert(s != null && s.equals("Data passed to timed task"));
…
Currency conversion
).
Dependency on an ever-increasing richer set of worldwide business
services (e.g., Rapid API)
may stumble over service deny.
@javax.persistence.Entity
@javax.persistence.Table(name = "PRISONER")
@javax.persistence.NamedNativeQuery(name = "Prisoner.Under_remand_SQL", query = "SELECT * FROM Prisoner WHERE prison_file_number NOT IN (SELECT prison_file_number FROM Conviction)")
@javax.persistence.NamedQueries({
@javax.persistence.NamedQuery(name = "Prisoner.All_JPQL", query = "SELECT p FROM Prisoner p"),
@javax.persistence.NamedQuery(name = "Prisoner.Under_remand_JPQL", query = "SELECT p FROM Prisoner p WHERE p._conviction IS EMPTY")
})
public class Prisoner implements java.io.Serializable {
private static final long serialVersionUID = 1L;
@javax.persistence.Id
@javax.persistence.Basic(optional = false)
@javax.validation.constraints.NotNull
@javax.validation.constraints.Size(min = 1, max = 10)
@javax.persistence.Column(name = "PRISON_FILE_NUMBER")
private String _prison_file_number;
public String get_prison_file_number() {
return _prison_file_number;
}
…
@org.springframework.stereotype.Repository
public interface PrisonerDao extends org.springframework.data.jpa.repository.JpaRepository<Prisoner, String> {
@org.springframework.data.jpa.repository.Query(value = "SELECT * FROM Prisoner WHERE prison_file_number NOT IN (SELECT prison_file_number FROM Conviction)", nativeQuery = true)
java.util.List<Prisoner> under_remand();
}
@org.springframework.stereotype.Service
public interface JSON_service {
public enum QUERY {
ALL_CRIMINAL_CASES, ALL_JUDICIAL_DECISIONS, ALL_MOTIVES, ALL_OFFENSES, ALL_PRISONERS, UNDER_REMAND_PRISONERS
};
String to_JSON(QUERY type);
}
@org.springframework.web.bind.annotation.RestController
public class PrisonerCRUD implements JSON_service {
@org.springframework.beans.factory.annotation.Autowired
private PrisonerDao _prisonerDao;
@Override
public String to_JSON(QUERY type) {
java.util.List<Prisoner> prisoners = type == QUERY.ALL_PRISONERS ? _prisonerDao.findAll() : type == QUERY.UNDER_REMAND_PRISONERS ? _prisonerDao.under_remand() : new java.util.LinkedList<>();
javax.json.JsonArrayBuilder _prisoners = javax.json.Json.createArrayBuilder();
for (Prisoner prisoner : prisoners) {
javax.json.JsonObjectBuilder builder = javax.json.Json.createObjectBuilder();
builder.add("GIVEN_NAME", prisoner.get_given_name());
builder.add("SURNAME", prisoner.get_surname());
_prisoners.add(builder.build());
}
return _prisoners.build().toString();
}
// http://localhost:8080/NYCP/API/prisoners
@org.springframework.web.bind.annotation.GetMapping(value = "/prisoners")
public String all() { return to_JSON(QUERY.ALL_PRISONERS); }
application.properties
file
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:derby:memory:local;create=true
server.servlet.contextPath=/NYCP/API
NewYorkCityPenitentiary_application.java
file
@org.springframework.boot.autoconfigure.SpringBootApplication
public class NewYorkCityPenitentiary_application {
public static void main(String[] args) {
org.springframework.boot.SpringApplication.run(NewYorkCityPenitentiary_application.class, args);
}
}
POST
(Spring)Content-type
'application/x-www-form-urlencoded'
// curl -X POST -d 'motive_number=02&motive_label=assault and battery' http://localhost:8080/NYCP/API/motives/new
@org.springframework.web.bind.annotation.PostMapping(value = "/new") // <=> '@RequestMapping(method = RequestMethod.POST)'
public void post_(@org.springframework.web.bind.annotation.RequestParam java.util.Map<String, String> query) {
Motive motive = new Motive();
motive.set_motive_number(query.get("motive_number"));
motive.set_motive_label(query.get("motive_label"));
_motiveDao.save(motive);
}
Content-type
'application/json'
// curl -X POST -H "Content-Type: application/json" -d '{"_motive_number":"02", "_motive_label":"assault and battery"}' http://localhost:8080/NYCP/API/motives
@org.springframework.web.bind.annotation.PostMapping(value = "", // <=> '@RequestMapping(method = RequestMethod.POST)'
consumes = org.springframework.http.MediaType.APPLICATION_JSON_VALUE)
public void post(@org.springframework.web.bind.annotation.RequestBody Motive motive) {
_motiveDao.save(motive);
…
}
The Web Services W3 technology generates the need for API discoverability that may leverage, for instance, Web Services semantic composition.
While prior middleware or Web Services technologies (e.g., CORBA, SOAP) single out entry points as fixed interfaces (e.g., in Interface Description Language -IDL- for CORBA, WSDL for SOAP), RESTful-oriented architecture promotes a dynamical approach, which is HATEOAS.
Use cases, advantages, and disadvantages here…
// Inheriting 'RepresentationModel' provides an 'add' method to create "business-logic" RESTful navigation links:
public class Motive extends org.springframework.hateoas.RepresentationModel<Motive> implements java.io.Serializable { …
@org.springframework.web.bind.annotation.RestController
@org.springframework.web.bind.annotation.RequestMapping(value = "/motives")
public class MotiveCRUD implements JSON_service {
@org.springframework.beans.factory.annotation.Autowired
private MotiveDao _motiveDao;
…
@org.springframework.web.bind.annotation.GetMapping(value = "/{motive_number}")
public String get(@org.springframework.web.bind.annotation.PathVariable String motive_number) {
java.util.Optional<Motive> motive = _motiveDao.findById(motive_number);
javax.json.JsonObjectBuilder builder = javax.json.Json.createObjectBuilder();
if (motive.isPresent())
builder.add("MOTIVE_LABEL", motive.get().get_motive_label());
return builder.build().toString();
}
…
// curl -X POST -H "Content-Type: application/json" -d '{"_motive_number":"02", "_motive_label":"assault and battery"}' http://localhost:8080/NYCP/API/motives
@org.springframework.web.bind.annotation.PostMapping(value = "", // <=> '@RequestMapping(method = RequestMethod.POST)'
consumes = org.springframework.http.MediaType.APPLICATION_JSON_VALUE)
public org.springframework.hateoas.RepresentationModel<Motive> post(@org.springframework.web.bind.annotation.RequestBody Motive motive) {
_motiveDao.save(motive);
// 'linkTo' inspects the controller class and obtains its root mapping, e.g., http://localhost:8080/NYCP/API/motives
// 'slash' adds 'motive_number' as the path variable of the link
// finally, 'withSelfRel' qualifies the relation as a self-link
org.springframework.hateoas.Link link
= org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo(MotiveCRUD.class).slash(motive.get_motive_number()).withSelfRel();
// System.out.println(link.toUri().toString()); // e.g., http://localhost:8080/NYCP/API/motives/02
motive.add(link);
return motive;
}
curl -X POST -H "Content-Type: application/json" -d '{"_motive_number":"02", "_motive_label":"assault and battery"}'
\ http://localhost:8080/NYCP/API/motives
{
"_motive_number":"02",
"_motive_label":"assault and battery",
"_links":
{
"self":
{
"href":"http://localhost:8080/NYCP/API/motives/02"
}
}
}
public static double Convert(Currencies fromCurrency, Currencies toCurrency, double amount)
throws java.net.MalformedURLException, java.io.IOException {
java.net.URL url = new java.net.URL("http://openexchangerates.org/api/latest.json" + "?app_id=" + _License_key);
java.net.URLConnection connection = (java.net.URLConnection) url.openConnection();
if (connection != null) {
// No specific configuration data so 'null':
javax.json.stream.JsonParserFactory factory = javax.json.Json.createParserFactory(null);
javax.json.stream.JsonParser parser = factory.createParser(connection.getInputStream());
…
while (parser.hasNext()) {
javax.json.stream.JsonParser.Event event = parser.next();
if (event == javax.json.stream.JsonParser.Event.KEY_NAME && parser.getString().equals(toCurrency.currency)) {
while (parser.hasNext()) {
event = parser.next();
if (event == javax.json.stream.JsonParser.Event.VALUE_NUMBER) {
amount *= parser.getBigDecimal().doubleValue(); // Conversion rate acquisition (free), but direct conversion is with charge!
break;
}
}
}
}
{
"success":true,
"timestamp":1656062943,
"base":"EUR",
"date":"2022-06-24",
"rates":{"AED":3.874208,"AFN":94.22818,"ALL":119.759709,"AMD":434.685387,…}
}
<wsdl:documentation> Currency Server - An exchange rate information and currency conversion Web service.
</wsdl:documentation>
…
<s:element name="Convert">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="licenseKey" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="fromCurrency" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="toCurrency" type="s:string"/>
<s:element minOccurs="1" maxOccurs="1" name="amount" type="s:double"/>
<s:element minOccurs="1" maxOccurs="1" name="rounding" type="s:boolean"/>
<s:element minOccurs="0" maxOccurs="1" name="format" type="s:string"/>
<s:element minOccurs="1" maxOccurs="1" name="returnRate" type="tns:curncsrvReturnRate"/>
<s:element minOccurs="0" maxOccurs="1" name="time" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="type" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
A SOAP Web Service requires a Web Services Description Language (WSDL) specification.
// Location of the WSDL specification:
@javax.xml.ws.WebServiceRef(wsdlLocation = "META-INF/wsdl/fx.currencysystem.com/webservices/CurrencyServer5.asmx.wsdl")
com.currencysystem.webservices.currencyserver.CurrencyServer service;
…
com.currencysystem.webservices.currencyserver.CurrencyServerSoap port = service.getCurrencyServerSoap12();
Object o = port.convert(licenseKey, fromCurrency, toCurrency, amount, rounding, format, returnRate, time, type);
*Apache CXF may automatically generate client components (consumers) in Java, JavaScript or other languages from WSDL.
const soap = require('soap');
soap.createClientAsync("https://fx.currencysystem.com/webservices/CurrencyServer5.asmx?wsdl").then((client: any) => {
// console.log(JSON.stringify(client.describe()));
const ActiveCurrencies = client['ActiveCurrencies'];
ActiveCurrencies(null, (err: any, result: any, envelope: any, header: any) => {
console.log("Result: " + JSON.stringify(result));
});
const Convert = client['Convert'];
Convert({
fromCurrency: "EUR",
toCurrency: "MAD",
amount: 1,
rounding: true,
returnRate: "curncsrvReturnRateString"
}, (err: any, result: any) => {
console.log("Result: " + result.data);
});
});
javax.ws.rs
package:
characterization
within the Java EE Tutorial here…
*RESTful Web Services have gained leadership because of their wide take-up by Google, Amazon, Facebook, etc. RESTful Web Services single out the idea of “resource” as the key means to retrieve data from Web places supporting exposed Web Services. While RESTful Web Services may be described with the help of WSDL, WADL (Web Application Description Language) is the preferred support.
An ESB (e.g., Apigee) eases the discovering and access to services in a business perspective. It aims at including service interoperability both from a syntactical and semantic viewpoint.
“The key objective of cloud computing is the transparent access to computing resources without the need for an infrastructure and its management. For example, a chat application intensively requires message queues, their installation, their configuration, their administration and their use through programs.”
Private, public or hybrid cloud computing platforms?
JMS that is fully part of Java EE.
javax.jms.ConnectionFactory
interface and
javax.jms.Destination
interface with Queue
and Topic
as straight sub-interfaces
javax.jms.Destination
objects match to “physical” resources
as message containers on the Java EE application server
public void setJMSReplyTo(Destination replyTo) throws JMSException
)
The TopicRequestor
utility class is devoted to this communication mode
as well.
*Scalability issues lead to have many instances of a listener type.
setJMSExpiration
and/or setJMSTimestamp
.