29 januari 2023
Handige menu’s op je Cisco bureautelefoon

Ik probeer een bijzonder oud stukje software te moderniseren: een Asterisk hulpje gebouwd in Java 1.8 met JAXB zodat de Cisco telefoon Menus werken. gebouwd rondom 2010 met populaire technieken van toen. Zou ik eea nog naar ‘het heden’ kunnen upgraden?

van versie “antiek” naar recent

Laten we dat proberen te upgraden: JAXB is een handige manier om van XML notatie naar Java objecten om te zetten (serialiseren) en omgekeerd. Helaas is JAXB sinds Java 11 uit Het Java standaardframework gehaald, in Java 9 werd het verouderd verklaard (deprecate).

Dit alles was een eeuwigheid geleden, maar is er anno nu een vervanger om JAXB te gebruiken? Misschien een mooie nieuwere alternative implementatie buiten het standaard java framework?

goed uitgelegd

In het bovenstaand artikel wordt goed uitgelegd hoe je toch JAXB kan gebruiken zonder dat deze in het standaard java framework zit. Gelukkig is er dus ergens op het internet iemand die bedacht heeft de verouderde JAXB functionaliteit aan te bieden met een library

https://eclipse-ee4j.github.io/jaxb-ri/

<!-- JAXB API v3.0.1 -->
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>3.0.1</version>
</dependency>

<!-- JAXB v3.0.2 reference implementation (curiously with com.sun coordinates) -->
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>3.0.2</version>
    <scope>runtime</scope>
</dependency>

Spring framework

Het Spring framework dat ik voor de structuur, test en deployments gebruik is van een verouderde V3 vaar v5 geupdate, dit geeft geen probleem.!Hier is alleen een update van de laatste stabiele versie nodig. Kudos voor de dames en heren Spring voor deze 10 jaar aan backwards compatibility!

Vervolgens is het nodig om een WAR builder aan te zetten op het project

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.3.1</version>
</plugin>

Google App Engine?

Voeg met de gcloud SDK de app engine ondersteuning toe op de mac

gcloud components install app-engine-java
Voeg een App Engine local dev server toe
gebruik de volgende path:  
/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/platform/google_appengine/google/appengine/tools/java

Daarna voeg je een bestandje toe genaamd: appengine-web.xml in de WEB-INF folder

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <threadsafe>true</threadsafe>
  <runtime>java17</runtime>
</appengine-web-app>

Start de app engine omgeving en krijg de volgende fout

java.lang.RuntimeException: Unable to create a DevAppServer
	at com.google.appengine.tools.development.DevAppServerFactory.doCreateDevAppServer(DevAppServerFactory.java:378)
	at com.google.appengine.tools.development.DevAppServerFactory.createDevAppServer(DevAppServerFactory.java:310)
	at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:384)
	at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:58)
	at com.google.appengine.tools.development.DevAppServerMain.run(DevAppServerMain.java:258)
	at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:249)
Caused by: java.lang.ExceptionInInitializerError
	at com.google.appengine.tools.development.DevAppServerImpl.<init>(DevAppServerImpl.java:135)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at com.google.appengine.tools.development.DevAppServerFactory.doCreateDevAppServer(DevAppServerFactory.java:363)
	... 5 more
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make static java.net.URLStreamHandler java.net.URL.getURLStreamHandler(java.lang.String) accessible: module java.base does not "opens java.net" to unnamed module @18e8568
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
	at com.google.appengine.tools.development.StreamHandlerFactory.<clinit>(StreamHandlerFactory.java:52)
	... 12 more
Disconnected from server

Process finished with exit code 1

Oorzaak: Java17, hoewel Java17 al een tijd stabiel is lijkt de combinatie van mijn (stok)oude code en App Engine dev server geen goede.

https://www.spigotmc.org/threads/inaccessibleobjectexception-unable-to-make-protected-void-java-net-urlclassloader-addurl.514803/

Bovenstaand is een oplossing voor het classloader probleem dat zich sinds java16 kan voordoen.

Als alternatief gaan we terug naar Java11, eens kijken of dat wat veranderd.

bingo! een stokoude Angular frontend die niet af is

Change of Plans!

Omdat de App Engine omgeving me niet zoveel gaf, voornamelijk exceptions en problemen dacht ik “Het is toch een klein projectje, waarom niet van Spring naar Spring Boot overstappen?”

Het voordeel van Spring Boot is verregaande standardisatie, en de app draait nu ‘zonder hulpmiddelen’ dus met eigen (tomcat) server etc. Dit is ideal om het dan te laten draaien in een container en vervolgens in een GCP dienst als Cloud Run.

We gaan migreren! van full spring naar spring boot met behulp van deze guide

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.1</version>
</parent>

daarna alle spring framework referenties in de pom.xml verwijderen en vervangen voor een spring-boot web referentie

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Meerdere Servlets in 1 service.

Nu kom ik er achter dat ik waarschijnlijk iets gedaan heb wat qua design niet zo netjes is: ik heb 2 keer de dispatcher servlet in de oplossing gezet terwijl die er (schijnt) maar 1 keer in mag zitten

<web-app id="WebApp_ID" version="2.4"
	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<display-name>Franzenonline PBX web application</display-name>

	<servlet>
		<servlet-name>phoneservice-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>phoneservice-dispatcher</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>
	
	<servlet>
		<servlet-name>cisco-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>cisco-dispatcher</servlet-name>
		<url-pattern>/cisco/*</url-pattern>
	</servlet-mapping>


	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>WEB-INF/applicationContext.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>


</web-app>

Omdat we de hele handel naar Spring Boot over aan het zetten zijn lijkt met dit een mooi moment om afscheid te nemen van de hele WEB-INF folder en alle config in de Application class te zetten! Nu eerst een mooie oplossing bedenken voor deze 2 gescheiden delen van de API: /cisco/* vs /rest/*

Na wat onderzoeken bleek dat de XML messaging kant voor Cisco telefoons

Uiteindelijk

Volgende stap: beveiliging inbouwen en deployen een cloudomgeving

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

Time limit is exhausted. Please reload the CAPTCHA.