Skip to main content
  1. Posts/

Advent Calendar 2025 - Introduction of multiple aliases - Part 2

Sven Ruppert
Author
Sven Ruppert
20+ years of Java, specialised in Security, Vaadin and Developer Relations. When not coding, you’ll find me in the woods with an axe.
Table of Contents

Today’s update introduces another practical development step for the URL shortener. After the last few days were dedicated to UI refinement and the better structuring of detailed dialogues and form logic, the focus is now on an aspect that plays a significant role in the everyday life of many users: the flexible management of multiple aliases per target URL.

You can find the source code for this development status on GitHub underhttps://github.com/svenruppert/url-shortener/tree/feature/advent-2025-day-06

Here are the relevant screenshots of the Vaadin application.

Overview of the URL shortener application, displaying a list of created shortcodes, original URLs, and their expiration details.
Screenshot of a new alias management window in a URL shortener application, displaying fields for entering aliases, a preview section showing generated short URLs, and validation status indicators for each alias.
Screenshot of the URL shortener application interface, featuring sections for creating new short links, managing aliases, and displaying their status.

What was previously only possible sequentially – an alias, a destination address – will now become a dynamic workspace. Users can add new aliases to existing short links, create variants for different use cases, or manage parallel campaigns without creating new records each time. The MultiAliasEditorStrict forms the core of this new workflow: inline validation, fast feedback, clear status indicators and an event flow that propagates changes directly into the OverviewView. The application responds immediately to user input and keeps the entire interface consistent, without requiring manual reloads or context switching.

But this is much more than just a UI comfort update. The increased flexibility in the alias structure inevitably leads to higher demands on server-side stability – especially on the stability of forwarders. Once several aliases point to the same destination address, the redirect logic must be deterministic and reliably detect erroneous requests. Therefore, a consistent, centralised request check was introduced in parallel with the UI extension to secure all forwarding operations and ensure predictable HTTP behaviour.

These changes combine two sides of the same coin: greater user freedom in their daily work and a robust technical foundation that reliably supports it. In the following, we will therefore take a closer look at the revised redirect implementation and the new security mechanisms that underpin stable, traceable, and maintainable redirect behaviour.

More Robust Redirects and HTTP Security
#

In parallel with the extensive improvements to the user interface, the server-side component of the URL shortener has also been revised. A central focus was on increasing the stability and security of HTTP communication. Especially when handling redirects, several methods have had to carry out similar checks – for example, whether the correct HTTP method was used or whether a request was incomplete. These repetitions led to inconsistent behaviour and made maintenance difficult.

In the process, a consistent request-handling system was introduced to centralise these checks. The code for the RedirectHandler clearly shows how a robust redirect is now implemented:

package com.svenruppert.urlshortener.server.handler;

import com.svenruppert.urlshortener.core.http.HttpStatus;
import com.svenruppert.urlshortener.core.store.UrlMappingStore;
import com.svenruppert.urlshortener.server.util.RequestMethodUtils;
import com.svenruppert.urlshortener.server.util.ResponseWriter;
import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;

public class RedirectHandler
    implements HttpHandler, HasLogger {

  private final UrlMappingLookup store;

  public RedirectHandler(UrlMappingLookup store) {
    this.store = store;
  }

  @Override
  public void handle(HttpExchange exchange)
      throws IOException {
    if (! RequestMethodUtils.requireGet(exchange)) return;

    final String path = exchange.getRequestURI().getPath(); e.g. "/ABC123"
    if (path == null || !path.startsWith(PATH_REDIRECT)) {
      exchange.sendResponseHeaders(400, -1);
      return;
    }
    final String code = path.substring((PATH_REDIRECT).length());
    if (code.isBlank()) {
      exchange.sendResponseHeaders(400, -1);
      return;
    }
    logger().info("looking for short code {}", code);
    Optional<String> target = store
        .findByShortCode(code)
        .map(ShortUrlMapping::originalUrl);

    if (target.isPresent()) {
      exchange.getResponseHeaders().add("Location", target.get());
      exchange.sendResponseHeaders(302, -1);
    } else {
      exchange.sendResponseHeaders(404, -1);
    }
  }
}

The RedirectHandler class ensures that only valid GET requests are accepted. Invalid methods – such as POST or DELETE – are caught by the RequestMethodUtils helper class. This prevents inadvertent writes to a read-only resource.

The check logic in RequestMethodUtils is deliberately kept simple and centralises all recurring security checks. The following excerpt shows how she works internally:

package com.svenruppert.urlshortener.server.util;

import com.svenruppert.urlshortener.core.http.HttpStatus;
import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;

public class RequestMethodUtils {

  public static boolean requireGet(HttpExchange exchange)
      throws IOException {
    HasLogger.staticLogger().info("handle ... {} ", exchange.getRequestMethod());
    Objects.requireNonNull(exchange, "exchange");
    if (!" GET".equalsIgnoreCase(exchange.getRequestMethod())) {
      writeJson(exchange, METHOD_NOT_ALLOWED, "Only GET is allowed for this endpoint.");
      return false;
    }
    return true;
  }
  SNIP...
}

This helper class serves as a compact security wall: every request-processing method calls it at the beginning. This creates predictable, consistent behaviour across the HTTP stack. This is particularly relevant for forwarding, as unauthorised or erroneous methods are reliably blocked.

Response generation is handled by ResponseWriter, which handles clean header configuration and uniform error output. In contrast to earlier implementations, which manually generated JSON or text responses in several places, there is now a central method:

public static void writeJson(HttpExchange ex, HttpStatus httpStatus, String message)
      throws IOException {
    HasLogger.staticLogger().info("writeJson {}, {}", httpStatus, message);
    byte[] data = message.getBytes(UTF_8);
    Headers h = ex.getResponseHeaders();
    h.set(CONTENT_TYPE, JSON_CONTENT_TYPE);
    ex.sendResponseHeaders(httpStatus.code(), data.length);
    try (OutputStream os = ex.getResponseBody()) {
      os.write(data);
    } catch (Exception e) {
      HasLogger.staticLogger().info("writeJson {} (catch)", e.getMessage());
      byte[] body = ("{\"error\":\"" + e.getMessage() + "\"}").getBytes(StandardCharsets.UTF_8);
      try {
        ex.getResponseHeaders().set(CONTENT_TYPE, JSON_CONTENT_TYPE);
        ex.sendResponseHeaders(INTERNAL_SERVER_ERROR.code(), body.length);
        ex.getResponseBody().write(body);
      } catch (Exception ignoredI) {
        HasLogger.staticLogger().info("writeJson (catch - ignored I) {} ", ignoredI.getMessage());
      }
    } finally {
      try {
        ex.close();
      } catch (Exception ignoredII) {
        HasLogger.staticLogger().info("writeJson (catch - ignored II) {} ", ignoredII.getMessage());
      }
    }
  }

The merging of these helper classes yields a well-structured server architecture. Each handler is leaner, easier to read, and easier to test. For users, this results in a more reliable redirect: error messages are displayed consistently, HTTP status codes match the expected behaviour exactly, and unauthorised methods do not cause side effects.

This also gives the URL shortener additional robustness at the protocol level. Error handling is traceable, behaviour is transparent, and server components follow the same principles of clarity and reusability introduced in the UI. In this way, the system’s technical integrity is strengthened, as is user confidence in its stability.

Conclusion: User Comfort Meets Clean Design
#

With the completion of this development step, the URL shortener has developed into a much more mature system – both technically and conceptually. What started as a simple platform for creating and managing individual shortlinks has become a full-fledged application that balances user needs, security, and maintainability. The transition from a one-alias logic to a flexible multi-alias approach is probably the most visible progress. Still, the real strength of this update lies in the design’s consistent coherence.

From the user’s perspective, a tool is now available that makes workflows more fluid, consistent, and traceable. The detail-dialogue and the Create View form a harmonious pair: both use the same editor, the exact validation mechanisms and the same event flow. Actions are immediately visible, and changes are automatically displayed. The result is a surface that hides its technical complexity and instead focuses on efficiency and clarity.

A clear development is also noticeable on the architectural level. The interplay of Vaadin EventBus, component-based UI structure and centralised HTTP handling has resulted in a maintenance-friendly, extensible system. Every level – from the user interface to the validation logic to the server – follows the same principles: clear responsibilities, loose coupling, and transparent behaviour. This uniformity is evident not only in the code but above all in everyday use.

This step thus sets a clear benchmark for future project expansions. The concept of multiple aliases, the consistent reactivity of the UI, and the clean server design will not remain isolated features in the coming development phases; they will serve as a structural basis. Working on the user experience has shown that technical design and interaction quality are not mutually exclusive – on the contrary, they reinforce each other when they are consistently coordinated.

Cheers Sven

Related

Advent Calendar 2025 - Introduction of multiple aliases - Part 1

Introduction: More convenience for users # With today’s development milestone for the URL Shortener project, a crucial improvement has been achieved, significantly enhancing the user experience. Up to this point, working with short URLs was functional, but in many ways it was still linear: each destination URL was assigned exactly one alias. This meant users had to create a new short URL for each context or campaign, even when the destination was identical. While this approach was simple, it wasn’t sufficiently flexible to meet real-world application requirements.

Advent Calendar - 2025 - From Grid to Detail: Understanding the User Experience in the Short-URL Manager

The current UI from the user’s point of view # On the first call, the user lands in the overview. The site is built on a Vaadin grid, whose header contains a search bar, paging controls, and a small settings button with a gear icon. The most essential flow begins with the table displaying immediately understandable columns: the shortcode as a clearly typographically separated monospace value with copy action, the original URL as a clickable link, a creation time in local format, and an expiration badge that visually communicates semantic states such as “Expired”, “Today” or “in n days” via theme colours. The whole thing is designed for quick viewing and efficient one-handed operation: a click on a data record opens the detailed dialogue if required; a right-click or the context menu offers direct quick actions; and the gear button can be used to show or hide visible columns live.

Advent Calendar - 2025 - ColumnVisibilityDialog - Part 2

Server-Side Extension: PreferencesHandler and REST Interfaces # The server-side extension for dynamic column visibility follows the same design logic as the UI: simplicity, clear accountability, and a precise data flow. While the OverviewView and the ColumnVisibilityDialog form the interface for the interaction, several specialized REST handlers handle the processing and persistence of the user settings. Their job is to process incoming JSON requests, validate them, translate them into domain operations, and return or store the current state.

Advent Calendar - 2025 - Detail Dialog - Part 2

Client contract from a UI perspective # In this project, the user interface not only serves as a graphical layer on top of the backend, but is also part of the overall contract between the user, the client, and the server. This part focuses on the data flow from the UI’s perspective: how inputs are translated into structured requests, how the client forwards them, and what feedback the user interface processes.