Skip to content

Commit

Permalink
feat(codegen): streamline protocol implementations by providing conve…
Browse files Browse the repository at this point in the history
…nience methods
  • Loading branch information
sruehl committed May 21, 2022
1 parent 5418f8e commit fa0ce26
Show file tree
Hide file tree
Showing 24 changed files with 283 additions and 323 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.plc4x.plugins.codegenerator.language.mspec.model.fields.*;
import org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.*;
import org.apache.plc4x.plugins.codegenerator.language.mspec.model.terms.WildcardTerm;
import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
import org.apache.plc4x.plugins.codegenerator.types.definitions.*;
import org.apache.plc4x.plugins.codegenerator.types.enums.EnumValue;
import org.apache.plc4x.plugins.codegenerator.types.fields.ArrayField;
Expand Down Expand Up @@ -60,9 +61,9 @@ public class MessageFormatListener extends MSpecBaseListener implements LazyType

protected Map<String, TypeDefinition> types;

protected Map<String, List<Consumer<TypeDefinition>>> typeDefinitionConsumers = new HashMap<>();
protected Map<String, List<Consumer<TypeDefinition>>> typeDefinitionConsumers;

private Stack<Map<String, Term>> batchSetAttributes = new Stack<>();
private final Stack<Map<String, Term>> batchSetAttributes = new Stack<>();

public Deque<List<Field>> getParserContexts() {
return parserContexts;
Expand All @@ -74,11 +75,20 @@ public Deque<List<EnumValue>> getEnumContexts() {

private String currentTypeName;

public MessageFormatListener() {
types = new HashMap<>();
typeDefinitionConsumers = new HashMap<>();
}

public MessageFormatListener(TypeContext exitingTypeContext) {
types = new HashMap<>(exitingTypeContext.getTypeDefinitions());
typeDefinitionConsumers = new HashMap<>(exitingTypeContext.getUnresolvedTypeReferences());
}

@Override
public void enterFile(MSpecParser.FileContext ctx) {
parserContexts = new LinkedList<>();
enumContexts = new LinkedList<>();
types = new HashMap<>();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.apache.plc4x.plugins.codegenerator.language.mspec.MSpecLexer;
import org.apache.plc4x.plugins.codegenerator.language.mspec.MSpecParser;
import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ValidatableTypeContext;
import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
import org.slf4j.Logger;
Expand All @@ -40,35 +41,41 @@ public class MessageFormatParser {

private static final Logger LOGGER = LoggerFactory.getLogger(MessageFormatParser.class);

public TypeContext parse(InputStream source) {
return parse(source, new HashMap<>());
public ValidatableTypeContext parse(InputStream source) {
return parse(source, null);
}

public TypeContext parse(InputStream source, Map<String, List<Consumer<TypeDefinition>>> unresolvedTypeReferences) {
return parse(source, Collections.emptyMap(), unresolvedTypeReferences);
}

public TypeContext parse(InputStream source, Map<String, TypeDefinition> parsedTypedReferences, Map<String, List<Consumer<TypeDefinition>>> unresolvedTypeReferences) {
public ValidatableTypeContext parse(InputStream source, TypeContext existingTypeContext) {
LOGGER.debug("Parsing: {}", source);
MSpecLexer lexer;
try {
lexer = new MSpecLexer(CharStreams.fromStream(source));
} catch (IOException e) {
throw new RuntimeException(e);
}
MessageFormatListener listener = new MessageFormatListener();
if (unresolvedTypeReferences != null) {
LOGGER.debug("Continue with {} unresolvedTypeReferences", unresolvedTypeReferences.size());
listener.typeDefinitionConsumers = unresolvedTypeReferences;
MessageFormatListener listener;
if (existingTypeContext == null) {
listener = new MessageFormatListener();
} else {
if (LOGGER.isDebugEnabled()) {
Map<String, TypeDefinition> exitingTypeDefinitions = existingTypeContext.getTypeDefinitions();
if (exitingTypeDefinitions != null) {
LOGGER.debug("Continue with {} exitingTypeDefinitions", exitingTypeDefinitions.size());
}
Map<String, List<Consumer<TypeDefinition>>> unresolvedTypeReferences = existingTypeContext.getUnresolvedTypeReferences();
if (unresolvedTypeReferences != null) {
LOGGER.debug("Continue with {} unresolvedTypeReferences", unresolvedTypeReferences.size());
}
}

listener = new MessageFormatListener(existingTypeContext);
}

new ParseTreeWalker().walk(listener, new MSpecParser(new CommonTokenStream(lexer)).file());
if (!parsedTypedReferences.isEmpty()) {
LOGGER.info("connecting open consumers with passed types");
parsedTypedReferences.forEach(listener::dispatchType);
}
LOGGER.info("Checking for open consumers");
listener.typeDefinitionConsumers.forEach((key, value) -> LOGGER.warn("{} has {} open consumers", key, value.size()));
return new TypeContext() {
return new ValidatableTypeContext() {

@Override
public Map<String, TypeDefinition> getTypeDefinitions() {
return listener.types;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 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.
*/
package org.apache.plc4x.plugins.codegenerator.language.mspec.protocol;

import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;

import java.io.InputStream;
import java.util.Objects;

public interface ProtocolHelpers extends Protocol {

/**
* Returns a mspec stream by using {@link Protocol#getName()}
*
* @return the {@link InputStream} of the referenced {@code mspecName}
* @throws GenerationException if the mspec can't be found.
*/
default InputStream getMspecStream() throws GenerationException {
return getMspecStream(getName());
}

/**
* Returns a mspec stream for a give name
*
* @param mspecName the name without the .mspec extension
* @return the {@link InputStream} of the referenced {@code mspecName}
* @throws GenerationException if the mspec can't be found.
*/
default InputStream getMspecStream(String mspecName) throws GenerationException {
Objects.requireNonNull(mspecName, "mspecName must be set");
String versionSubPath = getVersion().map(version -> "/v" + version).orElse("");
String packageName = getPackageName();
String path = "/protocols/" + packageName + versionSubPath + "/" + mspecName + ".mspec";
InputStream inputStream = getClass().getResourceAsStream(path);
if (inputStream == null) {
throw new GenerationException("Error loading " + mspecName + " schema for protocol '" + getName() + "' (path " + path + ")");
}
return inputStream;
}

/**
* @return {@link Protocol#getName()} in sanitized form
*/
default String getSanitizedName() {
return Objects.requireNonNull(getName(), "protocol should return useful value at getName()")
// Replace - with emptiness
.replaceAll("-", "");
}

/**
* @return the package name
*/
default String getPackageName() {
return getSanitizedName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.
*/
package org.apache.plc4x.plugins.codegenerator.language.mspec.protocol;

import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;

public interface ValidatableTypeContext extends TypeContext {

/**
* validates the {@link TypeContext}
*
* @throws GenerationException if {@link TypeContext}
*/
default void validate() throws GenerationException {
// TODO: check that we have at least of parsed type
if (getUnresolvedTypeReferences().size() > 0) {
throw new GenerationException("Unresolved types left: " + getUnresolvedTypeReferences());
}
}
}
6 changes: 3 additions & 3 deletions plc4go/internal/plc4go/knxnetip/readwrite/ParserHelper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions plc4go/internal/plc4go/knxnetip/readwrite/XmlParserHelper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@
package org.apache.plc4x.protocol.abeth;

import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ProtocolHelpers;
import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ValidatableTypeContext;
import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;

import java.io.InputStream;
import java.util.Map;

public class ABETHProtocol implements Protocol {
public class ABETHProtocol implements Protocol, ProtocolHelpers {

@Override
public String getName() {
Expand All @@ -36,14 +34,8 @@ public String getName() {

@Override
public TypeContext getTypeContext() throws GenerationException {
InputStream schemaInputStream = ABETHProtocol.class.getResourceAsStream("/protocols/abeth/ab-eth.mspec");
if(schemaInputStream == null) {
throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
}
TypeContext typeContext = new MessageFormatParser().parse(schemaInputStream);
if (typeContext.getUnresolvedTypeReferences().size() > 0) {
throw new GenerationException("Unresolved types left: " + typeContext.getUnresolvedTypeReferences());
}
ValidatableTypeContext typeContext = new MessageFormatParser().parse(getMspecStream());
typeContext.validate();
return typeContext;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@
package org.apache.plc4x.protocol.ads;

import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ProtocolHelpers;
import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ValidatableTypeContext;
import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;

import java.io.InputStream;
import java.util.Map;

/**
* Little helper protocol used to communicate over UDP with Beckhoff hardware.
*/
public class ADSDiscoveryProtocol implements Protocol {
public class ADSDiscoveryProtocol implements Protocol, ProtocolHelpers {

@Override
public String getName() {
Expand All @@ -39,15 +39,13 @@ public String getName() {

@Override
public TypeContext getTypeContext() throws GenerationException {
InputStream schemaInputStream = ADSDiscoveryProtocol.class.getResourceAsStream("/protocols/ads/ads-discovery.mspec");
if(schemaInputStream == null) {
throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
}
TypeContext typeContext = new MessageFormatParser().parse(schemaInputStream);
if (typeContext.getUnresolvedTypeReferences().size() > 0) {
throw new GenerationException("Unresolved types left: " + typeContext.getUnresolvedTypeReferences());
}
ValidatableTypeContext typeContext = new MessageFormatParser().parse(getMspecStream("ads-discovery"));
typeContext.validate();
return typeContext;
}

@Override
public String getPackageName() {
return "ads";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@
package org.apache.plc4x.protocol.ads;

import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ProtocolHelpers;
import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ValidatableTypeContext;
import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;

import java.io.InputStream;
import java.util.Map;

public class ADSProtocol implements Protocol {
public class ADSProtocol implements Protocol, ProtocolHelpers {

@Override
public String getName() {
Expand All @@ -36,14 +34,8 @@ public String getName() {

@Override
public TypeContext getTypeContext() throws GenerationException {
InputStream schemaInputStream = ADSProtocol.class.getResourceAsStream("/protocols/ads/ads.mspec");
if(schemaInputStream == null) {
throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
}
TypeContext typeContext = new MessageFormatParser().parse(schemaInputStream);
if (typeContext.getUnresolvedTypeReferences().size() > 0) {
throw new GenerationException("Unresolved types left: " + typeContext.getUnresolvedTypeReferences());
}
ValidatableTypeContext typeContext = new MessageFormatParser().parse(getMspecStream());
typeContext.validate();
return typeContext;
}

Expand Down
Loading

0 comments on commit fa0ce26

Please sign in to comment.