You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2022/08/08 13:32:51 UTC

[plc4x] 02/02: refactor(plc4go): streamlined plc_browse api

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit e0cc944d4e20ae9e510fdd9468c0202856298d37
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Mon Aug 8 15:32:42 2022 +0200

    refactor(plc4go): streamlined plc_browse api
---
 .../discovery/hello_world_plc4go_knx_discovery.go  |   8 +-
 plc4go/internal/cbus/Browser.go                    |  54 +++++++++
 plc4go/internal/cbus/Connection.go                 |   3 +-
 plc4go/internal/knxnetip/Browser.go                |  43 +++----
 plc4go/internal/spi/model/DefaultBrowseRequest.go  |  76 ------------
 plc4go/internal/spi/model/DefaultPlcBrowseEvent.go |  10 +-
 .../spi/model/DefaultPlcBrowseQueryResult.go       |  10 +-
 .../internal/spi/model/DefaultPlcBrowseRequest.go  | 128 +++++++++++++++++++++
 .../internal/spi/model/DefaultPlcBrowseResponse.go |  26 ++++-
 plc4go/pkg/api/model/plc_browse.go                 |  40 ++++---
 plc4go/pkg/api/model/plc_connection_metadata.go    |   2 -
 plc4go/pkg/api/model/plc_read.go                   |   4 +-
 plc4go/pkg/api/model/plc_write.go                  |   4 +-
 plc4go/tools/plc4xbrowser/commands.go              |   2 +-
 14 files changed, 267 insertions(+), 143 deletions(-)

diff --git a/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go b/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go
index 79bbe4198..5febd5785 100644
--- a/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go
+++ b/plc4go/examples/knx/discovery/hello_world_plc4go_knx_discovery.go
@@ -70,9 +70,9 @@ func main() {
 
 		// Try to find all KNX devices on the current network
 		browseRequest, err := connection.BrowseRequestBuilder().
-			AddItem("allDevices", "[1-15].[1-15].[0-255]").
-			//AddItem("allMyDevices", "[1-3].[1-6].[0-60]").
-			//AddItem("onlyOneDevice", "1.1.20")
+			AddQuery("allDevices", "[1-15].[1-15].[0-255]").
+			//AddQuery("allMyDevices", "[1-3].[1-6].[0-60]").
+			//AddQuery("onlyOneDevice", "1.1.20")
 			Build()
 		if err != nil {
 			log.Error().Err(err).Msg("error creating browse request")
@@ -85,7 +85,7 @@ func main() {
 
 			// Try to get all the com-objects and the group addresses they are attached to.
 			browseRequest, err := connection.BrowseRequestBuilder().
-				AddItem("comObjects", knxAddress+"#com-obj").
+				AddQuery("comObjects", knxAddress+"#com-obj").
 				Build()
 			if err != nil {
 				log.Error().Err(err).Msg("error creating read request")
diff --git a/plc4go/internal/cbus/Browser.go b/plc4go/internal/cbus/Browser.go
new file mode 100644
index 000000000..39c5ccbe0
--- /dev/null
+++ b/plc4go/internal/cbus/Browser.go
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ *   https://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 cbus
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
+)
+
+type Browser struct {
+	connection      *Connection
+	messageCodec    spi.MessageCodec
+	sequenceCounter uint8
+}
+
+func NewBrowser(connection *Connection, messageCodec spi.MessageCodec) *Browser {
+	return &Browser{
+		connection:      connection,
+		messageCodec:    messageCodec,
+		sequenceCounter: 0,
+	}
+}
+
+func (m Browser) Browse(browseRequest apiModel.PlcBrowseRequest) <-chan apiModel.PlcBrowseRequestResult {
+	return m.BrowseWithInterceptor(browseRequest, func(result apiModel.PlcBrowseEvent) bool {
+		return true
+	})
+}
+
+func (m Browser) BrowseWithInterceptor(browseRequest apiModel.PlcBrowseRequest, interceptor func(result apiModel.PlcBrowseEvent) bool) <-chan apiModel.PlcBrowseRequestResult {
+	result := make(chan apiModel.PlcBrowseRequestResult)
+
+	go func() {
+		// TODO: implement me
+	}()
+	return result
+}
diff --git a/plc4go/internal/cbus/Connection.go b/plc4go/internal/cbus/Connection.go
index e45928470..f5dd9895f 100644
--- a/plc4go/internal/cbus/Connection.go
+++ b/plc4go/internal/cbus/Connection.go
@@ -157,8 +157,7 @@ func (c *Connection) UnsubscriptionRequestBuilder() apiModel.PlcUnsubscriptionRe
 }
 
 func (c *Connection) BrowseRequestBuilder() apiModel.PlcBrowseRequestBuilder {
-	// TODO: where do we get the browser from
-	return internalModel.NewDefaultPlcBrowseRequestBuilder(nil)
+	return internalModel.NewDefaultPlcBrowseRequestBuilder(NewBrowser(c, c.messageCodec))
 }
 
 func (c *Connection) addSubscriber(subscriber *Subscriber) {
diff --git a/plc4go/internal/knxnetip/Browser.go b/plc4go/internal/knxnetip/Browser.go
index a782ed1f4..247ca225b 100644
--- a/plc4go/internal/knxnetip/Browser.go
+++ b/plc4go/internal/knxnetip/Browser.go
@@ -67,43 +67,38 @@ func (m Browser) BrowseWithInterceptor(browseRequest apiModel.PlcBrowseRequest,
 	}
 
 	go func() {
-		results := map[string][]apiModel.PlcBrowseQueryResult{}
-		for _, queryName := range browseRequest.GetQueryNames() {
-			queryString := browseRequest.GetQueryString(queryName)
-			field, err := m.connection.fieldHandler.ParseQuery(queryString)
-			if err != nil {
-				sendResult(nil, err)
-				return
-			}
+		responseCodes := map[string]apiModel.PlcResponseCode{}
+		results := map[string][]apiModel.PlcBrowseFoundField{}
+		for _, fieldName := range browseRequest.GetFieldNames() {
+			field := browseRequest.GetField(fieldName)
 
 			switch field.(type) {
 			case DeviceQueryField:
-				queryResults, err := m.executeDeviceQuery(field.(DeviceQueryField), browseRequest, queryName, interceptor)
+				queryResults, err := m.executeDeviceQuery(field.(DeviceQueryField), browseRequest, fieldName, interceptor)
 				if err != nil {
-					// TODO: Return some sort of return code like with the read and write APIs
-					results[queryName] = nil
+					log.Warn().Err(err).Msg("Error executing device query")
+					responseCodes[fieldName] = apiModel.PlcResponseCode_INTERNAL_ERROR
 				} else {
-					results[queryName] = queryResults
+					results[fieldName] = queryResults
 				}
 			case CommunicationObjectQueryField:
 				queryResults, err := m.executeCommunicationObjectQuery(field.(CommunicationObjectQueryField))
 				if err != nil {
-					// TODO: Return some sort of return code like with the read and write APIs
-					results[queryName] = nil
+					log.Warn().Err(err).Msg("Error executing device query")
+					responseCodes[fieldName] = apiModel.PlcResponseCode_INTERNAL_ERROR
 				} else {
-					results[queryName] = queryResults
+					results[fieldName] = queryResults
 				}
 			default:
-				// TODO: Return some sort of return code like with the read and write APIs
-				results[queryName] = nil
+				responseCodes[fieldName] = apiModel.PlcResponseCode_INTERNAL_ERROR
 			}
 		}
-		sendResult(model.NewDefaultPlcBrowseResponse(browseRequest, results), nil)
+		sendResult(model.NewDefaultPlcBrowseResponse(browseRequest, results, responseCodes), nil)
 	}()
 	return result
 }
 
-func (m Browser) executeDeviceQuery(field DeviceQueryField, browseRequest apiModel.PlcBrowseRequest, queryName string, interceptor func(result apiModel.PlcBrowseEvent) bool) ([]apiModel.PlcBrowseQueryResult, error) {
+func (m Browser) executeDeviceQuery(field DeviceQueryField, browseRequest apiModel.PlcBrowseRequest, fieldName string, interceptor func(result apiModel.PlcBrowseEvent) bool) ([]apiModel.PlcBrowseFoundField, error) {
 	// Create a list of address strings, which doesn't contain any ranges, lists or wildcards
 	knxAddresses, err := m.calculateAddresses(field)
 	if err != nil {
@@ -113,7 +108,7 @@ func (m Browser) executeDeviceQuery(field DeviceQueryField, browseRequest apiMod
 		return nil, errors.New("query resulted in not a single valid address")
 	}
 
-	var queryResults []apiModel.PlcBrowseQueryResult
+	var queryResults []apiModel.PlcBrowseFoundField
 	// Parse each of these expanded addresses and handle them accordingly.
 	for _, knxAddress := range knxAddresses {
 		// Send a connection request to the device
@@ -141,7 +136,7 @@ func (m Browser) executeDeviceQuery(field DeviceQueryField, browseRequest apiMod
 				if interceptor != nil {
 					add = interceptor(&model.DefaultPlcBrowseEvent{
 						Request:   browseRequest,
-						QueryName: queryName,
+						FieldName: fieldName,
 						Result:    queryResult,
 						Err:       nil,
 					})
@@ -174,8 +169,8 @@ func (m Browser) executeDeviceQuery(field DeviceQueryField, browseRequest apiMod
 	return queryResults, nil
 }
 
-func (m Browser) executeCommunicationObjectQuery(field CommunicationObjectQueryField) ([]apiModel.PlcBrowseQueryResult, error) {
-	var results []apiModel.PlcBrowseQueryResult
+func (m Browser) executeCommunicationObjectQuery(field CommunicationObjectQueryField) ([]apiModel.PlcBrowseFoundField, error) {
+	var results []apiModel.PlcBrowseFoundField
 
 	knxAddress := field.toKnxAddress()
 	knxAddressString := KnxAddressToString(knxAddress)
@@ -404,7 +399,7 @@ func (m Browser) executeCommunicationObjectQuery(field CommunicationObjectQueryF
 				continue
 			}
 
-			// Assemble a PlcBrowseQueryResult
+			// Assemble a PlcBrowseFoundField
 			var field apiModel.PlcField
 			communicationEnable := descriptor.GetCommunicationEnable()
 			readable := communicationEnable && descriptor.GetReadEnable()
diff --git a/plc4go/internal/spi/model/DefaultBrowseRequest.go b/plc4go/internal/spi/model/DefaultBrowseRequest.go
deleted file mode 100644
index 5bf3c0ee5..000000000
--- a/plc4go/internal/spi/model/DefaultBrowseRequest.go
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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
- *
- *   https://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 model
-
-import (
-	"github.com/apache/plc4x/plc4go/internal/spi"
-	"github.com/apache/plc4x/plc4go/pkg/api/model"
-)
-
-type DefaultPlcBrowseRequestBuilder struct {
-	browser spi.PlcBrowser
-	queries map[string]string
-}
-
-func NewDefaultPlcBrowseRequestBuilder(browser spi.PlcBrowser) *DefaultPlcBrowseRequestBuilder {
-	return &DefaultPlcBrowseRequestBuilder{
-		browser: browser,
-		queries: map[string]string{},
-	}
-}
-
-func (m *DefaultPlcBrowseRequestBuilder) AddItem(name string, query string) model.PlcBrowseRequestBuilder {
-	m.queries[name] = query
-	return m
-}
-
-func (m *DefaultPlcBrowseRequestBuilder) Build() (model.PlcBrowseRequest, error) {
-	queries := m.queries
-	return DefaultPlcBrowseRequest{
-		queries: queries,
-		browser: m.browser,
-	}, nil
-}
-
-type DefaultPlcBrowseRequest struct {
-	DefaultRequest
-	queries map[string]string
-	browser spi.PlcBrowser
-}
-
-func (d DefaultPlcBrowseRequest) GetQueryNames() []string {
-	var queryNames []string
-	for queryName := range d.queries {
-		queryNames = append(queryNames, queryName)
-	}
-	return queryNames
-}
-
-func (d DefaultPlcBrowseRequest) GetQueryString(name string) string {
-	return d.queries[name]
-}
-
-func (d DefaultPlcBrowseRequest) Execute() <-chan model.PlcBrowseRequestResult {
-	return d.browser.Browse(d)
-}
-
-func (d DefaultPlcBrowseRequest) ExecuteWithInterceptor(interceptor func(result model.PlcBrowseEvent) bool) <-chan model.PlcBrowseRequestResult {
-	return d.browser.BrowseWithInterceptor(d, interceptor)
-}
diff --git a/plc4go/internal/spi/model/DefaultPlcBrowseEvent.go b/plc4go/internal/spi/model/DefaultPlcBrowseEvent.go
index 1f276eb7e..004ed32df 100644
--- a/plc4go/internal/spi/model/DefaultPlcBrowseEvent.go
+++ b/plc4go/internal/spi/model/DefaultPlcBrowseEvent.go
@@ -23,8 +23,8 @@ import "github.com/apache/plc4x/plc4go/pkg/api/model"
 
 type DefaultPlcBrowseEvent struct {
 	Request   model.PlcBrowseRequest
-	QueryName string
-	Result    model.PlcBrowseQueryResult
+	FieldName string
+	Result    model.PlcBrowseFoundField
 	Err       error
 }
 
@@ -32,11 +32,11 @@ func (d *DefaultPlcBrowseEvent) GetRequest() model.PlcBrowseRequest {
 	return d.Request
 }
 
-func (d *DefaultPlcBrowseEvent) GetQueryName() string {
-	return d.QueryName
+func (d *DefaultPlcBrowseEvent) GetFieldName() string {
+	return d.FieldName
 }
 
-func (d *DefaultPlcBrowseEvent) GetResult() model.PlcBrowseQueryResult {
+func (d *DefaultPlcBrowseEvent) GetResult() model.PlcBrowseFoundField {
 	return d.Result
 }
 
diff --git a/plc4go/internal/spi/model/DefaultPlcBrowseQueryResult.go b/plc4go/internal/spi/model/DefaultPlcBrowseQueryResult.go
index 9fb7dab46..8888eb868 100644
--- a/plc4go/internal/spi/model/DefaultPlcBrowseQueryResult.go
+++ b/plc4go/internal/spi/model/DefaultPlcBrowseQueryResult.go
@@ -19,7 +19,10 @@
 
 package model
 
-import "github.com/apache/plc4x/plc4go/pkg/api/model"
+import (
+	"github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/apache/plc4x/plc4go/pkg/api/values"
+)
 
 type DefaultPlcBrowseQueryResult struct {
 	Field             model.PlcField
@@ -28,6 +31,7 @@ type DefaultPlcBrowseQueryResult struct {
 	Writable          bool
 	Subscribable      bool
 	PossibleDataTypes []string
+	Attributes        map[string]values.PlcValue
 }
 
 func (d *DefaultPlcBrowseQueryResult) GetField() model.PlcField {
@@ -53,3 +57,7 @@ func (d *DefaultPlcBrowseQueryResult) IsSubscribable() bool {
 func (d *DefaultPlcBrowseQueryResult) GetPossibleDataTypes() []string {
 	return d.PossibleDataTypes
 }
+
+func (d *DefaultPlcBrowseQueryResult) GetAttributes() map[string]values.PlcValue {
+	return d.Attributes
+}
diff --git a/plc4go/internal/spi/model/DefaultPlcBrowseRequest.go b/plc4go/internal/spi/model/DefaultPlcBrowseRequest.go
new file mode 100644
index 000000000..06cb5bc94
--- /dev/null
+++ b/plc4go/internal/spi/model/DefaultPlcBrowseRequest.go
@@ -0,0 +1,128 @@
+/*
+ * 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
+ *
+ *   https://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 model
+
+import (
+	"github.com/apache/plc4x/plc4go/internal/spi"
+	"github.com/apache/plc4x/plc4go/internal/spi/utils"
+	"github.com/apache/plc4x/plc4go/pkg/api/model"
+	"github.com/pkg/errors"
+)
+
+type DefaultPlcBrowseRequestBuilder struct {
+	fieldHandler spi.PlcFieldHandler
+	browser      spi.PlcBrowser
+	queries      map[string]string
+	queryNames   []string
+	fields       map[string]model.PlcField
+	fieldNames   []string
+}
+
+func NewDefaultPlcBrowseRequestBuilder(browser spi.PlcBrowser) *DefaultPlcBrowseRequestBuilder {
+	return &DefaultPlcBrowseRequestBuilder{
+		browser: browser,
+		queries: map[string]string{},
+	}
+}
+
+func (d *DefaultPlcBrowseRequestBuilder) AddQuery(name string, query string) model.PlcBrowseRequestBuilder {
+	d.queryNames = append(d.queryNames, name)
+	d.queries[name] = query
+	return d
+}
+
+func (d *DefaultPlcBrowseRequestBuilder) AddField(name string, field model.PlcField) model.PlcBrowseRequestBuilder {
+	d.fieldNames = append(d.fieldNames, name)
+	d.fields[name] = field
+	return d
+}
+
+func (d *DefaultPlcBrowseRequestBuilder) Build() (model.PlcBrowseRequest, error) {
+	for _, name := range d.queryNames {
+		query := d.queries[name]
+		field, err := d.fieldHandler.ParseQuery(query)
+		if err != nil {
+			return nil, errors.Wrapf(err, "Error parsing query: %s", query)
+		}
+		d.AddField(name, field)
+	}
+	return NewDefaultPlcBrowseRequest(d.fields, d.fieldNames, d.browser), nil
+}
+
+type DefaultPlcBrowseRequest struct {
+	DefaultRequest
+	browser spi.PlcBrowser
+}
+
+func NewDefaultPlcBrowseRequest(fields map[string]model.PlcField, fieldNames []string, browser spi.PlcBrowser) model.PlcBrowseRequest {
+	return DefaultPlcBrowseRequest{
+		DefaultRequest: NewDefaultRequest(fields, fieldNames),
+		browser:        browser,
+	}
+}
+
+func (d DefaultPlcBrowseRequest) Execute() <-chan model.PlcBrowseRequestResult {
+	return d.browser.Browse(d)
+}
+
+func (d DefaultPlcBrowseRequest) ExecuteWithInterceptor(interceptor func(result model.PlcBrowseEvent) bool) <-chan model.PlcBrowseRequestResult {
+	return d.browser.BrowseWithInterceptor(d, interceptor)
+}
+
+func (d DefaultPlcBrowseRequest) Serialize(writeBuffer utils.WriteBuffer) error {
+	if err := writeBuffer.PushContext("PlcBrowseRequest"); err != nil {
+		return err
+	}
+
+	if err := writeBuffer.PushContext("fields"); err != nil {
+		return err
+	}
+	for _, fieldName := range d.GetFieldNames() {
+		if err := writeBuffer.PushContext(fieldName); err != nil {
+			return err
+		}
+		field := d.GetField(fieldName)
+		if serializableField, ok := field.(utils.Serializable); ok {
+			if err := serializableField.Serialize(writeBuffer); err != nil {
+				return err
+			}
+		} else {
+			return errors.Errorf("Error serializing. Field %T doesn't implement Serializable", field)
+		}
+		if err := writeBuffer.PopContext(fieldName); err != nil {
+			return err
+		}
+	}
+	if err := writeBuffer.PopContext("fields"); err != nil {
+		return err
+	}
+	if err := writeBuffer.PopContext("PlcBrowseRequest"); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d DefaultPlcBrowseRequest) String() string {
+	writeBuffer := utils.NewBoxedWriteBufferWithOptions(true, true)
+	if err := writeBuffer.WriteSerializable(d); err != nil {
+		return err.Error()
+	}
+	return writeBuffer.GetBox().String()
+}
diff --git a/plc4go/internal/spi/model/DefaultPlcBrowseResponse.go b/plc4go/internal/spi/model/DefaultPlcBrowseResponse.go
index 26c31b0c6..4bc37e2b3 100644
--- a/plc4go/internal/spi/model/DefaultPlcBrowseResponse.go
+++ b/plc4go/internal/spi/model/DefaultPlcBrowseResponse.go
@@ -19,21 +19,35 @@
 
 package model
 
-import "github.com/apache/plc4x/plc4go/pkg/api/model"
+import (
+	"github.com/apache/plc4x/plc4go/pkg/api/model"
+)
 
 type DefaultPlcBrowseResponse struct {
 	DefaultResponse
 	request model.PlcBrowseRequest
-	results map[string][]model.PlcBrowseQueryResult
+	results map[string][]model.PlcBrowseFoundField
 }
 
-func NewDefaultPlcBrowseResponse(request model.PlcBrowseRequest, results map[string][]model.PlcBrowseQueryResult) DefaultPlcBrowseResponse {
+func NewDefaultPlcBrowseResponse(request model.PlcBrowseRequest, results map[string][]model.PlcBrowseFoundField, responseCodes map[string]model.PlcResponseCode) DefaultPlcBrowseResponse {
 	return DefaultPlcBrowseResponse{
-		request: request,
-		results: results,
+		DefaultResponse: DefaultResponse{responseCodes: responseCodes},
+		request:         request,
+		results:         results,
 	}
 }
 
+func (d DefaultPlcBrowseResponse) GetFieldNames() []string {
+	var fieldNames []string
+	// We take the field names from the request to keep order as map is not ordered
+	for _, name := range d.request.GetFieldNames() {
+		if _, ok := d.results[name]; ok {
+			fieldNames = append(fieldNames, name)
+		}
+	}
+	return fieldNames
+}
+
 func (d DefaultPlcBrowseResponse) GetRequest() model.PlcBrowseRequest {
 	return d.request
 }
@@ -46,6 +60,6 @@ func (d DefaultPlcBrowseResponse) GetQueryNames() []string {
 	return queryNames
 }
 
-func (d DefaultPlcBrowseResponse) GetQueryResults(queryName string) []model.PlcBrowseQueryResult {
+func (d DefaultPlcBrowseResponse) GetQueryResults(queryName string) []model.PlcBrowseFoundField {
 	return d.results[queryName]
 }
diff --git a/plc4go/pkg/api/model/plc_browse.go b/plc4go/pkg/api/model/plc_browse.go
index 3f008bde2..762ba8e9b 100644
--- a/plc4go/pkg/api/model/plc_browse.go
+++ b/plc4go/pkg/api/model/plc_browse.go
@@ -19,35 +19,29 @@
 
 package model
 
+import "github.com/apache/plc4x/plc4go/pkg/api/values"
+
 type PlcBrowseRequestBuilder interface {
-	AddItem(name string, query string) PlcBrowseRequestBuilder
+	AddQuery(name string, query string) PlcBrowseRequestBuilder
 	Build() (PlcBrowseRequest, error)
 }
 
-type PlcBrowseQueryResult interface {
-	GetField() PlcField
-	GetName() string
-	IsReadable() bool
-	IsWritable() bool
-	IsSubscribable() bool
-	GetPossibleDataTypes() []string
-}
-
 type PlcBrowseRequest interface {
+	PlcRequest
 	// Execute Will not return until a potential scan is finished and will return all results in one block
 	Execute() <-chan PlcBrowseRequestResult
 	// ExecuteWithInterceptor Will call the given callback for every found resource
 	ExecuteWithInterceptor(interceptor func(result PlcBrowseEvent) bool) <-chan PlcBrowseRequestResult
-	GetQueryNames() []string
-	GetQueryString(name string) string
-	PlcRequest
+	GetFieldNames() []string
+	GetField(name string) PlcField
 }
 
 type PlcBrowseResponse interface {
-	GetRequest() PlcBrowseRequest
-	GetQueryNames() []string
-	GetQueryResults(name string) []PlcBrowseQueryResult
 	PlcResponse
+	GetRequest() PlcBrowseRequest
+	GetFieldNames() []string
+	GetResponseCode(name string) PlcResponseCode
+	GetQueryResults(name string) []PlcBrowseFoundField
 }
 
 type PlcBrowseRequestResult interface {
@@ -58,7 +52,17 @@ type PlcBrowseRequestResult interface {
 
 type PlcBrowseEvent interface {
 	GetRequest() PlcBrowseRequest
-	GetQueryName() string
-	GetResult() PlcBrowseQueryResult
+	GetFieldName() string
+	GetResult() PlcBrowseFoundField
 	GetErr() error
 }
+
+type PlcBrowseFoundField interface {
+	GetField() PlcField
+	GetName() string
+	IsReadable() bool
+	IsWritable() bool
+	IsSubscribable() bool
+	GetPossibleDataTypes() []string
+	GetAttributes() map[string]values.PlcValue
+}
diff --git a/plc4go/pkg/api/model/plc_connection_metadata.go b/plc4go/pkg/api/model/plc_connection_metadata.go
index 4712ca857..905d2e92f 100644
--- a/plc4go/pkg/api/model/plc_connection_metadata.go
+++ b/plc4go/pkg/api/model/plc_connection_metadata.go
@@ -22,10 +22,8 @@ package model
 // PlcConnectionMetadata Information about connection capabilities.
 // This includes connection and driver specific metadata.
 type PlcConnectionMetadata interface {
-
 	// GetConnectionAttributes Gives access to a map of additional information the driver might be able to provide.
 	GetConnectionAttributes() map[string]string
-
 	// CanRead Indicates that the connection supports reading.
 	CanRead() bool
 	// CanWrite Indicates that the connection supports writing.
diff --git a/plc4go/pkg/api/model/plc_read.go b/plc4go/pkg/api/model/plc_read.go
index b27f77b81..7dd6f9fc3 100644
--- a/plc4go/pkg/api/model/plc_read.go
+++ b/plc4go/pkg/api/model/plc_read.go
@@ -34,16 +34,16 @@ type PlcReadRequestResult interface {
 }
 
 type PlcReadRequest interface {
+	PlcRequest
 	Execute() <-chan PlcReadRequestResult
 	GetFieldNames() []string
 	GetField(name string) PlcField
-	PlcRequest
 }
 
 type PlcReadResponse interface {
+	PlcResponse
 	GetRequest() PlcReadRequest
 	GetFieldNames() []string
 	GetResponseCode(name string) PlcResponseCode
 	GetValue(name string) values.PlcValue
-	PlcResponse
 }
diff --git a/plc4go/pkg/api/model/plc_write.go b/plc4go/pkg/api/model/plc_write.go
index 3df89507d..d78d2d0ff 100644
--- a/plc4go/pkg/api/model/plc_write.go
+++ b/plc4go/pkg/api/model/plc_write.go
@@ -34,16 +34,16 @@ type PlcWriteRequestResult interface {
 }
 
 type PlcWriteRequest interface {
+	PlcRequest
 	Execute() <-chan PlcWriteRequestResult
 	GetFieldNames() []string
 	GetField(name string) PlcField
 	GetValue(name string) values.PlcValue
-	PlcRequest
 }
 
 type PlcWriteResponse interface {
+	PlcResponse
 	GetRequest() PlcWriteRequest
 	GetFieldNames() []string
 	GetResponseCode(name string) PlcResponseCode
-	PlcResponse
 }
diff --git a/plc4go/tools/plc4xbrowser/commands.go b/plc4go/tools/plc4xbrowser/commands.go
index 3be7676e5..0241a659d 100644
--- a/plc4go/tools/plc4xbrowser/commands.go
+++ b/plc4go/tools/plc4xbrowser/commands.go
@@ -264,7 +264,7 @@ var rootCommand = Command{
 				} else {
 					start := time.Now()
 					browseRequest, err := connection.BrowseRequestBuilder().
-						AddItem("writeField", split[1]).
+						AddQuery("writeField", split[1]).
 						Build()
 					if err != nil {
 						return errors.Wrapf(err, "%s can't browse", connectionsString)