All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.photon.api.pathdescriptor.PathDescriptorPart Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014-2024 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * 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.
 */
package com.helger.photon.api.pathdescriptor;

import java.io.Serializable;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.collection.CollectionHelper;
import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.equals.EqualsHelper;
import com.helger.commons.hashcode.HashCodeGenerator;
import com.helger.commons.string.StringHelper;
import com.helger.commons.string.ToStringGenerator;

/**
 * This class keeps a single path part. This can be either a static string or a
 * variable argument with optional constraints.
 *
 * @author Philip Helger
 */
@Immutable
public final class PathDescriptorPart implements Serializable
{
  public static final String VARIABLE_START = "{";
  public static final String VARIABLE_END = "}";
  public static final char CONSTRAINT_SEPARATOR = ':';
  private static final int MIN_VARIABLE_LENGTH = VARIABLE_START.length () + VARIABLE_END.length ();

  private final boolean m_bIsVariable;
  private final String m_sName;
  private final ICommonsList  m_aVariableConstraints;

  private PathDescriptorPart (final boolean bIsVariable,
                              @Nonnull @Nonempty final String sName,
                              @Nullable final ICommonsList  aVariableConstraints)
  {
    ValueEnforcer.notEmpty (sName, "Name");
    m_bIsVariable = bIsVariable;
    m_sName = sName;
    m_aVariableConstraints = aVariableConstraints;
  }

  /**
   * @return true if this is variable path part, false
   *         if it is static
   */
  public boolean isVariable ()
  {
    return m_bIsVariable;
  }

  /**
   * @return Either the static string or the name of the variable. Neither
   *         null nor empty.
   */
  @Nonnull
  @Nonempty
  public String getName ()
  {
    return m_sName;
  }

  /**
   * @return The optional variable constraints. Only relevant if this is a
   *         variable path part. Never null but maybe empty.
   */
  @Nonnull
  @ReturnsMutableCopy
  public ICommonsList  getAllVariableConstraints ()
  {
    return new CommonsArrayList <> (m_aVariableConstraints);
  }

  /**
   * Check if the passed path part matches the requirements of this object. If
   * this is a static path part, it's a simple string equals. For variable path
   * parts, all the constraints (if any) must be fulfilled.
   *
   * @param sPathPart
   *        The string to be checked.
   * @return true if the passed string matches, false
   *         otherwise.
   */
  public boolean matches (@Nonnull final String sPathPart)
  {
    if (m_bIsVariable)
    {
      // Check additional constraints
      if (m_aVariableConstraints != null)
        for (final PathDescriptorVariableConstraint aVariableConstraint : m_aVariableConstraints)
          if (!aVariableConstraint.matches (sPathPart))
            return false;

      // Variables match if all constraints match
      return true;
    }

    // Static path part - string equals
    return m_sName.equals (sPathPart);
  }

  @Nonnull
  @Nonempty
  public String getAsURLString ()
  {
    if (m_bIsVariable)
    {
      final StringBuilder aSB = new StringBuilder ();
      aSB.append (VARIABLE_START).append (m_sName);
      if (m_aVariableConstraints != null)
        for (final PathDescriptorVariableConstraint aVariableConstraint : m_aVariableConstraints)
          aSB.append (CONSTRAINT_SEPARATOR).append (aVariableConstraint.getAsURLString ());
      aSB.append (VARIABLE_END);
      return aSB.toString ();
    }

    // Static :)
    return m_sName;
  }

  @Override
  public boolean equals (final Object o)
  {
    if (o == this)
      return true;
    if (o == null || !getClass ().equals (o.getClass ()))
      return false;
    final PathDescriptorPart rhs = (PathDescriptorPart) o;
    return m_bIsVariable == rhs.m_bIsVariable &&
           m_sName.equals (rhs.m_sName) &&
           EqualsHelper.equals (m_aVariableConstraints, rhs.m_aVariableConstraints);
  }

  @Override
  public int hashCode ()
  {
    return new HashCodeGenerator (this).append (m_bIsVariable).append (m_sName).append (m_aVariableConstraints).getHashCode ();
  }

  @Override
  public String toString ()
  {
    return new ToStringGenerator (null).append ("IsVariable", m_bIsVariable)
                                       .append ("Name", m_sName)
                                       .appendIf ("VariableConstraints", m_aVariableConstraints, CollectionHelper::isNotEmpty)
                                       .getToString ();
  }

  @Nonnull
  @Nonempty
  public static String getVariableName (@Nonnull @Nonempty final String sName)
  {
    ValueEnforcer.notEmpty (sName, "Name");
    ValueEnforcer.isFalse ( () -> sName.startsWith (VARIABLE_START), () -> "Name is already a variable: '" + sName + "'");
    return VARIABLE_START + sName + VARIABLE_END;
  }

  @Nonnull
  public static PathDescriptorPart create (@Nonnull @Nonempty final String sPathPart)
  {
    ValueEnforcer.notEmpty (sPathPart, "PathPart");
    if (sPathPart.length () > MIN_VARIABLE_LENGTH && sPathPart.startsWith (VARIABLE_START) && sPathPart.endsWith (VARIABLE_END))
    {
      // It's a variable

      // Remove "{" and "}"
      final String sVariablePart = sPathPart.substring (VARIABLE_START.length (), sPathPart.length () - VARIABLE_END.length ());

      // Check for additional variable constraints
      // Example: {path:regex=^[0-9]+$}
      final ICommonsList  aVarPartParts = StringHelper.getExploded (CONSTRAINT_SEPARATOR, sVariablePart);

      // Variable name is always first
      final String sVariableName = aVarPartParts.get (0);

      // Constraints come afterwars
      ICommonsList  aVariableConstraints = null;
      final int nVarPartPartCount = aVarPartParts.size ();
      if (nVarPartPartCount > 1)
      {
        // Skip var name
        for (int i = 1; i < nVarPartPartCount; ++i)
        {
          final String sVariableConstraint = aVarPartParts.get (i);
          final PathDescriptorVariableConstraint aConstraint = PathDescriptorVariableConstraint.createOrNull (sVariableConstraint);
          if (aConstraint != null)
          {
            if (aVariableConstraints == null)
              aVariableConstraints = new CommonsArrayList <> ();
            aVariableConstraints.add (aConstraint);
          }
        }
      }

      // It's a variable argument - cut prefix
      return new PathDescriptorPart (true, sVariableName, aVariableConstraints);
    }
    return new PathDescriptorPart (false, sPathPart, null);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy