Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Descriptor tree & other validation changes
  • Loading branch information
ankitk-me committed Jan 7, 2024
commit 682bb4418a5206a0d5eca083d5fd54608de7f67c
2 changes: 1 addition & 1 deletion incubator/validator-protobuf/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<jacoco.coverage.ratio>0.88</jacoco.coverage.ratio>
<jacoco.coverage.ratio>0.84</jacoco.coverage.ratio>
<jacoco.missed.count>0</jacoco.missed.count>
</properties>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright 2021-2023 Aklivity Inc
*
* Licensed under the Aklivity Community License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* https://www.aklivity.io/aklivity-community-license/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package io.aklivity.zilla.runtime.validator.protobuf;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.protobuf.Descriptors;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FileDescriptor;

public class DescriptorTree
{
protected final Map<String, DescriptorTree> children;
protected final List<Integer> indexes;

protected Descriptors.Descriptor descriptor;
protected String name;

private DescriptorTree()
{
this.children = new LinkedHashMap<>();
this.indexes = new LinkedList<>();
}

protected DescriptorTree(
FileDescriptor fileDescriptors)
{
this();
this.name = fileDescriptors.getPackage();
for (Descriptor descriptor : fileDescriptors.getMessageTypes())
{
addDescriptor(descriptor);
addNestedDescriptors(descriptor);
}
}

protected DescriptorTree findByName(
String path)
{
DescriptorTree current = this;
int start = 0;
int end;

while (start < path.length())
{
end = path.indexOf('.', start);
if (end == -1)
{
end = path.length();
}

String part = path.substring(start, end);
current = current.children.get(part);

if (current == null)
{
break;
}
start = end + 1;
}
return current;
}

protected DescriptorTree findByIndexes(
List<Integer> indexes)
{
DescriptorTree current = this;

for (Integer index : indexes)
{
current = current.getChild(index);
if (current == null)
{
return null;
}
}
return current;
}

private DescriptorTree findParent(
String path)
{
int index = path.lastIndexOf('.');
String part = index >= 0 ? path.substring(index + 1) : path;
return this.children.getOrDefault(part, null);
}

private DescriptorTree getChild(
int index)
{
DescriptorTree tree = this;
int currentIndex = 0;
for (Map.Entry<String, DescriptorTree> entry : children.entrySet())
{
if (currentIndex == index)
{
tree = entry.getValue();
break;
}
currentIndex++;
}
return tree;
}

private void addNestedDescriptor(
Descriptor parent,
int index)
{
DescriptorTree parentNode = findParent(parent.getFullName());
if (parentNode != null)
{
Descriptors.Descriptor nestedDescriptor = parent.getNestedTypes().get(index);
parentNode.addDescriptor(nestedDescriptor);
parentNode.addNestedDescriptors(nestedDescriptor);
}
}

private void addDescriptor(
Descriptor descriptor)
{
DescriptorTree node = new DescriptorTree();
node.descriptor = descriptor;
node.name = name;
node.indexes.addAll(this.indexes);
node.indexes.add(this.children.size());
this.children.put(descriptor.getName(), node);
}

private void addNestedDescriptors(Descriptor descriptor)
{
for (int i = 0; i < descriptor.getNestedTypes().size(); i++)
{
addNestedDescriptor(descriptor, i);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,6 @@ public void enterMessageDef(
builder.setName(name);
messageHierarchy.push(name);

String parentNodes = String.join(".", messageHierarchy);
System.out.println("Message Hierarchy: " + parentNodes);

for (Protobuf3Parser.MessageElementContext element : ctx.messageBody().messageElement())
{
if (element.field() != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@
*/
package io.aklivity.zilla.runtime.validator.protobuf;

import static io.aklivity.zilla.runtime.engine.catalog.CatalogHandler.NO_SCHEMA_ID;

import java.io.IOException;
import java.util.function.LongFunction;

import org.agrona.DirectBuffer;

import com.google.protobuf.Descriptors;
import com.google.protobuf.DynamicMessage;

import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler;
import io.aklivity.zilla.runtime.engine.validator.FragmentValidator;
import io.aklivity.zilla.runtime.engine.validator.ValueValidator;
Expand Down Expand Up @@ -45,22 +51,95 @@ public int padding(

@Override
public int validate(
int flags,
DirectBuffer data,
int index,
int length,
FragmentConsumer next)
ValueConsumer next)
{
return 0;
return validateComplete(data, index, length, next);
}

@Override
public int validate(
int flags,
DirectBuffer data,
int index,
int length,
FragmentConsumer next)
{
return (flags & FLAGS_FIN) != 0x00
? validateComplete(data, index, length, (b, i, l) -> next.accept(FLAGS_COMPLETE, b, i, l))
: 0;
}

private int validateComplete(
DirectBuffer data,
int index,
int length,
ValueConsumer next)
{
return handler.decode(data, index, length, next, this::decodePayload);
}

private int decodePayload(
int schemaId,
DirectBuffer data,
int index,
int length,
ValueConsumer next)
{
return 0;
int valLength = -1;

if (schemaId == NO_SCHEMA_ID)
{
if (catalog.id != NO_SCHEMA_ID)
{
schemaId = catalog.id;
}
else
{
schemaId = handler.resolve(subject, catalog.version);
}
}

int progress = decodeIndexes(data, index, length);
int currentIndex = index + progress;
int remainingLength = length - progress;

if (validate(schemaId, data, currentIndex, remainingLength))
{
next.accept(data, currentIndex, remainingLength);
valLength = remainingLength;
}
return valLength;
}

private boolean validate(
int schemaId,
DirectBuffer buffer,
int index,
int length)
{
boolean status = false;
Descriptors.FileDescriptor fileDescriptor = supplyDescriptor(schemaId);
if (fileDescriptor != null)
{
DescriptorTree tree = new DescriptorTree(fileDescriptor).findByIndexes(indexes);
if (tree != null)
{
Descriptors.Descriptor descriptor = tree.descriptor;
try
{
in.wrap(buffer, index, length);
DynamicMessage message = DynamicMessage.parseFrom(descriptor, in);
status = message.getUnknownFields().asMap().isEmpty();
}
catch (IOException e)
{
e.printStackTrace();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
catch (IOException e)
{
e.printStackTrace();
}
catch (IOException ex)
{
ex.printStackTrace();
}

We typically use ex for exception variables.

}
}
return status;
}
}
Loading