oshi / oshi6

Repository for planning/coordination of OSHI 6.0
MIT License
0 stars 2 forks source link

Official definitions of common terms #7

Open cilki opened 5 years ago

cilki commented 5 years ago

We need to agree on some common definitions to make it easier to discuss design and write documentation. I propose the following initial set:

Term Definition Example
Attribute A specific property of some aspect of the system guid, vendor, name
Component A POJO container for related attributes Cpu, Gpu, ...
Index An interface that defines all attributes of a component CpuIndex, GpuIndexWindows
Driver TBD
dbwiddis commented 5 years ago

Attribute needs not only the property, but the API "tree" to get there. For example, hardware.memory.available.

Not sure I like the term "Component" for the POJO container. While the interfaces can be names of (physical) components, I am leaning toward (in OSHI 4) the POJO containers being called *Data.

The Interfaces will be the API and should be the simple component names, rather than the "Index".

YoshiEnVerde commented 5 years ago

Not sure I like the term "Component" [...] I'm sure we're talking terms only here, not how they'll be named in the implementation. Just how we'll reference them in the documentation, and in any further design conversation.

I stumbled over this issue myself while trying to give the explanation of how layers should work in #2 and #3

Just like in those issues, I have a more nuanced structure for the components in my head. I'll draw a quick diagram and share it later today. Until then, my contributions to this:

Term Definition Example My ¢2
Result The content of any Attribute. Follows a pattern similar to Optional These should be able to contain the resulting variable from a valid Value flowing up all the way from the Driver, if available, or error details if something goes wrong in the process
Attribute A specific property of some aspect of the system guid, vendor, name I like this one, with @dbwiddis caveat of using full paths for their individual names
Endpoint An interface that defines a container for related attributes Processor, ProcessorWithFrequencyRates, ... Instead of having indexes, I agree with @dbwiddis on using the API interfaces for this
Entity A POJO container that implements one or more Endpoints PhysicalProcessor, LogicalProcessor, ... Any of these should correspond to a main Endpoint it implements, while maybe implementing extra minor Endpoints depending on their internals or references. Like I told @dbwiddis in #2, a LogicalProcessor would be one of the implementations of Processor, while also implementing ProcessorWithFrequencyRates and DependentOnProcessor (for having a parent PhysicalProcessor to reference)
Component Non-POJO implementation of an underlying system element. Maps between the underlying layers and the Entities/Endpoints PhysicalProcessorIntel, NetworkInterfaceCommon, HardDriveWindows, ... These correspond, more or less, to the objects being output by current OSHI3
Cache Any element, collection, or framework we'll use for caching values. No specific details, since we should use this transparently Value refresh will be handled here
Strategy A configurable object that knows how to effectively recover attribute values from the underlying system MotherboardDetailsStrategyWindows, ProcessorStrategyMac, ... These will make sure to call the corresponding drivers, handle any errors they throw, etc
Driver A configurable low-level object that knows how to interact with a specific system service for data WmicDriver, LinuxCommandDmiDecodeDriver, ... These know how to handle one single service well. They are charged with calling the service, and parsing the recovered values
Value Any value fetched and parsed by a Driver We should strive for these to be only primitives, String, and enums
YoshiEnVerde commented 5 years ago

This chart would correspond to the higher level API I was proposing. If we also want a lower level API closer to the drivers, we can have a second set of Components that may, or not, have a caching layer, and work in a straight coupling with the Strategies

cilki commented 5 years ago

The reason I intended users to interact with API classes (components) rather than interfaces (index) is because it would be beneficial for the user to do other things not defined in the interface.

Here's what I mean. A CPU interface would define String getModel(), but it could also be desirable to have another method that returns the attribute itself: Attribute<String> model(). This object would contain metadata like timestamps, but most importantly would be AutoClosable so OSHI knows when the user is done polling the attribute. I'm also imagining an addListener() defined for attributes which adds a callback that receives change events.

These methods shouldn't be added to the main interface because then the drivers would need to implement them as well.

Edit: Although now that we've agreed to generate the API, we could just make a separate interface for the drivers.

YoshiEnVerde commented 5 years ago

In that case, we're talking about building a whole second API.

And no, the drivers don't have to implement anything you don't need them to implement. Their job is only to fetch the values.

If you want timestamps, that would go wherever you're handling caching of the values. Same with callbacks and listeners, which should happen above the caching layer.

Those are all high level concerns that should never fall in the lower layers.


For example, change events require some kind of threading model that will keep a constant/periodical check on the values of the system to allow you to know if something's changed.

This means implementing at least a single thread that goes through a full list of every single value of interest, requesting the drivers for the latest value (irregardless of the cache state), and comparing it to the cached values to see if an event must be triggered.

Timestamps are a bit easier: the caching solution already implements timestamps for the cached values, so you just need to keep the full cache record when requesting values, instead of just the value itself


Finally, AutoClosable is technically dependent on your underlying layers having an Open/Closed state of some type, that you will invoke within a single scope (no matter how big that scope is).

OSHI, in general, doesn't work that way. More so, this would go against the whole point of having unmodifiable POJOs at the public facing side of the library, since those are set once read.

The correct thing for such a use case would be for the user to write some AutoClosableOshiWrapper that handles the auto-closable part of the request

YoshiEnVerde commented 5 years ago

Not saying the use cases aren't there, or interesting, just that we should focus on designing and implementing OSHI here, and leaving any high level functionalities to a separate module.

The problem with adding extra functionalities is that we start clashing with the try to be more performant part of the OSHI design.

What we can do, is build each layer of the library as a separate module (or set of modules). For example, a module with the Win Drivers, one for the Mac Drivers, one for Components, etc.

That way, adding a module with the functionality you want would be as easy as adding another module to the OSHI catalog, that depends on the Strategy/Driver level modules, and works as a standalone from the standard OSHI library

cilki commented 5 years ago

We discussed a polling engine to supply change listeners a while back and decided it was best for another artifact. I was just trying to setup the base design so it could easily support such extensions in the future.

One more tangent: OSHI doesn't currently have the notion of open/closed for anything, but I think it would benefit from having stateful drivers/strategies. What do you think about that?

YoshiEnVerde commented 5 years ago

The reason I intended users to interact with API classes (components) rather than interfaces (index) is because it would be beneficial for the user to do other things not defined in the interface.

Here's what I mean. A CPU interface would define String getModel(), but it could also be desirable to have another method that returns the attribute itself: Attribute<String> model(). This object would contain metadata like timestamps, but most importantly would be AutoClosable so OSHI knows when the user is done polling the attribute. I'm also imagining an addListener() defined for attributes which adds a callback that receives change events.

These methods shouldn't be added to the main interface because then the drivers would need to implement them as well.

Edit: Although now that we've agreed to generate the API, we could just make a separate interface for the drivers.

One thing I've realized about your post, related to the Attributes, is that you're asking for a possible AutoClosable on the Attributes themselves. My guess would be to keep updating them until you don't need to?

First of all, our current work (OSHI3) on the code that would go into the drivers doesn't contemplate keeping a resource open for variable lengths of time. We request the value from the system, we get it back, done. Any update means doing the full request once more. That's even the only approach available for most of the requests.

Second, what you're asking for the Attributes would be the reason why I split the response data into Response, Attribute, Entity and Component: The first three should be static. Once requested, they're fixed. That allows for the user to have stable and reliable data on hand. The Component is updateable, returning a new set of Entities on every update. With that, what you ask for in states is, technically, part of the Component; while metadata can easily be argued in favor of, or against, as part of the Result objects.

We discussed a polling engine to supply change listeners a while back and decided it was best for another artifact. I was just trying to setup the base design so it could easily support such extensions in the future.

I actually find the use case to be a very useful one. I just don't see this being a part of OSHI itself. For setting things up for the capability, I just raised a new issue, since I do find it to be a perfectly valid reason for some details in the design approach

One more tangent: OSHI doesn't currently have the notion of open/closed for anything, but I think it would benefit from having stateful drivers/strategies. What do you think about that?

This is one of the reasons why we'd have Drivers/Strategies in a separate layer from the Caching and API itself. If we need to, we can implement Drivers that are not stateless (I actually encourage that for some drivers). However, the way the driver works should not reflect on the way the API works, since the whole point of a Driver Pattern is to abstract such concerns from the API.

What we can do is add/leverage the configuration layer, to be able to set those up.

cilki commented 5 years ago

the way the driver works should not reflect on the way the API works, since the whole point of a Driver Pattern is to abstract such concerns from the API

The only problem is, how can you determine when to release a driver's resources without a cue from a higher layer? Making the lowest layer stateful introduces a session-like architecture to the higher layers.

YoshiEnVerde commented 5 years ago

Last response, and then let's move this to it's own issue, since this one is supposed to be about naming conventions ;)

The only problem is, how can you determine when to release a driver's resources without a cue from a higher layer? Making the lowest layer stateful introduces a session-like architecture to the higher layers.

Yup, that's an issue that we do need to address as part of the Driver's design/implementation. It should still not be part of the general API. By that, I mean that the state of the Drivers should not be something that impacts on the Entities/Attributes/Results.

If we need to, we'll add some management module that handles that. Or we'll add a way to set this up, or to open/close the resources, or whatever we might need. But it should never be delegated to an element five layers of abstraction away.

For the case you proposed back in oshi/oshi#548 , for example, with the ability to set only specific values to be updated on polling, and avoiding others, we'd just as easily have a configuration value that disables certain values from being fetched by a Driver. This is even something that can be done programmatically, just by replacing a value in the app properties map. If we have such a configuration value, we can just as well have some kind of ConfigHandler/ConfigManager that has methods to set all those without needing to blindly set values in the properties themselves.

cilki commented 5 years ago

Sorry for completely derailing this. I'll make an issue for the driver state thing and hide the tangential comments to get back on track since this is a very important issue.

I'm curious as to what @dbwiddis thinks about your terms. The only two that bother me are strategy and entity. Strategy is just a specialized driver, so that's why I've been saying driver and generic driver. Also, strategy doesn't really suit the concept in my opinion.

YoshiEnVerde commented 5 years ago

No problem. We're here to design all this, so any issue is welcome, I guess.

I used Entity and Strategy because they're the more common pattern names for what I was thinking. I'll welcome any name that might be better. Let's not forget that we're defining terms only here to be able to throw around designs and ideas without having (too many) communication failures.

In the case of Strategies, my idea would be that on OSHI3 we have multiple ways of recovering a value from the system, and we need to be able to use them.

For example, recovering some random system detail from Windows might trigger a request to WMIC, if that fails, we'll ask another Windows API, if that fails, we'll check the Register, and if that fails, we'll ask some file in the system folder. That kind of logic flow is pretty common in OSHI3.

For such a case, we'd actually have 4 different drivers involved there:

As such, the Strategy object would handle the flow between drivers depending on their priority, raise/throw the errors as needed, check the config for disabled drivers, etc

dbwiddis commented 5 years ago

I'm curious as to what @dbwiddis thinks about your terms.

Don't give me any special consideration! You're the professionals!

That said...

Result -- Agreed, we need Value (or null/NaN/flag for failure), Error details, and also a Timestamp.

Entity/Endpoint -- don't understand the example ProcessorWithFrequencyRates. This seems overly complicated.

Strategy -- ok. I prefer "Fallback Logic"

Driver -- ok. Should think about a generic "text column parsing" utility that we can use for a lot of the command line stuff that returns outputs in delimited columns, which is essentially like a "database query" equivalent.

Value -- not sure I like Enum, just return the string name for it. We expect Values to be eventually represented in JSON so generally need to follow that spec (numeric, string, arrays). Need a way to represent unsigned long (BigInteger).

dbwiddis commented 5 years ago

WMIC Driver

Since we're being all official with definitions let me make sure this one's clear. Windows Management Instrumentation (WMI) is the infrastructure that gives us access to a lot of data on Windows. Component Object Model (COM) is the API available to us in C (or Java via JNA) to query WMI via WMI Query Language (SQL). WMI command-line (WMIC) is a command line utility with its own syntax similar to, but unique from WQL. Early versions of OSHI used the wmic.exe command line, but that has since been replaced by WQL calls using the COM API.