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

de.sayayi.lib.protocol.spi.AbstractProtocol Maven / Gradle / Ivy

There is a newer version: 1.5.0
Show newest version
/*
 * Copyright 2019 Jeroen Gremmen
 *
 * 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 de.sayayi.lib.protocol.spi;

import de.sayayi.lib.protocol.Level;
import de.sayayi.lib.protocol.Protocol;
import de.sayayi.lib.protocol.Protocol.ProtocolMessageBuilder;
import de.sayayi.lib.protocol.ProtocolEntry;
import de.sayayi.lib.protocol.ProtocolFactory;
import de.sayayi.lib.protocol.ProtocolFormatter;
import de.sayayi.lib.protocol.ProtocolGroup;
import de.sayayi.lib.protocol.ProtocolIterator.DepthEntry;
import de.sayayi.lib.protocol.ProtocolIterator.GroupEndEntry;
import de.sayayi.lib.protocol.ProtocolIterator.GroupStartEntry;
import de.sayayi.lib.protocol.ProtocolIterator.MessageEntry;
import de.sayayi.lib.protocol.ProtocolIterator.ProtocolEnd;
import de.sayayi.lib.protocol.ProtocolIterator.ProtocolStart;
import de.sayayi.lib.protocol.TagSelector;
import de.sayayi.lib.protocol.matcher.MessageMatcher;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.val;
import lombok.var;

import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;

import static java.util.Spliterator.DISTINCT;
import static java.util.Spliterator.NONNULL;
import static java.util.Spliterator.ORDERED;
import static java.util.Spliterator.SORTED;


/**
 * @param   internal message object type
 *
 * @author Jeroen Gremmen
 */
@EqualsAndHashCode(onlyExplicitlyIncluded = true, doNotUseGetters = true, callSuper = false)
abstract class AbstractProtocol>
    implements Protocol, InternalProtocolQueryable
{
  private static final AtomicInteger PROTOCOL_ID = new AtomicInteger(0);

  @EqualsAndHashCode.Include
  @Getter private final int id;

  @Getter final @NotNull ProtocolFactory factory;

  final @NotNull ParameterMap parameterMap;
  final @NotNull List> entries;
  final @NotNull Map> tagPropagationMap;


  protected AbstractProtocol(@NotNull ProtocolFactory factory, ParameterMap parentParameterMap)
  {
    this.factory = factory;

    id = PROTOCOL_ID.incrementAndGet();
    parameterMap = new ParameterMap(parentParameterMap);
    entries = new ArrayList<>(8);
    tagPropagationMap = new HashMap<>(8);
  }


  protected @NotNull Set getPropagatedTags(@NotNull Set tags)
  {
    if (tagPropagationMap.isEmpty())
      return tags;

    val collectedPropagatedTagDefs = new TreeSet<>(tags);

    for(val tagPropagation: tagPropagationMap.entrySet())
      if (tagPropagation.getKey().match(collectedPropagatedTagDefs))
        collectedPropagatedTagDefs.addAll(tagPropagation.getValue());

    return collectedPropagatedTagDefs;
  }


  public abstract @NotNull B add(@NotNull Level level);


  @Override
  public boolean matches0(@NotNull Level levelLimit, @NotNull MessageMatcher matcher)
  {
    for(val entry: entries)
      if (entry.matches0(levelLimit, matcher))
        return true;

    return false;
  }


  @NotNull List> getEntries(@NotNull Level levelLimit,
                                             @NotNull MessageMatcher matcher)
  {
    val filteredEntries = new ArrayList>();

    for(val entry: entries)
      if (entry.matches0(levelLimit, matcher))
      {
        if (entry instanceof InternalProtocolEntry.Group)
        {
          filteredEntries.add(ProtocolGroupEntryAdapter.from(levelLimit,
              (InternalProtocolEntry.Group)entry));
        }
        else
        {
          filteredEntries.add(ProtocolMessageEntryAdapter.from(levelLimit,
              (InternalProtocolEntry.Message)entry));
        }
      }

    return filteredEntries;
  }


  @Override
  public int getVisibleEntryCount0(@NotNull Level levelLimit, @NotNull MessageMatcher matcher)
  {
    var count = 0;

    for(val entry: entries)
      count += entry.getVisibleEntryCount0(levelLimit, matcher);

    return count;
  }


  @Override
  public @NotNull Optional> getGroupByName(@NotNull String name)
  {
    for(final Iterator> groupIterator = groupIterator(); groupIterator.hasNext();)
    {
      val result = groupIterator.next().getGroupByName(name);
      if (result.isPresent())
        return result;
    }

    return Optional.empty();
  }


  @Override
  public void forEachGroupByRegex(@NotNull String regex, @NotNull Consumer> action) {
    groupIterator().forEachRemaining(group -> group.forEachGroupByRegex(regex, action));
  }


  @Override
  public @NotNull ProtocolGroup createGroup()
  {
    @SuppressWarnings("unchecked")
    val group = new ProtocolGroupImpl<>((AbstractProtocol>)this);

    entries.add(group);

    return group;
  }


  @Override
  public @NotNull Spliterator> spliterator(@NotNull MessageMatcher matcher) {
    return new ProtocolSpliterator<>(iterator(matcher));
  }


  @Override
  public @NotNull Iterator> groupIterator() {
    return new GroupIterator();
  }


  @Override
  public @NotNull Spliterator> groupSpliterator()
  {
    return Spliterators.spliterator(groupIterator(), entries.size(),
        DISTINCT | ORDERED | SORTED | NONNULL);
  }


  @Override
  public  R format(@NotNull ProtocolFormatter formatter, @NotNull MessageMatcher matcher)
  {
    // initialize formatter
    formatter.init(factory, matcher,
        countGroupDepth() + (isProtocolGroup() ? 1 : 0));

    iterator(matcher).forEachRemaining(entry -> {
      if (entry instanceof MessageEntry)
        formatter.message((MessageEntry)entry);
      else if (entry instanceof GroupStartEntry)
        formatter.groupStart((GroupStartEntry)entry);
      else if (entry instanceof GroupEndEntry)
        formatter.groupEnd((GroupEndEntry)entry);
      else if (entry instanceof ProtocolStart)
        formatter.protocolStart();
      else if (entry instanceof ProtocolEnd)
        formatter.protocolEnd();
    });

    return formatter.getResult();
  }


  int countGroupDepth()
  {
    var depth = 0;

    for(val entry: entries)
      if (entry instanceof ProtocolGroupImpl)
        depth = Math.max(depth, 1 + ((ProtocolGroupImpl)entry).countGroupDepth());

    return depth;
  }




  /**
   * @since 0.7.0
   */
  protected final class GroupIterator implements Iterator>
  {
    private final Iterator> iterator;
    private ProtocolGroup next;


    private GroupIterator()
    {
      iterator = entries.iterator();
      findNext();
    }


    private void findNext()
    {
      while(iterator.hasNext())
      {
        val entry = iterator.next();
        if (entry instanceof ProtocolGroup)
        {
          //noinspection unchecked
          next = (ProtocolGroup)entry;
          return;
        }
      }

      next = null;
    }


    @Override
    public boolean hasNext() {
      return next != null;
    }


    @Override
    public ProtocolGroup next()
    {
      if (!hasNext())
        throw new NoSuchElementException();

      val nextGroup = next;
      findNext();

      return nextGroup;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy