I like the fact that Gregg's pushed the envelope, he's pushed Jini beyond it's current capability.

Now I'm wondering if there's a way around the Preferred Classes problem.

In Reggie's proxy implementation, during registration, fields in Entry classes, if they can be resolved to standard java classes, are, however they are sent as a MarshalledWrapper (wrapping a MarshalledInstance), if they can't.

For MarshalledServiceItem, we don't have to honour preferred classes, since we can unmarshall everything correctly when the unmarshall method is called, in other words we can unmarshall the Entry's again, using preferred class loading and downloaded codebases.

For implementation of MarshalledServiceItem, the reggie implementation EntryClass can be first used to identify an entry we're interested in, first we check if the name matches an Entry's Class name we're interested in, secondly we resolve all fields of these Entry's locally by providing a get() method on MarshalledInstance that ignores codebase annotations, leaving any field that cannot be unresolved as null.

So what we get at the client is a number of Entry's that may be fully unmarshalled, or partly so, which should give us enough information to determine if the service is interesting.

When the client finds a field in an Entry in the ServiceItem, set to null, and it wants to know more, it must then unmarshall the MarshalledServiceItem, a process which then retrieves all codebases and correctly unmarshalls all Entry's and the Service, the original array of Entry's contained in the MarshalledServiceItem is discarded, so the fact that these were previously resolved locally doesn't matter.

Then we could leave Preferred classes alone.

Thoughts?

Peter.

Gregg Wonderly wrote:
I am finding my self being slightly defensive sounding and I'm not wanting to be defensive about my implementation. I want to defend the features that I need and thus made changes in lookup to provide. Hopefully the inline below is not degenerating into to much reiteration of the issues. There are some additional thoughts about other ways that lookup could be changed to provide the "string" information without a proxy service.

See below...

On 2/2/2011 3:26 AM, Dan Creswell wrote:
Inline and leaving context for now.....

On 1 February 2011 19:12, Gregg Wonderly<ge...@cox.net>  wrote:

On 2/1/2011 3:17 AM, Dan Creswell wrote:

So...

On 1 February 2011 01:29, Gregg Wonderly<gr...@wonderly.org>   wrote:

  One of the important things for my use of my changes to the
ServiceRegistrar interface was separating deserialization of the Entrys
from
the service object.


Note "separating" used here. I was trying to say that I need to be able to "pick" which Entry objects to deserialize, and deserialize them independent
of deserializing the service proxy/object.


  Being able to defer downloading was also controlled by the changes to
ClassLoading to include the "neverPrefer" settings on a class name. I
can
do that now through the recent RMIClassLoaderSPI override capabilities.
  But
I still need to be able to control which Entry is deserialized. I need
to
be able to ask what classes, by name, are in the namespace of each Entry
object as my implementation allowed. I had made changes to Reggie
marshalling to use reflection to get the class hierarchy, and then
provided
access to the list of classnames as part of the returned, marshalled
value
in my API.


Digging through classes belonging to a service implementation that is
designed to be encapsulated/not your concern? Does that sound right? I
gotta
say, it sounds horribly invasive, very hacky and speaks of an overly
complex
solution as the result of treating symptoms, not problems.


Okay, I want to go through the problems that I was dealing with, the
attributes of the current mechanisms, and how I inserted points of control
to manage these issues.

First, let's look at the simple client mechanisms I wanted to have. I have
a desktop environment, which does lookup, and then shows treeviews of
services based on "machine"->"group"->Service Instance structure.  The
deployed services contain Entry objects that provide values for these three name spaces. Since I need to look at these, they can not be preferred by the service or I can't read them. There may be a subclass that the client has used, and that can be preferred no problem. There are some other items in the Entrys that I need too, such as icons. Any of the Entry objects that I need access to, and any classes which they are dependent on, and which are publicly visible classes/interfaces, because of that attribute (public) can
not be realistically preferred.


These Entry types are part of the basic infrastructure of your system aren't they? Why download them at all? I guess because you have to "teach" it to
the LUS via code-download? Or you could just put them on all classpaths
including LUS? S'far as I can see you've got an extended LUS infrastructure that everyone shares thus codebase seems like the wrong choice for these.

Sure user's can subclass Entry types but do they? Do you even want them to? Why? Thus far I've seen many subclass Entry's for JavaSpaces and, I think,
zero for LUS type annotations.

See my other thread with Peter but it seems to me that you have some core
additions to LUS infrastructure and a need to be able to filter what you
don't want to see/is outside of a client's knowledge base. Because it's that
inability to filter that then leads to lots of additional downloading.

The basic issue is that I need to show users what services exist. The LUS maintains a very useful view of the health of the network. Asking it what services exist has to happen by some 'client'. Remember that my customers techs are using the client out in the field, on a slow network. So whether they enumerate something from the LUS or from another "service", there will be network traffic.

It might be possible to enumerate services at a aggregation service, but then you have to unmarshall all of the services there to get the "data" that you'd send to a client. I don't want to have 100s of proxies active on the network for this mechanism, really. The deferred unmarshalling in discussion with Peter would help deal with this by allowing such an aggregation service to not have to unmarshall the proxy. That was my initial intent. It was only after I got that implemented that I found out how the PREFERRED.LIST really kept it from working at all, and so I had to do something to keep the PREFERRED.LIST from being accessed when not needed yet.

The service aggregation becomes a single point of failure and I'd need to replicate it to every server that had an LUS on it. Then, it really becomes more like a secondary look up service, and so I'd still have to ask, is the LUS API really in the right form if there is a "mirror" of it needed? Note that I made it possible to pick through a lot of the class information for the Entry and the service Proxy in reef's work because I was trying to get around having to mess with the never-preferred business. But in the end, I just could not find any other way, because as soon as I wanted to unmarshall an Entry to get a "Name" and a "Group" and an "Icon" for my UI, PreferredClassLoading went after the PREFERRED.LIST, even though not a single class that I was using would be resolved from the codebase.

I'm not sure how I would "not activate the codebase" in some client. It needs the Entry object, fully resolved. I want the codebase to work right, so I'm not gonna just throw in a proxy context class loader that resolves everything locally. If there is content in an Entry that is an unknown class, I will suffer the download to make sure that it resolves to the right codebase.

Note that I am not wanting to focus on the never-prefer issue as something that I need. What I actually need is to defer download of any part of the codebase until the service is "activated".

What might be interesting is to figure out how to stuff the preferred list into the MarshalledObject annotation so that PreferredClassLoader would not need to retrieve the codebase elements to resolve how to perform class loading.

Currently, there is a lot of backward compatibility involved in how the annotation is managed.

The namespace change that we are discussing for com.sun.jini, might be the right moment to introduce any compatibility issues with MarshalledObject and the use of the RMIClassLoader annotation.

So my first assertion is that Entry objects will hardly ever be preferred,
and thus downloading of the PREFERRED.LIST is not a necessary step to
correctly resolve them for my use.

The next issues is this PREFERRED.LIST file. The implementation of that technology is that the file is retrieved from the first jar file listed in
the codebase.  So, in order to resolve any class in the proxy or Entry
values, there must be a download from the associated codebase server.

Now, one of the first things that I think about with distributed computing is the business of partial failure and limiting that impact to the overall performance of the system. My deployments at my customers' sites consist of copies of the same service platform with the same services on it. There are
copies for both redundancy and for capacity.

Each instance of my platform has as a starting point 20 some services each with a separate codebase, but with many common jars such as jsk-dk.jar. If a lookup service responds with a list of services but the codebase server
doesn't respond with jars, then any attempt to download limits the
performance of the display of available services, and I considered an
"incorrect list of available services" less important than non-display or
slow-display of available services.

As Michal says elsewhere, are you sure the solution is to try and leverage
LUS to handle display challenges like this?

I need the data with minimal network traffic. The LUS lookup is even something that generates some delays. But, the UI, as it populates, feels largely like a web page load. I've reached a point of acceptable performance that works for now.

Service lookup and selection has always been a point of contention as you well know. I had always been on the side of the fence that said the LUS works fine the way it is. It wasn't until I tried to figure out how to manage 100s of services visible and only 1 being interesting that I suddenly found myself setting on the fence asking, "If it almost does the right thing, is there a way to maintain the same interface, but add a new interface with more functionality that would keep me from having to completely ignore the LUS?"

So, I tried something out. I find that given how Reggie works and is implemented, that the addition of the functionality as shown in Reef does provide some new opportunities. But, delayed unmarshalling alone, does not provide for no-download until needed. PreferredClassLoading is still in the mix. My solution to that, which I think does need to be revisited. We need to decide if the PREFERRED.LIST is really a problem because it causes a download. Service registration data will always require download, and so just to use the Entry values in a UI or some other client will still require download of all the elements of the codebase needed to resolve the classes.

In one explanation of how things are currently working with River, without my changes, I suggested that using Reggie and preferred class loading would be like opening up a Google session, running a query, and then having to download every matched pages content before you could see the list of search results.

Google provides the type of service that you describe by changing what the user has to experience to be something that is usable. But we don't all then go and write a new service on top of google. It does what is needed to find something to look at. But, it still then has the struggle that you have to click on a link, and wait for the page to load in order to validate which content is appropriate to your needs. The textual summaries don't always provide the right "view" of what you are looking for, even through they've tried to provide a textual view of the document fragment that contains what you searched for.

It is the load-before-need-is-established behavior that I am trying to raise the red flag about. We need a complete different LUS if there are more than a handful of services that match a lookup request.

I feel really strongly against forcing clients to resolve 10s of services much less 100s just to see what they might choose to use. Entry and service interface based filtering works to trim results dramatically. But in the case of a ServiceUI discovery where you are just looking for services that have a

Service registration with a ServiceRegistrar implementation is the "I am alive" moment, and I think we need to maintain that single point of information because doing otherwise spreads knowledge out into more than one place and makes for a distributed database that I don't feel we don't need to add to the mix.

What you seem to be doing is constructing a navigation structure for a GUI direct from the LUS per client. Why wouldn't you have some separate "service
summary service" that builds up this navigation structure by tracking
service arrivals and such and creating the necessary descriptive text for
clients to pull down in one big bang?

There is some tangible benefits I can see in doing this, but I don't like the idea that this is another layer between the client and the LUS regarding availability and liveness. As I said above, the LUS has the information, but it's the "unmarshalling" (ServiceRegistrar's APIs) and PreferredClassLoading that don't allow a client of the LUS to avoid downloading what they don't need to download. That's why I went specifically at those two sources.

If I didn't have the sources to mess with, I am sure I would have had a different approach or done something without Jini even.

You get caching for staters, no need to download a bunch of services until later and thus far fewer downloads especially as things like Entry's can be
rendered into text reps as part of this process of building navigation
information. (heck you could even insist all Entry's provide a toString for use on your platform). No reason too why the summary service couldn't build on demand trees for some specified set of Entry types. It could cache those and update them too such that if another client requests the same tree it
gets it straight back.

I guess my summary would be, I feel like you've gone for a "deep" solution that builds into existing infrastructure instead of building extensions atop
that specifically tackle your problems in a more "meta" fashion. Please
don't take offence at that, I'm not for a moment saying it's a mistake, just
one path to solution and given what I've heard so far I think there's
another path that hasn't been ruled out yet.

I'm good with this discussion. That never happened before, even at the Jini Community meeting and later when I pushed Reef out onto java.net.

I want to really stress what I feel are the primary issues for me and my customers. I also feel that given the larger set of services that might be visible on a broader network environment, such as the internet, that these issue will be important to others as well. It sounds like Chris at least did the caching of jars.

Imagine if ServiceRegistrar included an XML or other string document that could be used by applications to get "client display" information, instead of just Entry object values, and that PreferredClassLoader got the PREFERRED.LIST from the annotation String instead of from a META-INF entry in the jar file.

Then, the ServiceRegistrar could still be a primary source of service registration and lookup but would include some flexibility for local needs. We could even cause the XML to be constructed by the serialization process so that it looked something like:

<entries>
    <entry class="net.jini.lookup.entry.Name">
        <field name="name" type="java.lang.String" value="My Service"/>
    </entry>
</entries>

All the public fields would be enumerated and specified with values that would allow complete use of them (when they have appropriate toString() values) and thus we can get the text from the Entry objects directly.
`
We'd just provide an API that provided the programmatic iteration over this information without XML being directly visible.

So the existing lookup would be fine, and ServiceItem could have an additional XML string field to pass to a new API.

Just thinking out loud here...

Gregg


Reply via email to