Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- [#2101](https://github.com/apache/trafficcontrol/issues/2101) *Traffic Portal* Added the ability to tell if a Delivery Service is the target of another steering DS.
- [#6033](https://github.com/apache/trafficcontrol/issues/6033) *Traffic Ops, Traffic Portal* Added ability to assign multiple server capabilities to a server.
- [#7032](https://github.com/apache/trafficcontrol/issues/7032) *Cache Config* Add t3c-apply flag to use local ATS version for config generation rather than Server package Parameter, to allow managing the ATS OS package via external tools. See 'man t3c-apply' and 'man t3c-generate' for details.
- Add Kotlin 1.7.10 support to Traffic Router

### Changed
- *Traffic Ops* Python client now uses Traffic Ops API 4.1 by default.
Expand Down
14 changes: 13 additions & 1 deletion docs/source/development/traffic_router.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@ If a development environment is already set up for the previous version of Traff
mvn clean verify -Djava.library.path=[tomcat native library path on your box]
java -Djava.library.path=[tomcat native library path on your box] TrafficRouterStart


Converting Traffic Router to Kotlin
===================================

:ref:`tr-to-kotlin`

.. toctree::
:hidden:
:maxdepth: 1

traffic_router/converting_to_kotlin

Manual Testing
==============
Look up the URL for a test HTTP :term:`Delivery Service` in Traffic Ops and then make a request. When Traffic Router is running and used as a resolver for the host in the :term:`Delivery Service` URL, the requested origin content should be found through an Edge-tier :term:`cache server`.
Expand Down Expand Up @@ -316,4 +328,4 @@ API
:hidden:
:maxdepth: 1

traffic_router/traffic_router_api
traffic_router/traffic_router_api
163 changes: 163 additions & 0 deletions docs/source/development/traffic_router/converting_to_kotlin.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
..
..
.. Licensed under the Apache License, Version 2.0 (the "License");
.. you may not use this file except in compliance with the License.
.. You may obtain a copy of the License at
..
.. http://www.apache.org/licenses/LICENSE-2.0
..
.. Unless required by applicable law or agreed to in writing, software
.. distributed under the License is distributed on an "AS IS" BASIS,
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
.. See the License for the specific language governing permissions and
.. limitations under the License.
..

.. _tr-to-kotlin:

***********************************
Converting Traffic Router to Kotlin
***********************************


Kotlin Setup
============

#. Get the latest version of IntelliJ IDEA Community Edition from the package manager of your choice.

.. Note:: Version 2022.2.2 or higher is recommended.

Go to File -> Settings -> Plugins and update the Kotlin plugin if an update is available.

#. Remove the ``.idea/`` directory from the :file:`traffic_router/` router directory

#. Open the :file:`traffic_router/` directory in IntelliJ IDEA. It will auto-detect Traffic Router's Java version and Maven modules and download the Maven dependencies. In IntelliJ, the *Project* pane should look like this:

.. figure:: intellij-traffic_router.png
:width: 60%
:align: center
:alt: Traffic Router in IntelliJ Idea

Project Pane

#. Go to Settings -> Editor -> Code Style -> Kotlin -> Imports and
* Under *Top-Level Symbols*, choose *Use single name import*

* Under *Java Statics and Enum Members*, choose *Use single name imports*

* Under *Packages to Use Import with '*'*, remove packages until it says *Nothing to show*

* Save your settings

Converting a single source file to Kotlin
=========================================

#. In the *Project* pane, right click on the main ``traffic_router`` directory and choose *Convert Java File to Kotlin File*. This process will take 20-30 minutes. Do not do anything else in IntelliJ until this step completes.

.. Note:: It is very important to select the ``traffic_router`` directory so that *all* Java sources are considered during the conversion process. If you select only one or some Traffic Router sources before clicking *Convert Java File to Kotlin File*, the converter will incorrectly detect variables as nullable because not all sources were considered. Any Kotlin sources generated without selecting the whole ``traffic_router`` directory should be scrapped, even if you spent a lot of time on it.

#. Decide which single newly-converted Kotlin source file you want to keep. You may want to choose a small source file to start off with. To find the smallest newly-converted Kotlin source file:

.. code-block:: shell
:caption: List of newly-converted Kotlin source files, ordered by size

git diff --cached --name-only '*.kt' | xargs wc -l | sort -gr

In this example, we will keep the conversion of :file:`traffic_router/connector/src/main/java/org/apache/traffic_control/traffic_router/utils/HttpsProperties.java`.

#. Restore all of the other newly-deleted Java sources:

.. code-block:: shell
:caption: Restore all of the other newly-deleted Java sources

git diff --cached --name-only '*.java' |
grep -v 'traffic_router/connector/src/main/java/org/apache/traffic_control/traffic_router/utils/HttpsProperties\.*' |
xargs git checkout HEAD

#. Delete all of the other newly-generated Kotlin sources:

.. code-block:: shell
:caption: Delete all of the other newly-generated Kotlin sources

git diff --cached --name-only '*.kt' |
grep -v 'traffic_router/connector/src/main/java/org/apache/traffic_control/traffic_router/utils/HttpsProperties\.*' |
xargs git rm -f

#. Verify that running ``git status`` shows you only 2 changes (both of which are staged):

* ``HttpsProperties.java`` is deleted

* ``HttpsProperties.kt`` is added

.. code-block:: shell
:caption: The result of ``git status``

Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: traffic_router/connector/src/main/java/org/apache/traffic_control/traffic_router/utils/HttpsProperties.java
new file: traffic_router/connector/src/main/java/org/apache/traffic_control/traffic_router/utils/HttpsProperties.kt

#. Commit these staged changes with a descriptive *commit* message.

#. Open your new Kotlin source file, most likely a class, in IntelliJ and look at it yourself before going on.

#. The conversion process mangles some imports. The most common example of this is having the word ``import`` at the end of one line, then the package name on a completely different line below:

.. code-block:: kotlin
:caption: An example of imports mangled from the Kotlin conversion process

package org.apache.traffic_control.traffic_router.utilsimport

import org.apache.logging.log4j.LogManager
import org.apache.traffic_control.traffic_router.utils.HttpsProperties
import java.nio.file.*
import java.util.function.Consumer

org.springframework.web.bind.annotation .RequestMapping

Run this code snippet to fix these types of mangled imports:

.. code-block:: shell
:caption: Fix a common type of mangled import

sed -i -z 's|import\(\n.*\n\)\([a-hk-z][a-z]*\.\)|\1import \2|g' $(git ls-files '*.kt')


Although the snippet above fixes that specific type of mangled import, in cases where the conversion mistakenly puts multiple imports on a single line, you will need to fix those yourself.

#. Once the imports are syntactically correct, remove the unused imports. With your Kotlin source file open in IntelliJ, go to Code -> Optimize Imports. This will remove a lot, likely hundreds, of unused imports left over from the Kotlin conversion process.

Stage and commit these fixes to the imports before going on.

#. Familiarize yourself with Kotlin syntax, particularly with syntax around null safety (go through https://kotlinlang.org/docs/null-safety.html).

A big Java pain point is null checks and NullPointerExceptions, and one of Kotlin's greatest features is its compile-time null safety. Converting your class from Java to Kotlin most likely produced several compile errors, which are usually null safety-related.

Jump to the first compile error by pressing ``F2``. In the example of ``HttpsProperties.kt``:

.. figure:: null-compile-error.png
:width: 80%
:align: center
:alt: The first compile-time error in HttpsProperties.kt

Compile-time error in HttpsProperties.kt


In this case, the null safety errors and warnings can be eliminated by making ``HTTPS_PROPERTIES_FILE`` a ``const val`` (in Java, ``HTTPS_PROPERTIES_FILE`` was ``private static final``):

.. figure:: errors-warnings-fixed.png
:width: 80%
:align: center
:alt: HttpsProperties.kt with errors and warnings fixed

HttpsProperties.kt with errors and warnings fixed

Almost all of these errors and warnings can be fixed with only small changes like these. Fix all of the Kotlin errors and warnings in the source file, then stage and commit.

#. Run unit, integration, and feature tests. Resolve test failures without removing the failing test cases.

#. PR your class! Congratulations, you have made the Traffic Router codebase safer and more maintainable.

.. Note:: For very small source files, sometimes it is acceptable to include more than one converted source file in a single PR. However, any large converted source file should have its own PR.

To see the git history of the HttpsProperties example shown here, see https://github.com/zrhoffman/trafficcontrol/commits/tr-kotlin-HttpsProperties.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ public Zone load(ZoneKey zoneKey) {
LoadingCache<ZoneKey, Zone> dynamicZoneCache = CacheBuilder.newBuilder().build(loader);

// stub calls for signatureManager, dynamicZoneCache and generateDynamicZoneKey
when(ZoneManager.getDynamicZoneCache()).thenReturn(dynamicZoneCache);
when(ZoneManager.getDynamicZoneCache()).thenAnswer(invocation -> dynamicZoneCache);
ZoneKey zk = new ZoneKey(Name.fromString("dns1.example.com."), recordList);
dynamicZoneCache.put(zk, dynamicZone);

when(ZoneManager.getSignatureManager()).thenReturn(signatureManager);
when(ZoneManager.getSignatureManager()).thenAnswer(invocation -> signatureManager);
Answer<ZoneKey> currentTimeAnswer = invocation -> zk;

when(ZoneManager.getSignatureManager().generateDynamicZoneKey(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
mock-maker-inline
67 changes: 67 additions & 0 deletions traffic_router/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<commons-compress.version>1.9</commons-compress.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
<kotlin.version>1.7.10</kotlin.version>
</properties>

<scm>
Expand All @@ -58,6 +59,30 @@

<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<jvmTarget>11</jvmTarget>
</configuration>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
Expand All @@ -70,6 +95,32 @@
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Expand Down Expand Up @@ -113,6 +164,22 @@
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
</dependencies>


<profiles>
<profile>
<id>rpm-build</id>
Expand Down