You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Gregg Wonderly <gr...@wonderly.org> on 2011/02/01 02:29:47 UTC
Re: MarshalledServiceItem
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. Ultimately, I wanted to not have to worry about how the "codebase" was structured in order to minimize downloading. Some Jini deployers have done things to put a small jar at the front of the codebase that just has the preferred.list in it. Even that download, for me, would have been too much. My customers' deployments have nearly 50 codebases visible when my client starts up. Those 50 connections over a cellular or other high latency network would make service selection take way too long.
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.
Gregg Wonderly
On Jan 30, 2011, at 2:23 PM, Peter Firmstone wrote:
> Gut feel, tells me the following class is not right, it's intent is to provide an api for implementation of delayed unmarshalling and provisioning of codebases, for services implementing a lookup service or ServiceRegistrar, whilst retaining backward compatibility.
>
> In other words, the lookup service proxy would implement it.
>
> Thoughts I had were to declare IOException's on methods, and to return a String annotation, rather than a URI.
>
> What are your thoughts?
>
> Cheers,
>
> Peter.
>
> /*
> * 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.river.api.lookup;
>
> import java.net.URI;
> import java.security.CodeSource;
> import net.jini.core.entry.Entry;
> import net.jini.core.lookup.ServiceID;
> import net.jini.core.lookup.ServiceItem;
>
> /**
> * MarshalledServiceItem extends ServiceItem and can be used anywhere a
> * ServiceItem can. A MarshalledServiceItem implementation instance
> * contains the marshalled form of a Service and it's Entry's,
> * the corresponding superclass ServiceItem however contains null values
> * for the service and can exclude any Entry's, however where Entry
> * classes already exist at the client, that they be unmarshalled.
> *
> * The ServiceID shall be in unmarshalled form always in the ServiceItem super class.
> *
> * Since the ServiceItem.service is null, use of this class in existing software
> * will not return the service, however it will not break that software as
> * ServiceItem's contract is to set service or Entry's to null when they cannot
> * be unmarshalled.
> *
> * ServiceItem's toString() method will return a different result for
> * MarshalledServiceItem instances.
> *
> * If required, a new ServiceItem that is fully unmarshalled
> * can be constructed from this class's methods and ServiceID.
> *
> * @author Peter Firmstone.
> */
> public abstract class MarshalledServiceItem extends ServiceItem{
> private static final long SerialVersionUID = 1L;
> protected MarshalledServiceItem(ServiceID id, Entry[] unmarshalledEntries){
> super(id, (Object) null, unmarshalledEntries);
> }
> /**
> * Unmarshall the service proxy.
> * @param load service with local or existing CodeSource or null for
> * default.
> * @return the service proxy, null if class not found.
> */
> public abstract Object getService(CodeSource[] code);
> /**
> * Unmarshall the Entry's
> * @return array of Entry's, null entry in array for any class not found.
> */
> public abstract Entry[] getEntries();
> public abstract URI[] getAnnotations();
> }
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Utility class for ServiceItemFilter's discussed in previous post.
/*
* 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.river.api.lookup;
import java.io.IOException;
import org.apache.river.api.util.ResultStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.jini.core.lookup.ServiceItem;
import net.jini.lookup.ServiceItemFilter;
/**
* A utility class designed for building complex queries, from existing
filters.
*
* Filters can be daisy chained with pre prepared filters to perform
logical AND operations.
*
* Logical OR operations can be simulated by providing multiple filters in
* constructors.
*
* Any references to ServiceResultStreamFilter should be set to null
* immediately after filtering.
* New instances can be created as required.
*
* @author Peter Firmstone.
*/
public class ServiceResultStreamFilter implements
ResultStream<ServiceItem> {
private final List<ServiceItemFilter> filters;
private final ResultStream inputResultStream;
/**
* Note the methods of ServiceResultStreamFilter implement
* ResultStream<ServiceItem>, but the constructor doesn't, this is to
* protect the client against unchecked type casts that would occur
* if a ResultStream<ServiceItem> was obtained from a service.
*
* All methods in this implementation perform their own type safety
* checks in order to implement ResultStream<ServiceItem> safely.
*
* @param rs
* @param sf
*/
public ServiceResultStreamFilter(ResultStream rs,
ServiceItemFilter[] sf){
inputResultStream = rs;
filters = new ArrayList<ServiceItemFilter>(sf.length);
filters.addAll(Arrays.asList(sf));
}
public ServiceItem get() throws IOException {
for(Object item = inputResultStream.get(); item != null;
item = inputResultStream.get()) {
if (item instanceof ServiceItem){
ServiceItem it = (ServiceItem) item;
int l = filters.size();
for ( int i = 0; i < l; i++){
ServiceItemFilter filter = filters.get(i);
if (filter == null) continue;
if (filter.check(it)) return it;
}// end filter loop
}// If it isn't a ServiceItem it is ignored.
}//end item loop
return null; // Our stream terminated item was null;
}
public void close() throws IOException {
inputResultStream.close();
}
}
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Gregg Wonderly 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. Ultimately, I wanted to not have to worry about how the "codebase" was structured in order to minimize downloading. Some Jini deployers have done things to put a small jar at the front of the codebase that just has the preferred.list in it. Even that download, for me, would have been too much. My customers' deployments have nearly 50 codebases visible when my client starts up. Those 50 connections over a cellular or other high latency network would make service selection take way too long.
>
> 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.
>
> Gregg Wonderly
>
> On Jan 30, 2011, at 2:23 PM, Peter Firmstone wrote:
>
>
Thanks Gregg,
What follows, is an interface for a lookup service, that extends the
existing ServiceRegistrar lookup service interface, enabling existing
clients to utilise the existing discovery mechanisms and interfaces.
I researched your implementation before writing this, so I was strongly
influenced by your lookup service, delayed umarshalling and selective
unmarshalling of Entry's are very important features, missing from River.
I wanted to utilise the features you created, at the same time, I wanted
a lookup service for the internet, so it also needed to be able to
retrieve an almost infinite collection of results incrementally, over
time, that may contain duplicates using a ResultStream (somewhat similar
to MatchSet in javaspaces). In the lookup method below, the caller can
provide the Class files of any Entry's it's interested in, after first
retrieving and determining them using a ServiceTemplate and
ResultStream. A ResultStream can use filter chaining where each filter
performs a single simple operation (like proxy verification,
unmarshalling, Entry based comparison, or removal), and can utilise the
existing ServiceItemFilter interface (when applicable), uninteresting
services can be removed from the ResultStream, or categorised and placed
in different queues for parallel processing, or left in the stream for
serial processing.
Once you've built a filter based result stream, this can be reused over
and over, to process lookup results from multiple lookup services.
I have plans to create some DNS-SRV discovery support classes, used to
produce LookupLocator's (actually a subclass of LookupLocator), to be
used by LookupLocatorDiscovery, using Unicast discovery to find lookup
services all over the internet. Each domain should be responsible for
providing lookup services for all public Jini Services it provides.
Another piece in the puzzle relates to ensuring we're reasonably
protected against unmarshalling DOS attacks, before proxy trust is
established.
So what I've got here is a small part of a much larger puzzle, I'm very
interested to hear your thoughts, have your input and make changes based
on your recommendations, and admit that the interface below has been
inspired by your work that long preceded it.
Best regards & many thanks,
Peter.
/*
* 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.river.api.lookup;
import java.io.IOException;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.lookup.ServiceItem;
import org.apache.river.api.util.ResultStream;
/**
* Defines the interface to the lookup service. The interface is not a
* remote interface; each implementation of the lookup service exports
* proxy objects that implement the StreamServiceRegistrar interface
local to
* the client, using an implementation-specific protocol to communicate
* with the actual remote server. All of the proxy methods obey normal
* RMI remote interface semantics except where explicitly noted. Two
* proxy objects are equal if they are proxies for the same lookup service.
* Every method invocation (on both StreamServiceRegistrar and
ServiceRegistration)
* is atomic with respect to other invocations.
*
* The StreamServiceRegistrar is intended to perform the same function
* as the ServiceRegistrar, but with the ability to return results as a
* stream, so memory consumption can be minimised at the client.
*
* All clients utilising ServiceRegistrar, should switch to the
* StreamServiceRegistrar.
*
* @see ServiceRegistrar
* @see PortableServiceRegistrar
* @see ServiceRegistration
* @author Peter Firmstone
* @since 2.2.0
*/
public interface StreamServiceRegistrar extends ServiceRegistrar{
/**
* Returns a ResultStream that provides access to MarshalledServiceItem
* instances. The ResultStream terminates with a null value. The
result
* stream may be infinite.
*
* MarshalledServiceItem extends ServiceItem and can be used anywhere a
* ServiceItem can. A MarshalledServiceItem implementation instance
* contains the marshalled form of a Service and it's Entry's,
* the corresponding superclass ServiceItem however contains null values
* for the service and excludes any Entry's that are not
specifically requested
* unmarshalled by this method. The ServiceID will be unmarshalled
always.
*
* This method is designed to allow the caller to control exactly what
* is unmarshalled and when, it allows unmarshalling of specific entries
* that the caller may wish to utilise for filtering. It is
* designed to allow both the caller and the implementer to deal
with very
* large result sets in an incremental fashion.
*
* It is absolutely essential that the caller closes and deletes any
references to
* the returned result stream as soon as it is no longer requried.
*
* @param tmpl template to match
* specified template
* @param unmarshalledEntries only Entry's with these classes will be in
* unmarshalled form.
* @param maxBatchSize Allows the caller to limit the number of results
* held locally, larger batch sizes reduce network traffic, but may
delay
* processing locally depending on implementation.
* @return ResultStream containing ServiceItem's
* @throws java.rmi.RemoteException
* @see MarshalledServiceItem
* @see ServiceItem
* @see ResultStream
* @see ServiceResultStreamFilter
* @see ResultStreamUnmarshaller
* @since 2.2.0
*/
ResultStream lookup(ServiceTemplate tmpl,
Class[] unmarshalledEntries, int maxBatchSize) throws IOException;
/**
* Looks at all service items that match the specified template, finds
* every entry (among those service items) that either doesn't match any
* entry templates or is a subclass of at least one matching entry
* template, and returns the set of the (most specific) classes of those
* entries. Duplicate classes are eliminated, and the order of classes
* within the returned array is arbitrary. Null (not an empty array) is
* returned if there are no such entries or no matching items. If a
* returned class cannot be deserialized, that element of the returned
* array is set to null and no exception is thrown.
*
* @param tmpl template to match
* @param maxBatchSize
* @return a ResultStream containing Class of entry (attribute sets)
for every service
* that matches the specified template
* @throws java.rmi.RemoteException
*/
ResultStream getEntryClasses(ServiceTemplate tmpl, int maxBatchSize)
throws IOException;
/**
* Looks at all service items that match the specified template, finds
* every entry (among those service items) that matches
* tmpl.attributeSetTemplates[setIndex], and returns the set of values
* of the specified field of those entries. Duplicate values are
* eliminated, and the order of values isarbitrary.
* If a returned value cannot be deserialized, that
* element is excluded and no exception is thrown.
*
* @param tmpl template to match
* @param setIndex index into tmpl.attributeSetTemplates
* @param field name of field of tmpl.attributeSetTemplates[setIndex]
*
* @param maxBatchSize
* @return a ResultStream of objects that represents field values of
entries
* associated with services that meet the specified matching
* criteria
*
* @throws NoSuchFieldException field does not name a field of the
* entry template
* @throws java.rmi.RemoteException
*/
ResultStream getFieldValues(ServiceTemplate tmpl, int setIndex,
String field,
int maxBatchSize) throws NoSuchFieldException, IOException;
/**
* Looks at all service items that match the specified template, and for
* every service item finds the most specific type (class or interface)
* or types the service item is an instance of that are neither
equal to,
* nor a superclass of, any of the service types in the template and
that
* have names that start with the specified prefix, and returns the set
* of all such types. Duplicate types are eliminated, and the order of
* types within the returned array is arbitrary.
* Null is returned if there are no such types. If a returned type
* cannot be deserialized, that element is excluded and no exception
is thrown.
*
* @param tmpl template to match
* @param prefix class name prefix
*
* @param maxBatchSize
* @return a ResultStream containing a Class for all services that
either match the
* specified template or match the specified prefix
* @throws java.rmi.RemoteException
*/
ResultStream getServiceTypes(ServiceTemplate tmpl, String prefix,
int maxBatchSize) throws IOException;
}
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
On 2/1/2011 2:30 PM, Christopher Dolan wrote:
> My alternative solution to the same problem as Gregg's was to compute
> SHA-1 hashes of the codebase jars, use that hash in the codebase URLs,
> and aggressively cache the jars client-side via a custom
> URLStreamHandlerFactory implementation instantiated in my
> PreferredClassProvider subclass. It works great -- it dramatically
> reduced startup time after the first deployment and I no longer have to
> worry too much about codebase jar sizes because I almost never need to
> download them. And it didn't require any code changes except in the
> createLoader() method of my PreferredClassProvider subclass.
Even that first "deployment", for me, could not start downloading 100s of jar
files. I did my vhttp: protocol handler for caching first, and it worked for my
"small" early client deployments where only a single client interface was
started and it would see 2-3 instances of the same service that it would list
and let you pick one to access. The slow start up was still disliked and I
heard about the issue from many techs. Even with a progress bar showing the
downloading, indicating why it was not starting yet, they just said, we need to
use the tool, not wait for it to download. I really wanted to use mobile code
though because it make a tremendous difference in the difficulty of deploying
bug fixes and updates. As picky as these people are, getting them to download
and install an update was equally problematic.
In subsequent stages of evolution to the platform, I started adding a whole
group of services/remote tools using Jini based discovery, so they could find an
instance which was reachable, at one of multiple deployment locations. I needed
to put all the tools into one "installed package" and a ServiceUI desktop was a
great way to integrate access to all services.
But, now instead of 3 codebases to resolve, there were 30 or more (10-20 per
machine). I just could not ask my customer to download all of that. I even
pre-populated my vhttp: protocol handlers cache as one form of non-initial
download handling. In the end, eliminating downloading until the service was
requested was the only "complete" solution for me. Everything else just felt
like a bandaid, where as this solution feels complete to me because it addresses
the exact problem by not doing what is unnecessary. If I don't need to have a
definition of a class from a remote server, then don't go there.
I'm glad to hear more about peoples customization of the service activation
steps to learn how different solutions to the same problems I've had, have
worked out.
Gregg
> Chris
>
> -----Original Message-----
> From: Gregg Wonderly [mailto:gregg@wonderly.org]
> Sent: Monday, January 31, 2011 7:30 PM
> To: river-dev@incubator.apache.org
> Subject: Re: MarshalledServiceItem
>
> 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. Ultimately, I wanted to not have to worry
> about how the "codebase" was structured in order to minimize
> downloading. Some Jini deployers have done things to put a small jar at
> the front of the codebase that just has the preferred.list in it. Even
> that download, for me, would have been too much. My customers'
> deployments have nearly 50 codebases visible when my client starts up.
> Those 50 connections over a cellular or other high latency network would
> make service selection take way too long.
>
> 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.
>
> Gregg Wonderly
>
> On Jan 30, 2011, at 2:23 PM, Peter Firmstone wrote:
>
>> Gut feel, tells me the following class is not right, it's intent is to
> provide an api for implementation of delayed unmarshalling and
> provisioning of codebases, for services implementing a lookup service or
> ServiceRegistrar, whilst retaining backward compatibility.
>>
>> In other words, the lookup service proxy would implement it.
>>
>> Thoughts I had were to declare IOException's on methods, and to return
> a String annotation, rather than a URI.
>>
>> What are your thoughts?
>>
>> Cheers,
>>
>> Peter.
>>
>> /*
>> * 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.river.api.lookup;
>>
>> import java.net.URI;
>> import java.security.CodeSource;
>> import net.jini.core.entry.Entry;
>> import net.jini.core.lookup.ServiceID;
>> import net.jini.core.lookup.ServiceItem;
>>
>> /**
>> * MarshalledServiceItem extends ServiceItem and can be used anywhere a
>> * ServiceItem can. A MarshalledServiceItem implementation instance
>> * contains the marshalled form of a Service and it's Entry's,
>> * the corresponding superclass ServiceItem however contains null
> values
>> * for the service and can exclude any Entry's, however where Entry
>> * classes already exist at the client, that they be unmarshalled.
>> *
>> * The ServiceID shall be in unmarshalled form always in the
> ServiceItem super class.
>> *
>> * Since the ServiceItem.service is null, use of this class in existing
> software
>> * will not return the service, however it will not break that software
> as
>> * ServiceItem's contract is to set service or Entry's to null when
> they cannot
>> * be unmarshalled.
>> *
>> * ServiceItem's toString() method will return a different result for
>> * MarshalledServiceItem instances.
>> *
>> * If required, a new ServiceItem that is fully unmarshalled
>> * can be constructed from this class's methods and ServiceID.
>> *
>> * @author Peter Firmstone.
>> */
>> public abstract class MarshalledServiceItem extends ServiceItem{
>> private static final long SerialVersionUID = 1L;
>> protected MarshalledServiceItem(ServiceID id, Entry[]
> unmarshalledEntries){
>> super(id, (Object) null, unmarshalledEntries);
>> }
>> /**
>> * Unmarshall the service proxy.
>> * @param load service with local or existing CodeSource or null for
>> * default.
>> * @return the service proxy, null if class not found.
>> */
>> public abstract Object getService(CodeSource[] code);
>> /**
>> * Unmarshall the Entry's
>> * @return array of Entry's, null entry in array for any class not
> found.
>> */
>> public abstract Entry[] getEntries();
>> public abstract URI[] getAnnotations();
>> }
>>
>
>
RE: MarshalledServiceItem
Posted by Christopher Dolan <ch...@avid.com>.
My alternative solution to the same problem as Gregg's was to compute
SHA-1 hashes of the codebase jars, use that hash in the codebase URLs,
and aggressively cache the jars client-side via a custom
URLStreamHandlerFactory implementation instantiated in my
PreferredClassProvider subclass. It works great -- it dramatically
reduced startup time after the first deployment and I no longer have to
worry too much about codebase jar sizes because I almost never need to
download them. And it didn't require any code changes except in the
createLoader() method of my PreferredClassProvider subclass.
Chris
-----Original Message-----
From: Gregg Wonderly [mailto:gregg@wonderly.org]
Sent: Monday, January 31, 2011 7:30 PM
To: river-dev@incubator.apache.org
Subject: Re: MarshalledServiceItem
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. Ultimately, I wanted to not have to worry
about how the "codebase" was structured in order to minimize
downloading. Some Jini deployers have done things to put a small jar at
the front of the codebase that just has the preferred.list in it. Even
that download, for me, would have been too much. My customers'
deployments have nearly 50 codebases visible when my client starts up.
Those 50 connections over a cellular or other high latency network would
make service selection take way too long.
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.
Gregg Wonderly
On Jan 30, 2011, at 2:23 PM, Peter Firmstone wrote:
> Gut feel, tells me the following class is not right, it's intent is to
provide an api for implementation of delayed unmarshalling and
provisioning of codebases, for services implementing a lookup service or
ServiceRegistrar, whilst retaining backward compatibility.
>
> In other words, the lookup service proxy would implement it.
>
> Thoughts I had were to declare IOException's on methods, and to return
a String annotation, rather than a URI.
>
> What are your thoughts?
>
> Cheers,
>
> Peter.
>
> /*
> * 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.river.api.lookup;
>
> import java.net.URI;
> import java.security.CodeSource;
> import net.jini.core.entry.Entry;
> import net.jini.core.lookup.ServiceID;
> import net.jini.core.lookup.ServiceItem;
>
> /**
> * MarshalledServiceItem extends ServiceItem and can be used anywhere a
> * ServiceItem can. A MarshalledServiceItem implementation instance
> * contains the marshalled form of a Service and it's Entry's,
> * the corresponding superclass ServiceItem however contains null
values
> * for the service and can exclude any Entry's, however where Entry
> * classes already exist at the client, that they be unmarshalled.
> *
> * The ServiceID shall be in unmarshalled form always in the
ServiceItem super class.
> *
> * Since the ServiceItem.service is null, use of this class in existing
software
> * will not return the service, however it will not break that software
as
> * ServiceItem's contract is to set service or Entry's to null when
they cannot
> * be unmarshalled.
> *
> * ServiceItem's toString() method will return a different result for
> * MarshalledServiceItem instances.
> *
> * If required, a new ServiceItem that is fully unmarshalled
> * can be constructed from this class's methods and ServiceID.
> *
> * @author Peter Firmstone.
> */
> public abstract class MarshalledServiceItem extends ServiceItem{
> private static final long SerialVersionUID = 1L;
> protected MarshalledServiceItem(ServiceID id, Entry[]
unmarshalledEntries){
> super(id, (Object) null, unmarshalledEntries);
> }
> /**
> * Unmarshall the service proxy.
> * @param load service with local or existing CodeSource or null for
> * default.
> * @return the service proxy, null if class not found.
> */
> public abstract Object getService(CodeSource[] code);
> /**
> * Unmarshall the Entry's
> * @return array of Entry's, null entry in array for any class not
found.
> */
> public abstract Entry[] getEntries();
> public abstract URI[] getAnnotations();
> }
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Peter Firmstone wrote:
>> I'm looking for the simplest thing that will work, then we can look at
>> additions/extensions. Why tackle complicated downloading/classloading
>> if we
>> can just solve the problem with a simple API extension that gives enough
>> flexibility for the common case?
>>
>
> The simplified MarshalledServiceItem should be capable of that, the
> registrar implementation proxy simply doesn't unmarshall until requested.
>
> Cheers,
>
> Peter.
>>
>>
>>> Hence the method:
>>>
>>>
>>> ResultStream lookup(ServiceTemplate tmpl, Class[]
>>> unmarshalledEntries, int
>>> maxBatchSize) throws IOException;
>>>
>>> But once we have the service we want, we'll need to download the jar
>>> files.
>>>
>>>
>>>
>> Yep,no chance of avoiding that....
>>
>>
>>
>
>
Currently StreamServiceRegistrar has four methods, these are very
similar to existing methods in ServiceRegistrar, the difference is they
return a ResultStream instead of array's, maxBatchSize is an indication
to the registrar proxy, how many records to cache locally:
ResultStream lookup(ServiceTemplate tmpl, Class[] unmarshalledEntries,
int maxBatchSize) throws IOException;
ResultStream getEntryClasses(ServiceTemplate tmpl, int maxBatchSize)
throws IOException;
ResultStream getFieldValues(ServiceTemplate tmpl, int setIndex, String
field, int maxBatchSize) throws NoSuchFieldException, IOException;
ResultStream getServiceTypes(ServiceTemplate tmpl, String prefix, int
maxBatchSize) throws IOException;
Apart from lookup, the additional methods may be useful for querying,
the reasoning is registrars on the internet could potentially have very
large result sets. However as Dennis has suggested, the simplest thing
that will work is to only have the lookup method, which provides to the
registrar proxy, the classes of the Entry's the client is interested in.
What do you think?
Cheers,
Peter.
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
>>> :) Yes, deployment but why are we choosing to deploy with this setup. What
>>> does it imply about services when they share .jar files?
>>>
>>>
>>>
>> Because it becomes difficult to manage with existing tools when a codebase
>> contains multiple jar files for multiple services. I believe that the
>> Codebase service implementors managed to make deployment easier by
>> automating codebase annotations.
>>
>
>
> Or we could build some new tools....
>
>
>
>>
>>>> Again, I'm sitting here thinking as a deployer of services, if I want to
>>>>
>>>>
>>>>
>>>>> widget around and consolidate .jars I can do that ahead of time and then
>>>>> tweak service codebases via config just prior to deploy.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> But it would be faster for the client to receive unconsolidated jar's,
>>>> since other services might use some of these jars also.
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Not for Gregg who hates roundtrips and multiple discoveries of codebases
>>> and
>>> such.
>>>
>>>
>>>
>> If we have the Entry jar files installed at the client or first download
>> the jar files for Entry's we need, using the getEntryClasses method, then we
>> can unmarshall only these entry's which we already have codebases for during
>> lookup, of course at some point we're going to have to download something,
>> but we can avoid downloading the codebases for services we don't need.
>>
>>
>>
>>
>>>
>>>> What matters is the proxy gets the correct class files, in its own
>>>> private
>>>> namespace that are not shared with other proxy's (except for service api,
>>>> which may include Entry's), but we can save duplicate downloads.
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Can you explain your reasoning for saving duplicate downloads? I think you
>>> mean because in some cases service's could share a codebase which they can
>>> do under the current scheme of course. Note that having "correct class
>>> files" isn't IMHO a sufficient constraint, it has to be a "particular
>>> collection of specific implementations of classes and versions".
>>>
>>>
>>>
>> Correct, but it might reduce the size of the download when we've got to
>> bite the bullet and download the service jar files, if we've already got
>> some of the necessary jar's cached locally.
>>
>
>
>
> Size of download is only one thing we need to worry about - latency....
>
Very true, I think the services most suited to low latency connections
will be smart proxy's that communicate with a remote server but do most
things locally.
>
>
>>
>>>
>>>
>>>> Maven provisioning is interesting.
>>>>
>>>> This is why I'm interested to investigate separating jar file identity
>>>> from
>>>> location, to simplify deployment and redundancy. I'm putting my thoughts
>>>> out on the list, to gather responses, to see if there's a better way.
>>>>
>>>>
>>>>
>>> Okay, so I think this also impacts on the stuff being discussed with
>>> Gregg.
>>> Whilst there are some complimentary aspects there are some costly steps in
>>> there as well.
>>>
>>>
>>>
>> The trick is to delay the costly step until we've decided which service
>> instance we want.
>>
>>
>>
>>
>>>
>>>>
>>>>
>>>>>
>>>>>
>>>>>> Jini's lookup service lack of AND / OR querying capability is due to
>>>>>> security, the avoidance of instantiating foreign objects.
>>>>>>
>>>>>> Delayed unmarshalling of the service proxy allows service entry's to be
>>>>>> compared as objects, without requiring a codebase download for the
>>>>>> proxy
>>>>>> if
>>>>>> it's not the service we want, so it's not quite just returning a
>>>>>> MarshalledInstance. This should be done without compromising the good
>>>>>> security features of the existing lookup service.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> I don't follow - I could tweak ServiceItem to hold the proxy as a
>>>>> MarshalledInstance and still expose all other "service identifying
>>>>> information". That MarshalledInstance mightn't even immediately carry
>>>>> the
>>>>> proxy code, could still be on the server and pulled down at point the
>>>>> consumer actually wants the proxy. Feels like some simple
>>>>> interface/sub-classing.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> This is true for cases where the service types don't matter to the
>>>> client,
>>>> I think Gregg wanted to elimate all codebase downloads until he was sure
>>>> he
>>>> had the correct service. Use of a MarshalledInstance could be an
>>>> acceptable
>>>> compromise, if Entry's have their own codebase annotations. How would
>>>> this
>>>> affect the lookup semantics if we're looking for particular service types
>>>> though?
>>>>
>>>>
>>>>
>>> Entry's have to have their own codebase for all cases of clients that
>>> don't
>>> know about those Entry's. Any client that has built-in knowledge of those
>>> Entry's will have them available on the classpath by virtue of it's need
>>> to
>>> specify them in it's lookup search.
>>>
>>>
>>>
>> Except when we call getEntryClasses for a ServiceTemplate and someone's
>> created a new Entry, then we need reflection to get the fields, but that's
>> probably a rare case anyway.
>>
>>
>> Can you explain more about the service types question?
>>
>>>
>> Reggie stores the class types of the service (not class files), so that
>> Reggie can use a ServiceTemplate to retrieve marshalled service proxy's that
>> match the service type defined in the template.
>>
>>
>>
>> If I'm looking for a particular type, I specify a particular interface.
>>
>> Exactly, so if we use a MarshalledInstance when we register the proxy, the
>> only interface (or class in this case) a client can specify is Object or
>> MarshalledInstance.
>>
>>
>>
> Ah, no. MarshalledInstance is the general contract we're talking not the
> implementation. There is nothing to stop us building a subclass or some
> other container that compacts the proxy away but also retains/generates
> sufficient information to allow matching on types.
>
> And in fact, we only need that contract for the client. Registration needn't
> follow that form. Client's also will have Entry types they wish to specify
> for searches on their classpath.
>
> So the codebase trick is asymmetric at least potentially - we do it for
> clients, not services that are registering....
>
>
>
True, which made me think a service interface that extends
ServiceRegistrar, is just a service, which clients can chose to utilise
if they need it, or otherwise just ignore.
It could be similar to reggie with an additional interface, while fully
supporting the existing ServiceRegistrar lookup semantics.
In fact Reggie already has most of the needed pieces.
>> I'm
>>
>>> guessing you mean a service with specific Entry's? A client after some
>>> specific set of Entry's will already know those via classpath. We could
>>> simply allow a client to say "I'm only interested in Services with these
>>> Entry's, return me all matches but only give me the following Entry types
>>> as
>>> part of the ServiceItem". This feels much closer to the original intent
>>> "stop stuff getting to a client that it's not interested in" than trying
>>> to
>>> "control in detail all aspects of download and intimately dig around in
>>> service implementations, including .jars, to do it".
>>>
>>>
>>>
>> I don't think we should dig around in jars etc to do it, just package
>> Entry's separately so we don't have to. By providing the class files for
>> the Entry's we want unmarshalled via the lookup call, we wouldn't need to
>> download their jar files.
>>
>>
>
> Package them separately and put them on client classpaths and then filter.
> In this fashion client has limited knowledge and can protect itself from
> additional knowledge via download side-effects by expressing it's desire to
> only see types it explicitly searches for/considers. Quite simply, if the
> client doesn't have an Entry on its classpath it has next to no interest in
> seeing that stuff.
>
Ok.
> I'm looking for the simplest thing that will work, then we can look at
> additions/extensions. Why tackle complicated downloading/classloading if we
> can just solve the problem with a simple API extension that gives enough
> flexibility for the common case?
>
The simplified MarshalledServiceItem should be capable of that, the
registrar implementation proxy simply doesn't unmarshall until requested.
Cheers,
Peter.
>
>
>> Hence the method:
>>
>>
>> ResultStream lookup(ServiceTemplate tmpl, Class[] unmarshalledEntries, int
>> maxBatchSize) throws IOException;
>>
>> But once we have the service we want, we'll need to download the jar files.
>>
>>
>>
> Yep,no chance of avoiding that....
>
>
>
Re: MarshalledServiceItem
Posted by Tom Hobbs <tv...@googlemail.com>.
I think Michal made a very good suggestion with the invention of a
*new* service type called something like "ServiceBrowserService".
(Good call, Michal!).
Reading the to-ing and fro-ing discussing this use of
MarshalledServiceItem and the use of the lookup service, it does
appear that we're trying to squeeze the LUS into doing something that
it possibly isn't designed to do. As Gregg has demonstrated, it can
be done and made to work well, but what is the cost of the complexity
in the infra/code cleanliness/design/etc?
A client can use a LUS to get *any* SBS, which can return non-domain
specific details describing the available services. (e.g. name :
String, type : Class[], service Id : String, groups : String[], etc).
Potentially clients can be deployed with all the JARs needed to
unmarshal a SBS (so no download needed there), they can then see
what's available view it's UI, and so download only becomes necessary
when the user uses a LUS and details from the SBS to choose their
service.
Maybe this SBS topic needs to be split off into it's own thread.
On Wed, Feb 2, 2011 at 11:00 AM, Dan Creswell <da...@gmail.com> wrote:
> On 2 February 2011 10:33, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>> Dan Creswell wrote:
>>
>>>
>>>>
>>>>> Clarification: Separate the location and identity of a jar file or
>>>>>
>>>>>
>>>> archive containing class files:
>>>>
>>>> We have integrity constraints, which rely on message digests to confirm
>>>> files have not been tampered with.
>>>>
>>>> The message digest (although now considered a weak form of encryption),
>>>> is
>>>> the identity of a jar file, well we use this type of information to
>>>> identify
>>>> it's the jar we expect.
>>>>
>>>> For httpmd, we use a URL string annotation (which could be an IP address
>>>> and port, or a DNS hostname and port), a path and file name, followed by
>>>> the
>>>> message digest.
>>>>
>>>> The IP address or dns hostname , port and path represent the location of
>>>> the jar file, while the file name and message digest represent it's
>>>> identity.
>>>>
>>>> If we separate the location + port, it can be discovered using DNS-SRV
>>>> records, allowing redundant codebase servers, while the identity is
>>>> limited
>>>> to the file name and message digest.
>>>>
>>>> Then the RMI codebase property only needs to be a domain in which a
>>>> suitable codebase can be discovered and queried.
>>>>
>>>>
>>>>
>>>>
>>> Mmm, but the process of resolution on codebases slows things down for
>>> Gregg.
>>>
>>>
>>
>> Correct, Gregg avoids the process of resolution, until it's absolutely
>> necessary, while Chris, caches his jar files after downloading, so he only
>> has to do so once. DNS resolution might take 10 seconds, so this is an
>> important point you've made. A local caching DNS would be advantageous.
>>
>>
>> I think we're gonna have to decide which profiles of machines we're going
>>> to
>>> target with what solutions. I'm not suggesting we try and build for all
>>> the
>>> different profiles more that we'll have to choose what we do and do not
>>> support.
>>> But, if service proxy's are sharing jar files, what does that mean?
>>> Someone
>>>
>>>
>>>> somewhere chose to package them all together like that for some reason.
>>>>> What
>>>>> reason, what problem are they solving?
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Deployment reasons.
>>>>
>>>>
>>>>
>>>>
>>> :) Yes, deployment but why are we choosing to deploy with this setup. What
>>> does it imply about services when they share .jar files?
>>>
>>>
>>
>> Because it becomes difficult to manage with existing tools when a codebase
>> contains multiple jar files for multiple services. I believe that the
>> Codebase service implementors managed to make deployment easier by
>> automating codebase annotations.
>
>
> Or we could build some new tools....
>
>
>>
>>
>>>
>>>> Again, I'm sitting here thinking as a deployer of services, if I want to
>>>>
>>>>
>>>>> widget around and consolidate .jars I can do that ahead of time and then
>>>>> tweak service codebases via config just prior to deploy.
>>>>>
>>>>>
>>>>>
>>>>>
>>>> But it would be faster for the client to receive unconsolidated jar's,
>>>> since other services might use some of these jars also.
>>>>
>>>>
>>>>
>>>>
>>> Not for Gregg who hates roundtrips and multiple discoveries of codebases
>>> and
>>> such.
>>>
>>>
>>
>> If we have the Entry jar files installed at the client or first download
>> the jar files for Entry's we need, using the getEntryClasses method, then we
>> can unmarshall only these entry's which we already have codebases for during
>> lookup, of course at some point we're going to have to download something,
>> but we can avoid downloading the codebases for services we don't need.
>>
>>
>>
>>>
>>>
>>>> What matters is the proxy gets the correct class files, in its own
>>>> private
>>>> namespace that are not shared with other proxy's (except for service api,
>>>> which may include Entry's), but we can save duplicate downloads.
>>>>
>>>>
>>>>
>>>>
>>> Can you explain your reasoning for saving duplicate downloads? I think you
>>> mean because in some cases service's could share a codebase which they can
>>> do under the current scheme of course. Note that having "correct class
>>> files" isn't IMHO a sufficient constraint, it has to be a "particular
>>> collection of specific implementations of classes and versions".
>>>
>>>
>>
>> Correct, but it might reduce the size of the download when we've got to
>> bite the bullet and download the service jar files, if we've already got
>> some of the necessary jar's cached locally.
>
>
> Size of download is only one thing we need to worry about - latency....
>
>
>>
>>
>>>
>>>
>>>
>>>> Maven provisioning is interesting.
>>>>
>>>> This is why I'm interested to investigate separating jar file identity
>>>> from
>>>> location, to simplify deployment and redundancy. I'm putting my thoughts
>>>> out on the list, to gather responses, to see if there's a better way.
>>>>
>>>>
>>>
>>>
>>> Okay, so I think this also impacts on the stuff being discussed with
>>> Gregg.
>>> Whilst there are some complimentary aspects there are some costly steps in
>>> there as well.
>>>
>>>
>>
>> The trick is to delay the costly step until we've decided which service
>> instance we want.
>>
>>
>>
>>>
>>>
>>>>
>>>>
>>>>
>>>>>
>>>>>
>>>>>
>>>>>> Jini's lookup service lack of AND / OR querying capability is due to
>>>>>> security, the avoidance of instantiating foreign objects.
>>>>>>
>>>>>> Delayed unmarshalling of the service proxy allows service entry's to be
>>>>>> compared as objects, without requiring a codebase download for the
>>>>>> proxy
>>>>>> if
>>>>>> it's not the service we want, so it's not quite just returning a
>>>>>> MarshalledInstance. This should be done without compromising the good
>>>>>> security features of the existing lookup service.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> I don't follow - I could tweak ServiceItem to hold the proxy as a
>>>>> MarshalledInstance and still expose all other "service identifying
>>>>> information". That MarshalledInstance mightn't even immediately carry
>>>>> the
>>>>> proxy code, could still be on the server and pulled down at point the
>>>>> consumer actually wants the proxy. Feels like some simple
>>>>> interface/sub-classing.
>>>>>
>>>>>
>>>>>
>>>>>
>>>> This is true for cases where the service types don't matter to the
>>>> client,
>>>> I think Gregg wanted to elimate all codebase downloads until he was sure
>>>> he
>>>> had the correct service. Use of a MarshalledInstance could be an
>>>> acceptable
>>>> compromise, if Entry's have their own codebase annotations. How would
>>>> this
>>>> affect the lookup semantics if we're looking for particular service types
>>>> though?
>>>>
>>>>
>>>
>>>
>>> Entry's have to have their own codebase for all cases of clients that
>>> don't
>>> know about those Entry's. Any client that has built-in knowledge of those
>>> Entry's will have them available on the classpath by virtue of it's need
>>> to
>>> specify them in it's lookup search.
>>>
>>>
>>
>> Except when we call getEntryClasses for a ServiceTemplate and someone's
>> created a new Entry, then we need reflection to get the fields, but that's
>> probably a rare case anyway.
>>
>>
>> Can you explain more about the service types question?
>>>
>>>
>>
>> Reggie stores the class types of the service (not class files), so that
>> Reggie can use a ServiceTemplate to retrieve marshalled service proxy's that
>> match the service type defined in the template.
>>
>>
>>
>> If I'm looking for a particular type, I specify a particular interface.
>>>
>>
>> Exactly, so if we use a MarshalledInstance when we register the proxy, the
>> only interface (or class in this case) a client can specify is Object or
>> MarshalledInstance.
>>
>>
> Ah, no. MarshalledInstance is the general contract we're talking not the
> implementation. There is nothing to stop us building a subclass or some
> other container that compacts the proxy away but also retains/generates
> sufficient information to allow matching on types.
>
> And in fact, we only need that contract for the client. Registration needn't
> follow that form. Client's also will have Entry types they wish to specify
> for searches on their classpath.
>
> So the codebase trick is asymmetric at least potentially - we do it for
> clients, not services that are registering....
>
>
>> I'm
>>> guessing you mean a service with specific Entry's? A client after some
>>> specific set of Entry's will already know those via classpath. We could
>>> simply allow a client to say "I'm only interested in Services with these
>>> Entry's, return me all matches but only give me the following Entry types
>>> as
>>> part of the ServiceItem". This feels much closer to the original intent
>>> "stop stuff getting to a client that it's not interested in" than trying
>>> to
>>> "control in detail all aspects of download and intimately dig around in
>>> service implementations, including .jars, to do it".
>>>
>>>
>>
>> I don't think we should dig around in jars etc to do it, just package
>> Entry's separately so we don't have to. By providing the class files for
>> the Entry's we want unmarshalled via the lookup call, we wouldn't need to
>> download their jar files.
>>
>
> Package them separately and put them on client classpaths and then filter.
> In this fashion client has limited knowledge and can protect itself from
> additional knowledge via download side-effects by expressing it's desire to
> only see types it explicitly searches for/considers. Quite simply, if the
> client doesn't have an Entry on its classpath it has next to no interest in
> seeing that stuff.
>
> I'm looking for the simplest thing that will work, then we can look at
> additions/extensions. Why tackle complicated downloading/classloading if we
> can just solve the problem with a simple API extension that gives enough
> flexibility for the common case?
>
>
>>
>> Hence the method:
>>
>>
>> ResultStream lookup(ServiceTemplate tmpl, Class[] unmarshalledEntries, int
>> maxBatchSize) throws IOException;
>>
>> But once we have the service we want, we'll need to download the jar files.
>>
>>
> Yep,no chance of avoiding that....
>
>
>>
>>
>>>
>>>
>>>
>>>>
>>>>
>>>>>
>>>>>
>>>>>
>>>>>> Over the internet, we could potentially have very large lookup
>>>>>> services,
>>>>>> by
>>>>>> allowing clients to remove unwanted services from their results before
>>>>>> unmarshalling, we can reduce the resources required of the client:
>>>>>>
>>>>>> * Network Bandwidth, clients don't need to download unwanted
>>>>>> codebases.
>>>>>> * Memory (ClassLoader and unwanted classes are not loaded into
>>>>>> memory).
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> If we were to go across internet have we squared away use of e.g.
>>>>> DNS-SD?
>>>>> i.e. Is it a given we'll expose a classic JINI LUS?
>>>>>
>>>>>
>>>>>
>>>>>
>>>> The semantics of DNS-SD make it well suited to discovery of a lookup
>>>> service. I think Sim highlighted earlier that its difficult to get
>>>> domain
>>>> administrators to do Dynamic Updated DNS-SD, they're comfortable with
>>>> DNS-SRV records, so it would appear easier to rely on DNS-SD as a lookup
>>>> locator / domain browser, not as a lookup service replacement.
>>>>
>>>>
>>>>
>>>
>>> Agreed. Solves my concerns of exposing unicast locators of the traditional
>>> type and multicast across the net.
>>>
>>>
>>>
>>>
>> ;)
>>
>> Cheers,
>>
>> Peter.
>>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
On 2 February 2011 10:33, Peter Firmstone <ji...@zeus.net.au> wrote:
> Dan Creswell wrote:
>
>>
>>>
>>>> Clarification: Separate the location and identity of a jar file or
>>>>
>>>>
>>> archive containing class files:
>>>
>>> We have integrity constraints, which rely on message digests to confirm
>>> files have not been tampered with.
>>>
>>> The message digest (although now considered a weak form of encryption),
>>> is
>>> the identity of a jar file, well we use this type of information to
>>> identify
>>> it's the jar we expect.
>>>
>>> For httpmd, we use a URL string annotation (which could be an IP address
>>> and port, or a DNS hostname and port), a path and file name, followed by
>>> the
>>> message digest.
>>>
>>> The IP address or dns hostname , port and path represent the location of
>>> the jar file, while the file name and message digest represent it's
>>> identity.
>>>
>>> If we separate the location + port, it can be discovered using DNS-SRV
>>> records, allowing redundant codebase servers, while the identity is
>>> limited
>>> to the file name and message digest.
>>>
>>> Then the RMI codebase property only needs to be a domain in which a
>>> suitable codebase can be discovered and queried.
>>>
>>>
>>>
>>>
>> Mmm, but the process of resolution on codebases slows things down for
>> Gregg.
>>
>>
>
> Correct, Gregg avoids the process of resolution, until it's absolutely
> necessary, while Chris, caches his jar files after downloading, so he only
> has to do so once. DNS resolution might take 10 seconds, so this is an
> important point you've made. A local caching DNS would be advantageous.
>
>
> I think we're gonna have to decide which profiles of machines we're going
>> to
>> target with what solutions. I'm not suggesting we try and build for all
>> the
>> different profiles more that we'll have to choose what we do and do not
>> support.
>> But, if service proxy's are sharing jar files, what does that mean?
>> Someone
>>
>>
>>> somewhere chose to package them all together like that for some reason.
>>>> What
>>>> reason, what problem are they solving?
>>>>
>>>>
>>>>
>>>>
>>> Deployment reasons.
>>>
>>>
>>>
>>>
>> :) Yes, deployment but why are we choosing to deploy with this setup. What
>> does it imply about services when they share .jar files?
>>
>>
>
> Because it becomes difficult to manage with existing tools when a codebase
> contains multiple jar files for multiple services. I believe that the
> Codebase service implementors managed to make deployment easier by
> automating codebase annotations.
Or we could build some new tools....
>
>
>>
>>> Again, I'm sitting here thinking as a deployer of services, if I want to
>>>
>>>
>>>> widget around and consolidate .jars I can do that ahead of time and then
>>>> tweak service codebases via config just prior to deploy.
>>>>
>>>>
>>>>
>>>>
>>> But it would be faster for the client to receive unconsolidated jar's,
>>> since other services might use some of these jars also.
>>>
>>>
>>>
>>>
>> Not for Gregg who hates roundtrips and multiple discoveries of codebases
>> and
>> such.
>>
>>
>
> If we have the Entry jar files installed at the client or first download
> the jar files for Entry's we need, using the getEntryClasses method, then we
> can unmarshall only these entry's which we already have codebases for during
> lookup, of course at some point we're going to have to download something,
> but we can avoid downloading the codebases for services we don't need.
>
>
>
>>
>>
>>> What matters is the proxy gets the correct class files, in its own
>>> private
>>> namespace that are not shared with other proxy's (except for service api,
>>> which may include Entry's), but we can save duplicate downloads.
>>>
>>>
>>>
>>>
>> Can you explain your reasoning for saving duplicate downloads? I think you
>> mean because in some cases service's could share a codebase which they can
>> do under the current scheme of course. Note that having "correct class
>> files" isn't IMHO a sufficient constraint, it has to be a "particular
>> collection of specific implementations of classes and versions".
>>
>>
>
> Correct, but it might reduce the size of the download when we've got to
> bite the bullet and download the service jar files, if we've already got
> some of the necessary jar's cached locally.
Size of download is only one thing we need to worry about - latency....
>
>
>>
>>
>>
>>> Maven provisioning is interesting.
>>>
>>> This is why I'm interested to investigate separating jar file identity
>>> from
>>> location, to simplify deployment and redundancy. I'm putting my thoughts
>>> out on the list, to gather responses, to see if there's a better way.
>>>
>>>
>>
>>
>> Okay, so I think this also impacts on the stuff being discussed with
>> Gregg.
>> Whilst there are some complimentary aspects there are some costly steps in
>> there as well.
>>
>>
>
> The trick is to delay the costly step until we've decided which service
> instance we want.
>
>
>
>>
>>
>>>
>>>
>>>
>>>>
>>>>
>>>>
>>>>> Jini's lookup service lack of AND / OR querying capability is due to
>>>>> security, the avoidance of instantiating foreign objects.
>>>>>
>>>>> Delayed unmarshalling of the service proxy allows service entry's to be
>>>>> compared as objects, without requiring a codebase download for the
>>>>> proxy
>>>>> if
>>>>> it's not the service we want, so it's not quite just returning a
>>>>> MarshalledInstance. This should be done without compromising the good
>>>>> security features of the existing lookup service.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> I don't follow - I could tweak ServiceItem to hold the proxy as a
>>>> MarshalledInstance and still expose all other "service identifying
>>>> information". That MarshalledInstance mightn't even immediately carry
>>>> the
>>>> proxy code, could still be on the server and pulled down at point the
>>>> consumer actually wants the proxy. Feels like some simple
>>>> interface/sub-classing.
>>>>
>>>>
>>>>
>>>>
>>> This is true for cases where the service types don't matter to the
>>> client,
>>> I think Gregg wanted to elimate all codebase downloads until he was sure
>>> he
>>> had the correct service. Use of a MarshalledInstance could be an
>>> acceptable
>>> compromise, if Entry's have their own codebase annotations. How would
>>> this
>>> affect the lookup semantics if we're looking for particular service types
>>> though?
>>>
>>>
>>
>>
>> Entry's have to have their own codebase for all cases of clients that
>> don't
>> know about those Entry's. Any client that has built-in knowledge of those
>> Entry's will have them available on the classpath by virtue of it's need
>> to
>> specify them in it's lookup search.
>>
>>
>
> Except when we call getEntryClasses for a ServiceTemplate and someone's
> created a new Entry, then we need reflection to get the fields, but that's
> probably a rare case anyway.
>
>
> Can you explain more about the service types question?
>>
>>
>
> Reggie stores the class types of the service (not class files), so that
> Reggie can use a ServiceTemplate to retrieve marshalled service proxy's that
> match the service type defined in the template.
>
>
>
> If I'm looking for a particular type, I specify a particular interface.
>>
>
> Exactly, so if we use a MarshalledInstance when we register the proxy, the
> only interface (or class in this case) a client can specify is Object or
> MarshalledInstance.
>
>
Ah, no. MarshalledInstance is the general contract we're talking not the
implementation. There is nothing to stop us building a subclass or some
other container that compacts the proxy away but also retains/generates
sufficient information to allow matching on types.
And in fact, we only need that contract for the client. Registration needn't
follow that form. Client's also will have Entry types they wish to specify
for searches on their classpath.
So the codebase trick is asymmetric at least potentially - we do it for
clients, not services that are registering....
> I'm
>> guessing you mean a service with specific Entry's? A client after some
>> specific set of Entry's will already know those via classpath. We could
>> simply allow a client to say "I'm only interested in Services with these
>> Entry's, return me all matches but only give me the following Entry types
>> as
>> part of the ServiceItem". This feels much closer to the original intent
>> "stop stuff getting to a client that it's not interested in" than trying
>> to
>> "control in detail all aspects of download and intimately dig around in
>> service implementations, including .jars, to do it".
>>
>>
>
> I don't think we should dig around in jars etc to do it, just package
> Entry's separately so we don't have to. By providing the class files for
> the Entry's we want unmarshalled via the lookup call, we wouldn't need to
> download their jar files.
>
Package them separately and put them on client classpaths and then filter.
In this fashion client has limited knowledge and can protect itself from
additional knowledge via download side-effects by expressing it's desire to
only see types it explicitly searches for/considers. Quite simply, if the
client doesn't have an Entry on its classpath it has next to no interest in
seeing that stuff.
I'm looking for the simplest thing that will work, then we can look at
additions/extensions. Why tackle complicated downloading/classloading if we
can just solve the problem with a simple API extension that gives enough
flexibility for the common case?
>
> Hence the method:
>
>
> ResultStream lookup(ServiceTemplate tmpl, Class[] unmarshalledEntries, int
> maxBatchSize) throws IOException;
>
> But once we have the service we want, we'll need to download the jar files.
>
>
Yep,no chance of avoiding that....
>
>
>>
>>
>>
>>>
>>>
>>>>
>>>>
>>>>
>>>>> Over the internet, we could potentially have very large lookup
>>>>> services,
>>>>> by
>>>>> allowing clients to remove unwanted services from their results before
>>>>> unmarshalling, we can reduce the resources required of the client:
>>>>>
>>>>> * Network Bandwidth, clients don't need to download unwanted
>>>>> codebases.
>>>>> * Memory (ClassLoader and unwanted classes are not loaded into
>>>>> memory).
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> If we were to go across internet have we squared away use of e.g.
>>>> DNS-SD?
>>>> i.e. Is it a given we'll expose a classic JINI LUS?
>>>>
>>>>
>>>>
>>>>
>>> The semantics of DNS-SD make it well suited to discovery of a lookup
>>> service. I think Sim highlighted earlier that its difficult to get
>>> domain
>>> administrators to do Dynamic Updated DNS-SD, they're comfortable with
>>> DNS-SRV records, so it would appear easier to rely on DNS-SD as a lookup
>>> locator / domain browser, not as a lookup service replacement.
>>>
>>>
>>>
>>
>> Agreed. Solves my concerns of exposing unicast locators of the traditional
>> type and multicast across the net.
>>
>>
>>
>>
> ;)
>
> Cheers,
>
> Peter.
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
>>
>>> Clarification: Separate the location and identity of a jar file or
>>>
>> archive containing class files:
>>
>> We have integrity constraints, which rely on message digests to confirm
>> files have not been tampered with.
>>
>> The message digest (although now considered a weak form of encryption), is
>> the identity of a jar file, well we use this type of information to identify
>> it's the jar we expect.
>>
>> For httpmd, we use a URL string annotation (which could be an IP address
>> and port, or a DNS hostname and port), a path and file name, followed by the
>> message digest.
>>
>> The IP address or dns hostname , port and path represent the location of
>> the jar file, while the file name and message digest represent it's
>> identity.
>>
>> If we separate the location + port, it can be discovered using DNS-SRV
>> records, allowing redundant codebase servers, while the identity is limited
>> to the file name and message digest.
>>
>> Then the RMI codebase property only needs to be a domain in which a
>> suitable codebase can be discovered and queried.
>>
>>
>>
> Mmm, but the process of resolution on codebases slows things down for Gregg.
>
Correct, Gregg avoids the process of resolution, until it's absolutely
necessary, while Chris, caches his jar files after downloading, so he
only has to do so once. DNS resolution might take 10 seconds, so this
is an important point you've made. A local caching DNS would be
advantageous.
> I think we're gonna have to decide which profiles of machines we're going to
> target with what solutions. I'm not suggesting we try and build for all the
> different profiles more that we'll have to choose what we do and do not
> support.
>
> But, if service proxy's are sharing jar files, what does that mean? Someone
>
>>> somewhere chose to package them all together like that for some reason.
>>> What
>>> reason, what problem are they solving?
>>>
>>>
>>>
>> Deployment reasons.
>>
>>
>>
> :) Yes, deployment but why are we choosing to deploy with this setup. What
> does it imply about services when they share .jar files?
>
Because it becomes difficult to manage with existing tools when a
codebase contains multiple jar files for multiple services. I believe
that the Codebase service implementors managed to make deployment easier
by automating codebase annotations.
>
>> Again, I'm sitting here thinking as a deployer of services, if I want to
>>
>>> widget around and consolidate .jars I can do that ahead of time and then
>>> tweak service codebases via config just prior to deploy.
>>>
>>>
>>>
>> But it would be faster for the client to receive unconsolidated jar's,
>> since other services might use some of these jars also.
>>
>>
>>
> Not for Gregg who hates roundtrips and multiple discoveries of codebases and
> such.
>
If we have the Entry jar files installed at the client or first download
the jar files for Entry's we need, using the getEntryClasses method,
then we can unmarshall only these entry's which we already have
codebases for during lookup, of course at some point we're going to have
to download something, but we can avoid downloading the codebases for
services we don't need.
>
>
>> What matters is the proxy gets the correct class files, in its own private
>> namespace that are not shared with other proxy's (except for service api,
>> which may include Entry's), but we can save duplicate downloads.
>>
>>
>>
> Can you explain your reasoning for saving duplicate downloads? I think you
> mean because in some cases service's could share a codebase which they can
> do under the current scheme of course. Note that having "correct class
> files" isn't IMHO a sufficient constraint, it has to be a "particular
> collection of specific implementations of classes and versions".
>
Correct, but it might reduce the size of the download when we've got to
bite the bullet and download the service jar files, if we've already got
some of the necessary jar's cached locally.
>
>
>
>> Maven provisioning is interesting.
>>
>> This is why I'm interested to investigate separating jar file identity from
>> location, to simplify deployment and redundancy. I'm putting my thoughts
>> out on the list, to gather responses, to see if there's a better way.
>>
>
>
> Okay, so I think this also impacts on the stuff being discussed with Gregg.
> Whilst there are some complimentary aspects there are some costly steps in
> there as well.
>
The trick is to delay the costly step until we've decided which service
instance we want.
>
>
>>
>>
>>>
>>>
>>>> Jini's lookup service lack of AND / OR querying capability is due to
>>>> security, the avoidance of instantiating foreign objects.
>>>>
>>>> Delayed unmarshalling of the service proxy allows service entry's to be
>>>> compared as objects, without requiring a codebase download for the proxy
>>>> if
>>>> it's not the service we want, so it's not quite just returning a
>>>> MarshalledInstance. This should be done without compromising the good
>>>> security features of the existing lookup service.
>>>>
>>>>
>>>>
>>>>
>>>>
>>> I don't follow - I could tweak ServiceItem to hold the proxy as a
>>> MarshalledInstance and still expose all other "service identifying
>>> information". That MarshalledInstance mightn't even immediately carry the
>>> proxy code, could still be on the server and pulled down at point the
>>> consumer actually wants the proxy. Feels like some simple
>>> interface/sub-classing.
>>>
>>>
>>>
>> This is true for cases where the service types don't matter to the client,
>> I think Gregg wanted to elimate all codebase downloads until he was sure he
>> had the correct service. Use of a MarshalledInstance could be an acceptable
>> compromise, if Entry's have their own codebase annotations. How would this
>> affect the lookup semantics if we're looking for particular service types
>> though?
>>
>
>
> Entry's have to have their own codebase for all cases of clients that don't
> know about those Entry's. Any client that has built-in knowledge of those
> Entry's will have them available on the classpath by virtue of it's need to
> specify them in it's lookup search.
>
Except when we call getEntryClasses for a ServiceTemplate and someone's
created a new Entry, then we need reflection to get the fields, but
that's probably a rare case anyway.
> Can you explain more about the service types question?
>
Reggie stores the class types of the service (not class files), so that
Reggie can use a ServiceTemplate to retrieve marshalled service proxy's
that match the service type defined in the template.
> If I'm looking for a particular type, I specify a particular interface.
Exactly, so if we use a MarshalledInstance when we register the proxy,
the only interface (or class in this case) a client can specify is
Object or MarshalledInstance.
> I'm
> guessing you mean a service with specific Entry's? A client after some
> specific set of Entry's will already know those via classpath. We could
> simply allow a client to say "I'm only interested in Services with these
> Entry's, return me all matches but only give me the following Entry types as
> part of the ServiceItem". This feels much closer to the original intent
> "stop stuff getting to a client that it's not interested in" than trying to
> "control in detail all aspects of download and intimately dig around in
> service implementations, including .jars, to do it".
>
I don't think we should dig around in jars etc to do it, just package
Entry's separately so we don't have to. By providing the class files
for the Entry's we want unmarshalled via the lookup call, we wouldn't
need to download their jar files.
Hence the method:
ResultStream lookup(ServiceTemplate tmpl, Class[] unmarshalledEntries,
int maxBatchSize) throws IOException;
But once we have the service we want, we'll need to download the jar files.
>
>
>
>>
>>>
>>>
>>>> Over the internet, we could potentially have very large lookup services,
>>>> by
>>>> allowing clients to remove unwanted services from their results before
>>>> unmarshalling, we can reduce the resources required of the client:
>>>>
>>>> * Network Bandwidth, clients don't need to download unwanted codebases.
>>>> * Memory (ClassLoader and unwanted classes are not loaded into memory).
>>>>
>>>>
>>>>
>>>>
>>>>
>>> If we were to go across internet have we squared away use of e.g. DNS-SD?
>>> i.e. Is it a given we'll expose a classic JINI LUS?
>>>
>>>
>>>
>> The semantics of DNS-SD make it well suited to discovery of a lookup
>> service. I think Sim highlighted earlier that its difficult to get domain
>> administrators to do Dynamic Updated DNS-SD, they're comfortable with
>> DNS-SRV records, so it would appear easier to rely on DNS-SD as a lookup
>> locator / domain browser, not as a lookup service replacement.
>>
>>
>
> Agreed. Solves my concerns of exposing unicast locators of the traditional
> type and multicast across the net.
>
>
>
;)
Cheers,
Peter.
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
>
>
>> Clarification: Separate the location and identity of a jar file or
> archive containing class files:
>
> We have integrity constraints, which rely on message digests to confirm
> files have not been tampered with.
>
> The message digest (although now considered a weak form of encryption), is
> the identity of a jar file, well we use this type of information to identify
> it's the jar we expect.
>
> For httpmd, we use a URL string annotation (which could be an IP address
> and port, or a DNS hostname and port), a path and file name, followed by the
> message digest.
>
> The IP address or dns hostname , port and path represent the location of
> the jar file, while the file name and message digest represent it's
> identity.
>
> If we separate the location + port, it can be discovered using DNS-SRV
> records, allowing redundant codebase servers, while the identity is limited
> to the file name and message digest.
>
> Then the RMI codebase property only needs to be a domain in which a
> suitable codebase can be discovered and queried.
>
>
Mmm, but the process of resolution on codebases slows things down for Gregg.
I think we're gonna have to decide which profiles of machines we're going to
target with what solutions. I'm not suggesting we try and build for all the
different profiles more that we'll have to choose what we do and do not
support.
But, if service proxy's are sharing jar files, what does that mean? Someone
>> somewhere chose to package them all together like that for some reason.
>> What
>> reason, what problem are they solving?
>>
>>
> Deployment reasons.
>
>
:) Yes, deployment but why are we choosing to deploy with this setup. What
does it imply about services when they share .jar files?
>
> Again, I'm sitting here thinking as a deployer of services, if I want to
>> widget around and consolidate .jars I can do that ahead of time and then
>> tweak service codebases via config just prior to deploy.
>>
>>
>
> But it would be faster for the client to receive unconsolidated jar's,
> since other services might use some of these jars also.
>
>
Not for Gregg who hates roundtrips and multiple discoveries of codebases and
such.
> What matters is the proxy gets the correct class files, in its own private
> namespace that are not shared with other proxy's (except for service api,
> which may include Entry's), but we can save duplicate downloads.
>
>
Can you explain your reasoning for saving duplicate downloads? I think you
mean because in some cases service's could share a codebase which they can
do under the current scheme of course. Note that having "correct class
files" isn't IMHO a sufficient constraint, it has to be a "particular
collection of specific implementations of classes and versions".
> Maven provisioning is interesting.
>
> This is why I'm interested to investigate separating jar file identity from
> location, to simplify deployment and redundancy. I'm putting my thoughts
> out on the list, to gather responses, to see if there's a better way.
Okay, so I think this also impacts on the stuff being discussed with Gregg.
Whilst there are some complimentary aspects there are some costly steps in
there as well.
>
>
>
>>
>>
>>
>>> Jini's lookup service lack of AND / OR querying capability is due to
>>> security, the avoidance of instantiating foreign objects.
>>>
>>> Delayed unmarshalling of the service proxy allows service entry's to be
>>> compared as objects, without requiring a codebase download for the proxy
>>> if
>>> it's not the service we want, so it's not quite just returning a
>>> MarshalledInstance. This should be done without compromising the good
>>> security features of the existing lookup service.
>>>
>>>
>>>
>>>
>> I don't follow - I could tweak ServiceItem to hold the proxy as a
>> MarshalledInstance and still expose all other "service identifying
>> information". That MarshalledInstance mightn't even immediately carry the
>> proxy code, could still be on the server and pulled down at point the
>> consumer actually wants the proxy. Feels like some simple
>> interface/sub-classing.
>>
>>
>
> This is true for cases where the service types don't matter to the client,
> I think Gregg wanted to elimate all codebase downloads until he was sure he
> had the correct service. Use of a MarshalledInstance could be an acceptable
> compromise, if Entry's have their own codebase annotations. How would this
> affect the lookup semantics if we're looking for particular service types
> though?
Entry's have to have their own codebase for all cases of clients that don't
know about those Entry's. Any client that has built-in knowledge of those
Entry's will have them available on the classpath by virtue of it's need to
specify them in it's lookup search.
Can you explain more about the service types question?
If I'm looking for a particular type, I specify a particular interface. I'm
guessing you mean a service with specific Entry's? A client after some
specific set of Entry's will already know those via classpath. We could
simply allow a client to say "I'm only interested in Services with these
Entry's, return me all matches but only give me the following Entry types as
part of the ServiceItem". This feels much closer to the original intent
"stop stuff getting to a client that it's not interested in" than trying to
"control in detail all aspects of download and intimately dig around in
service implementations, including .jars, to do it".
>
>
>>
>>
>>
>>> Over the internet, we could potentially have very large lookup services,
>>> by
>>> allowing clients to remove unwanted services from their results before
>>> unmarshalling, we can reduce the resources required of the client:
>>>
>>> * Network Bandwidth, clients don't need to download unwanted codebases.
>>> * Memory (ClassLoader and unwanted classes are not loaded into memory).
>>>
>>>
>>>
>>>
>> If we were to go across internet have we squared away use of e.g. DNS-SD?
>> i.e. Is it a given we'll expose a classic JINI LUS?
>>
>>
>
> The semantics of DNS-SD make it well suited to discovery of a lookup
> service. I think Sim highlighted earlier that its difficult to get domain
> administrators to do Dynamic Updated DNS-SD, they're comfortable with
> DNS-SRV records, so it would appear easier to rely on DNS-SD as a lookup
> locator / domain browser, not as a lookup service replacement.
>
Agreed. Solves my concerns of exposing unicast locators of the traditional
type and multicast across the net.
>
> Cheers,
>
> Peter.
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
> Ah, I know Sim is gonna hate this but I feel the need to retain full context
> for now....
>
> On 1 February 2011 10:55, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> Dan,
>>
>> I've appended the updated class after our earlier discussion,
>> MarshalledServiceItem, now only has one method as suggested.
>>
>> An option is to consider giving Entry's their own jar files, and to
>> consider doing something about providing a new codebase URL Handler, for
>> separating identity from location, so we can discover the same jar files in
>> other locations,
>>
>
>
> I don't think I understand the separation of identity from location fully
> yet so let's try a framing statement:
>
> A Service's ID and it's type plus some minimum set of Entrys to identify
> pertinent service details is enough isn't it?. And any client wishing to
> identify such a service would require those minimal Entry's (agreed it
> mightn't want the others, could filter that at Lookup Service side such that
> it never gets to the client thus doesn't need downloading).
>
> I don't see the need to play marshalling games so much as delay opening up
> the proxy and limiting the Entry's a client sees to those it declares
> interest in.
>
Clarification: Separate the location and identity of a jar file or
archive containing class files:
We have integrity constraints, which rely on message digests to confirm
files have not been tampered with.
The message digest (although now considered a weak form of encryption),
is the identity of a jar file, well we use this type of information to
identify it's the jar we expect.
For httpmd, we use a URL string annotation (which could be an IP address
and port, or a DNS hostname and port), a path and file name, followed by
the message digest.
The IP address or dns hostname , port and path represent the location of
the jar file, while the file name and message digest represent it's
identity.
If we separate the location + port, it can be discovered using DNS-SRV
records, allowing redundant codebase servers, while the identity is
limited to the file name and message digest.
Then the RMI codebase property only needs to be a domain in which a
suitable codebase can be discovered and queried.
>
>
>> similar to Codebase Services with message digests or Maven Provisioning as
>> suggested by Dennis. This doesn't mean I don't support the idea that the
>> best location for a codebase is at the originating service node, just that
>> it's likely that many service proxy's could share identical jar files, so
>> why should the client re-download something it already has?
>>
>>
>>
> But, if service proxy's are sharing jar files, what does that mean? Someone
> somewhere chose to package them all together like that for some reason. What
> reason, what problem are they solving?
>
Deployment reasons.
> Again, I'm sitting here thinking as a deployer of services, if I want to
> widget around and consolidate .jars I can do that ahead of time and then
> tweak service codebases via config just prior to deploy.
>
But it would be faster for the client to receive unconsolidated jar's,
since other services might use some of these jars also.
What matters is the proxy gets the correct class files, in its own
private namespace that are not shared with other proxy's (except for
service api, which may include Entry's), but we can save duplicate
downloads.
Maven provisioning is interesting.
This is why I'm interested to investigate separating jar file identity
from location, to simplify deployment and redundancy. I'm putting my
thoughts out on the list, to gather responses, to see if there's a
better way.
>
>
>
>> Jini's lookup service lack of AND / OR querying capability is due to
>> security, the avoidance of instantiating foreign objects.
>>
>> Delayed unmarshalling of the service proxy allows service entry's to be
>> compared as objects, without requiring a codebase download for the proxy if
>> it's not the service we want, so it's not quite just returning a
>> MarshalledInstance. This should be done without compromising the good
>> security features of the existing lookup service.
>>
>>
>>
> I don't follow - I could tweak ServiceItem to hold the proxy as a
> MarshalledInstance and still expose all other "service identifying
> information". That MarshalledInstance mightn't even immediately carry the
> proxy code, could still be on the server and pulled down at point the
> consumer actually wants the proxy. Feels like some simple
> interface/sub-classing.
>
This is true for cases where the service types don't matter to the
client, I think Gregg wanted to elimate all codebase downloads until he
was sure he had the correct service. Use of a MarshalledInstance could
be an acceptable compromise, if Entry's have their own codebase
annotations. How would this affect the lookup semantics if we're
looking for particular service types though?
>
>
>
>> Over the internet, we could potentially have very large lookup services, by
>> allowing clients to remove unwanted services from their results before
>> unmarshalling, we can reduce the resources required of the client:
>>
>> * Network Bandwidth, clients don't need to download unwanted codebases.
>> * Memory (ClassLoader and unwanted classes are not loaded into memory).
>>
>>
>>
> If we were to go across internet have we squared away use of e.g. DNS-SD?
> i.e. Is it a given we'll expose a classic JINI LUS?
>
The semantics of DNS-SD make it well suited to discovery of a lookup
service. I think Sim highlighted earlier that its difficult to get
domain administrators to do Dynamic Updated DNS-SD, they're comfortable
with DNS-SRV records, so it would appear easier to rely on DNS-SD as a
lookup locator / domain browser, not as a lookup service replacement.
Cheers,
Peter.
Re: MarshalledServiceItem
Posted by MICHAEL MCGRADY <mm...@topiatechnology.com>.
+1
On Feb 1, 2011, at 6:30 AM, Patricia Shanahan wrote:
> Sim IJskes - QCG wrote:
>> On 01-02-11 12:40, Dan Creswell wrote:
>>> Ah, I know Sim is gonna hate this but I feel the need to retain full context
>>> for now....
>> What i would prefer to see is:
>> - a use case defining internet deployment
>> - a proof of concept prototype implementing this use case
>> - define lessons learned
>> If it turns out that there is something in the lookup what needs improvement, then we can change that.
>> Better not use internet deployment in requirements discussions before whe have defined what it is. Thats too vague for me.
>
> I agree.
>
> If implementing Internet deployment is either impossible regardless of the proposed changes, or can be done well without them, then making the changes would be a mistake.
>
> The easiest way to be sure about this is a use-case and proof of concept prototype. The prototype can be used to demonstrate how proposed River changes contribute to implementing the use-case.
>
> Patricia
>
Michael McGrady
Chief Architect
Topia Technology, Inc.
Cel 1.253.720.3365
Work 1.253.572.9712 extension 2037
mmcgrady@topiatechnology.com
Re: MarshalledServiceItem
Posted by MICHAEL MCGRADY <mm...@topiatechnology.com>.
+1
On Feb 1, 2011, at 6:35 AM, Patricia Shanahan wrote:
> Patricia Shanahan wrote:
>> Sim IJskes - QCG wrote:
>>> On 01-02-11 12:40, Dan Creswell wrote:
>>>> Ah, I know Sim is gonna hate this but I feel the need to retain full context
>>>> for now....
>>>
>>> What i would prefer to see is:
>>> - a use case defining internet deployment
>>> - a proof of concept prototype implementing this use case
>>> - define lessons learned
>>>
>>> If it turns out that there is something in the lookup what needs improvement, then we can change that.
>>>
>>> Better not use internet deployment in requirements discussions before whe have defined what it is. Thats too vague for me.
>> I agree.
>> If implementing Internet deployment is either impossible regardless of the proposed changes, or can be done well without them, then making the changes would be a mistake.
>> The easiest way to be sure about this is a use-case and proof of concept prototype. The prototype can be used to demonstrate how proposed River changes contribute to implementing the use-case.
>
> Note also that even current proposals are exactly right about what needs to be changed in River for Internet deployment, this sequence does not make any change in the total amount of work, just in the order in which it is done.
>
> The use-case is the core of a document explaining how to do Internet deployment, and the proof-of-concept prototype is the foundation for the example code we would need.
>
> Patricia
Michael McGrady
Chief Architect
Topia Technology, Inc.
Cel 1.253.720.3365
Work 1.253.572.9712 extension 2037
mmcgrady@topiatechnology.com
Re: MarshalledServiceItem
Posted by Patricia Shanahan <pa...@acm.org>.
Patricia Shanahan wrote:
> Sim IJskes - QCG wrote:
>> On 01-02-11 12:40, Dan Creswell wrote:
>>> Ah, I know Sim is gonna hate this but I feel the need to retain full
>>> context
>>> for now....
>>
>> What i would prefer to see is:
>> - a use case defining internet deployment
>> - a proof of concept prototype implementing this use case
>> - define lessons learned
>>
>> If it turns out that there is something in the lookup what needs
>> improvement, then we can change that.
>>
>> Better not use internet deployment in requirements discussions before
>> whe have defined what it is. Thats too vague for me.
>
> I agree.
>
> If implementing Internet deployment is either impossible regardless of
> the proposed changes, or can be done well without them, then making the
> changes would be a mistake.
>
> The easiest way to be sure about this is a use-case and proof of concept
> prototype. The prototype can be used to demonstrate how proposed River
> changes contribute to implementing the use-case.
Note also that even current proposals are exactly right about what needs
to be changed in River for Internet deployment, this sequence does not
make any change in the total amount of work, just in the order in which
it is done.
The use-case is the core of a document explaining how to do Internet
deployment, and the proof-of-concept prototype is the foundation for the
example code we would need.
Patricia
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Patricia Shanahan wrote:
> Sim IJskes - QCG wrote:
>> On 01-02-11 12:40, Dan Creswell wrote:
>>> Ah, I know Sim is gonna hate this but I feel the need to retain full
>>> context
>>> for now....
>>
>> What i would prefer to see is:
>> - a use case defining internet deployment
>> - a proof of concept prototype implementing this use case
>> - define lessons learned
>>
>> If it turns out that there is something in the lookup what needs
>> improvement, then we can change that.
>>
>> Better not use internet deployment in requirements discussions before
>> whe have defined what it is. Thats too vague for me.
>
> I agree.
>
> If implementing Internet deployment is either impossible regardless of
> the proposed changes, or can be done well without them, then making
> the changes would be a mistake.
>
> The easiest way to be sure about this is a use-case and proof of
> concept prototype. The prototype can be used to demonstrate how
> proposed River changes contribute to implementing the use-case.
>
> Patricia
>
>
I think we need a standard process for developing and proposing new
components. Gregg provided his reef project in 2006, but I don't think
anyone from the River / Jini community has given much feedback or been
interested in changes to lookup semantics.
Jini was targeted at devices, and corporate networks, but Jini services
are not made available publicly over the internet. Jini was designed
with failure in mind and the 8 fallacies of distributed computing. The
internet is a form of distributed computing.
Jini works well on trusted networks, but untrusted networks are difficult.
Jini works well on networks with high bandwidth low latency, but has
usability issues with low bandwidth and high latency connections, or in
Gregg's case, probably has some issues with high bandwith networks also.
Gregg and Chris have come up with solutions to low bandwith, high
latency networks, but these are still private networks.
So to create a proof of concept prototype for the internet there's a
need to address at least the following issues:
* Low bandwidth high latency connections.
* Security on untrusted networks.
* Firewall traversal.
* Improved service search ability.
* Discovery of internet provided services.
I apologise in advance for use cases, which may or may not be a correct
interpretation of what "Use case" means.
A complex use case might be:
One company has a contract with a second company, a supplier which
provides parts and components the first company uses in manufacture of
it's products, the two company's have formed a contract based on cost
plus markup, where the first company uses the buying power of the second
to take advantage of volume discounts, the companies have agreed on
standard interfaces for jini services. The second company engages
multiple manufacturers of components, these manufacturers provide supply
chain product information, such as models, fit up drawings, pictures and
information relating to the product it sells, each manufacturer utilises
it's own internal systems and use their own Service UI's to display
information regarding supplied components for downstream purchasers and
up to date service bulletins for customers maintenance advise systems,
they also implement standard agreed service interfaces for commerce.
The second company, the supplier, also has other customers, these
company's use the services to enable their different systems to interact
using Jini service interfaces and Service UI's, rather than protocols.
This needs to be done securely and records of all transactions need to
be retained by all parties.
These services are performed over the internet, rather than through
virtual private networks, some applications are required in field for
maintenance and service bulletins, where the network may be third party
or public.
A simple use case might be:
A user browses services online, that perform various functions and are
found using a Jini service browser, all Service UI are downloaded on
demand, applications might range from online sellers and purchasers, to
interactive information, games or online banking.
Cheers,
Peter.
Re: MarshalledServiceItem
Posted by Patricia Shanahan <pa...@acm.org>.
Sim IJskes - QCG wrote:
> On 01-02-11 12:40, Dan Creswell wrote:
>> Ah, I know Sim is gonna hate this but I feel the need to retain full
>> context
>> for now....
>
> What i would prefer to see is:
> - a use case defining internet deployment
> - a proof of concept prototype implementing this use case
> - define lessons learned
>
> If it turns out that there is something in the lookup what needs
> improvement, then we can change that.
>
> Better not use internet deployment in requirements discussions before
> whe have defined what it is. Thats too vague for me.
I agree.
If implementing Internet deployment is either impossible regardless of
the proposed changes, or can be done well without them, then making the
changes would be a mistake.
The easiest way to be sure about this is a use-case and proof of concept
prototype. The prototype can be used to demonstrate how proposed River
changes contribute to implementing the use-case.
Patricia
Re: MarshalledServiceItem
Posted by Sim IJskes - QCG <si...@qcg.nl>.
On 01-02-11 12:40, Dan Creswell wrote:
> Ah, I know Sim is gonna hate this but I feel the need to retain full context
> for now....
What i would prefer to see is:
- a use case defining internet deployment
- a proof of concept prototype implementing this use case
- define lessons learned
If it turns out that there is something in the lookup what needs
improvement, then we can change that.
Better not use internet deployment in requirements discussions before
whe have defined what it is. Thats too vague for me.
Gr. Sim
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
Ah, I know Sim is gonna hate this but I feel the need to retain full context
for now....
On 1 February 2011 10:55, Peter Firmstone <ji...@zeus.net.au> wrote:
> Dan,
>
> I've appended the updated class after our earlier discussion,
> MarshalledServiceItem, now only has one method as suggested.
>
> An option is to consider giving Entry's their own jar files, and to
> consider doing something about providing a new codebase URL Handler, for
> separating identity from location, so we can discover the same jar files in
> other locations,
I don't think I understand the separation of identity from location fully
yet so let's try a framing statement:
A Service's ID and it's type plus some minimum set of Entrys to identify
pertinent service details is enough isn't it?. And any client wishing to
identify such a service would require those minimal Entry's (agreed it
mightn't want the others, could filter that at Lookup Service side such that
it never gets to the client thus doesn't need downloading).
I don't see the need to play marshalling games so much as delay opening up
the proxy and limiting the Entry's a client sees to those it declares
interest in.
> similar to Codebase Services with message digests or Maven Provisioning as
> suggested by Dennis. This doesn't mean I don't support the idea that the
> best location for a codebase is at the originating service node, just that
> it's likely that many service proxy's could share identical jar files, so
> why should the client re-download something it already has?
>
>
But, if service proxy's are sharing jar files, what does that mean? Someone
somewhere chose to package them all together like that for some reason. What
reason, what problem are they solving?
Again, I'm sitting here thinking as a deployer of services, if I want to
widget around and consolidate .jars I can do that ahead of time and then
tweak service codebases via config just prior to deploy.
> Jini's lookup service lack of AND / OR querying capability is due to
> security, the avoidance of instantiating foreign objects.
>
> Delayed unmarshalling of the service proxy allows service entry's to be
> compared as objects, without requiring a codebase download for the proxy if
> it's not the service we want, so it's not quite just returning a
> MarshalledInstance. This should be done without compromising the good
> security features of the existing lookup service.
>
>
I don't follow - I could tweak ServiceItem to hold the proxy as a
MarshalledInstance and still expose all other "service identifying
information". That MarshalledInstance mightn't even immediately carry the
proxy code, could still be on the server and pulled down at point the
consumer actually wants the proxy. Feels like some simple
interface/sub-classing.
> Over the internet, we could potentially have very large lookup services, by
> allowing clients to remove unwanted services from their results before
> unmarshalling, we can reduce the resources required of the client:
>
> * Network Bandwidth, clients don't need to download unwanted codebases.
> * Memory (ClassLoader and unwanted classes are not loaded into memory).
>
>
If we were to go across internet have we squared away use of e.g. DNS-SD?
i.e. Is it a given we'll expose a classic JINI LUS?
> The intent behind MarshalledServiceItem, is the entry's available for
> comparison are only those required by the client, these can be loaded into a
> child classloader (if they don't exist on the classpath) and shared by all
> MarshalledServiceItem instances. You wouldn't require the Entry for a
> ServiceUI without it's service proxy for instance.
>
>
I think I get the intent but I'm far from convinced that all these
marshalling games and such are necessary (see above framing comment).
> After the MarshalledServiceItem has been unmarshalled, the Entry's can be
> from the classpath and the proxy's classloader (meaning we might need to
> unmarshall some Entry's a second time).
>
> I don't doubt the requirement for more efficient and flexible means of
> service lookup, just the interfaces so far proposed, which is why I'm giving
> it lots of time & hoping for plenty of review, before setting it in stone.
>
> The reality is the line between private networks and the internet is
> blurring, in spite of router NAT. The internet is the market most ready to
> try different ideas like Jini / River, the corporate intranet is the least
> likely place and for political reasons more than technical ones. I'd like
> to take River where it hasn't been, where there are no users at present to
> justify such a feature.
>
> Yeah I know there are other issues that need solving, like firewall
> traversal.
>
> P.S. Hope you're feeling better after the coffee ;)
>
>
Ops mess hasn't cleared up so alas, no :)
>
> Cheers,
>
>
Thanks for tolerating my rantiness!
> Peter.
>
> 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. Ultimately, I wanted to not have to worry about how
>>> the
>>> "codebase" was structured in order to minimize downloading. Some Jini
>>> deployers have done things to put a small jar at the front of the
>>> codebase
>>> that just has the preferred.list in it. Even that download, for me,
>>> would
>>> have been too much. My customers' deployments have nearly 50 codebases
>>> visible when my client starts up. Those 50 connections over a cellular
>>> or
>>> other high latency network would make service selection take way too
>>> long.
>>>
>>>
>>>
>>>
>> "deserialization of Entry's from the service object"? What does "service
>> object" refer to?
>>
>> I think you _have_ to worry about how the codebase is structured. Anything
>> else is a hack and if we're going to do hacks there are better ones like
>> bundling up people's .jars for them etc so save on connections/add caching
>> and such. Doing it further downstream in the lookup mechanism is treating
>> a
>> symptom not the problem. Not the sort of thing that keeps a design clean
>> or
>> consistent.
>>
>>
>>
>> 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.
>>
>> Which brings me to a point Peter made elsewhere: "delayed umarshalling and
>> selective unmarshalling of Entry's are very important features, missing
>> from
>> River."
>>
>> Important to whom? How many people are in the category?
>>
>> If it's a lot of people, we should spend some time evaluating whether the
>> default class resolution/download/lookup approach is the generic norm and
>> potential replacements.
>>
>> Simplistically, delaying downloading is as simple as returning a
>> MarshalledInstance on which one can then call .get as and when one
>> desires.....
>>
>> Now, I haven't had my coffee yet and I've got a pile of operational
>> worries
>> to attend to this morning which means I'm maybe a little shout'y,
>> nevertheless I for one am not convinced of the value of this and less
>> convinced we have the right solution which feels complex, exceptional and
>> clunky.
>>
>>
>>
>>
> /*
> * 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.river.api.lookup;
>
> import java.net.URI;
> import java.security.CodeSource;
> import net.jini.core.entry.Entry;
> import net.jini.core.lookup.ServiceID;
> import net.jini.core.lookup.ServiceItem;
>
> /**
> * MarshalledServiceItem extends ServiceItem and can be used anywhere a
> * ServiceItem can. A MarshalledServiceItem implementation instance
> * contains the marshalled form of a Service and it's Entry's,
> * the corresponding superclass ServiceItem however contains null values
> * for the service and can exclude any Entry's, however where Entry
> * classes already exist at the client, that they be unmarshalled.
> *
> * The ServiceID shall be in unmarshalled form always in the ServiceItem
> super class.
> *
> * Since the ServiceItem.service is null, use of this class in existing
> software
> * will not return the service, however it will not break that software as
> * ServiceItem's contract is to set service or Entry's to null when they
> cannot
> * be unmarshalled.
> *
> * ServiceItem's toString() method will return a different result for
> * MarshalledServiceItem instances.
> *
> * If required, a new ServiceItem that is fully unmarshalled
> * can be constructed from this class's methods and ServiceID.
> *
> * @author Peter Firmstone.
> */
> public abstract class MarshalledServiceItem extends ServiceItem{
> private static final long SerialVersionUID = 1L;
> protected MarshalledServiceItem(ServiceID id, Entry[]
> unmarshalledEntries){
> super(id, (Object) null, unmarshalledEntries);
> }
> /**
> * Unmarshall the ServiceItem. The returned ServiceItem may have a null
> service
> * or entries , if unmarshalling is unsuccessful.
> *
> * @return ServiceItem, totally unmarshalled.
> */
> public abstract ServiceItem unmarshall();
> }
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan,
I've appended the updated class after our earlier discussion,
MarshalledServiceItem, now only has one method as suggested.
An option is to consider giving Entry's their own jar files, and to
consider doing something about providing a new codebase URL Handler, for
separating identity from location, so we can discover the same jar files
in other locations, similar to Codebase Services with message digests or
Maven Provisioning as suggested by Dennis. This doesn't mean I don't
support the idea that the best location for a codebase is at the
originating service node, just that it's likely that many service
proxy's could share identical jar files, so why should the client
re-download something it already has?
Jini's lookup service lack of AND / OR querying capability is due to
security, the avoidance of instantiating foreign objects.
Delayed unmarshalling of the service proxy allows service entry's to be
compared as objects, without requiring a codebase download for the proxy
if it's not the service we want, so it's not quite just returning a
MarshalledInstance. This should be done without compromising the good
security features of the existing lookup service.
Over the internet, we could potentially have very large lookup services,
by allowing clients to remove unwanted services from their results
before unmarshalling, we can reduce the resources required of the client:
* Network Bandwidth, clients don't need to download unwanted codebases.
* Memory (ClassLoader and unwanted classes are not loaded into memory).
The intent behind MarshalledServiceItem, is the entry's available for
comparison are only those required by the client, these can be loaded
into a child classloader (if they don't exist on the classpath) and
shared by all MarshalledServiceItem instances. You wouldn't require the
Entry for a ServiceUI without it's service proxy for instance.
After the MarshalledServiceItem has been unmarshalled, the Entry's can
be from the classpath and the proxy's classloader (meaning we might need
to unmarshall some Entry's a second time).
I don't doubt the requirement for more efficient and flexible means of
service lookup, just the interfaces so far proposed, which is why I'm
giving it lots of time & hoping for plenty of review, before setting it
in stone.
The reality is the line between private networks and the internet is
blurring, in spite of router NAT. The internet is the market most ready
to try different ideas like Jini / River, the corporate intranet is the
least likely place and for political reasons more than technical ones.
I'd like to take River where it hasn't been, where there are no users at
present to justify such a feature.
Yeah I know there are other issues that need solving, like firewall
traversal.
P.S. Hope you're feeling better after the coffee ;)
Cheers,
Peter.
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. Ultimately, I wanted to not have to worry about how the
>> "codebase" was structured in order to minimize downloading. Some Jini
>> deployers have done things to put a small jar at the front of the codebase
>> that just has the preferred.list in it. Even that download, for me, would
>> have been too much. My customers' deployments have nearly 50 codebases
>> visible when my client starts up. Those 50 connections over a cellular or
>> other high latency network would make service selection take way too long.
>>
>>
>>
> "deserialization of Entry's from the service object"? What does "service
> object" refer to?
>
> I think you _have_ to worry about how the codebase is structured. Anything
> else is a hack and if we're going to do hacks there are better ones like
> bundling up people's .jars for them etc so save on connections/add caching
> and such. Doing it further downstream in the lookup mechanism is treating a
> symptom not the problem. Not the sort of thing that keeps a design clean or
> consistent.
>
>
>
> 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.
>
> Which brings me to a point Peter made elsewhere: "delayed umarshalling and
> selective unmarshalling of Entry's are very important features, missing from
> River."
>
> Important to whom? How many people are in the category?
>
> If it's a lot of people, we should spend some time evaluating whether the
> default class resolution/download/lookup approach is the generic norm and
> potential replacements.
>
> Simplistically, delaying downloading is as simple as returning a
> MarshalledInstance on which one can then call .get as and when one
> desires.....
>
> Now, I haven't had my coffee yet and I've got a pile of operational worries
> to attend to this morning which means I'm maybe a little shout'y,
> nevertheless I for one am not convinced of the value of this and less
> convinced we have the right solution which feels complex, exceptional and
> clunky.
>
>
>
/*
* 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.river.api.lookup;
import java.net.URI;
import java.security.CodeSource;
import net.jini.core.entry.Entry;
import net.jini.core.lookup.ServiceID;
import net.jini.core.lookup.ServiceItem;
/**
* MarshalledServiceItem extends ServiceItem and can be used anywhere a
* ServiceItem can. A MarshalledServiceItem implementation instance
* contains the marshalled form of a Service and it's Entry's,
* the corresponding superclass ServiceItem however contains null values
* for the service and can exclude any Entry's, however where Entry
* classes already exist at the client, that they be unmarshalled.
*
* The ServiceID shall be in unmarshalled form always in the ServiceItem
super class.
*
* Since the ServiceItem.service is null, use of this class in existing
software
* will not return the service, however it will not break that software as
* ServiceItem's contract is to set service or Entry's to null when they
cannot
* be unmarshalled.
*
* ServiceItem's toString() method will return a different result for
* MarshalledServiceItem instances.
*
* If required, a new ServiceItem that is fully unmarshalled
* can be constructed from this class's methods and ServiceID.
*
* @author Peter Firmstone.
*/
public abstract class MarshalledServiceItem extends ServiceItem{
private static final long SerialVersionUID = 1L;
protected MarshalledServiceItem(ServiceID id, Entry[]
unmarshalledEntries){
super(id, (Object) null, unmarshalledEntries);
}
/**
* Unmarshall the ServiceItem. The returned ServiceItem may have a
null service
* or entries , if unmarshalling is unsuccessful.
*
* @return ServiceItem, totally unmarshalled.
*/
public abstract ServiceItem unmarshall();
}
Re: MarshalledServiceItem
Posted by Michał Kłeczek <mi...@xpro.biz>.
Regardless of whether LUS should be used for service browsing or
another service should be used - I can see the issue with
PREFERRED.LIST. It is really unfortunate that the client must download
something just to make a decision whether it must download anything...
Thinking out loud - isn't it (yet another) case for annotating classes
with objects - as I proposed in another thread discussing possible
unmarshalling DoS attacks. That way we could provide the client with
some class loading information (namely - preferred list but possibly
something else as well) in band while still maintaining out of band
code download.
Michal
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
ClasspathRestrictedServiceItem?
Dan Creswell wrote:
> Thing is the ServiceItem is not the thing being resolved....
>
> On 3 February 2011 09:59, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> How about LocallyResolvedServiceItem?
>>
>>
>> Dan Creswell wrote:
>>
>>
>>> Sure, the method does indeed unmarshall but within specific constraints
>>> and
>>> those constraints are defined by the enclosing class (an instance of
>>> ServiceItem in this case).
>>>
>>> So I'm thinking we're really talking about is a ServiceItem that pulls
>>> from
>>> classpath so maybe LocallyResolvingServiceItem (not entirely keen on that
>>> but explains what's happening).
>>>
>>> On some level there's a bit of me that screams we have a broken design if
>>> we
>>> can't get decent names.....
>>>
>>> On 3 February 2011 09:10, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>
>>>
>>>
>>>
>>>> Dan Creswell wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> "In summary MarshalledServiceItem is a class that only resolves local
>>>>> code.
>>>>> Interestingly MarshalledServiceItem, might not be an appropriate name,
>>>>> perhaps LocalServiceItem to indicate that only local code is utilised,
>>>>> on
>>>>> this reasoning, I can't see any objection to reflective proxy's being
>>>>> non
>>>>> null either."
>>>>>
>>>>> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
>>>>> what's going on.....
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> The method unmarshall, sort of makes sense, can you think of a better
>>>> name?
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
We're not matching, we're filtering to ignore attributes we have no interest
in (which in turn avoids unnecessary codebase access). So we're simply
indicating the types of things we are prepared to accept thus:
ServiceInfo.class, Name.class
As opposed to:
new ServiceInfo(....), new Name(.....)
Matching is done as a standard part of lookup and is tuplespace'ish already.
On 5 February 2011 19:41, <jg...@simulexinc.com> wrote:
> To state the obvious, matching entries that the client passes in sounds
> like tuplespace template matching.
>
> Perhaps this is a case where we'd benefit from having around a tuplespace
> data structure, in addition to the service?
>
> jamesG
>
> -----Original Message-----
> From: "Peter Firmstone" <ji...@zeus.net.au>
> Sent: Saturday, February 5, 2011 5:28am
> To: river-dev@incubator.apache.org
> Subject: Re: MarshalledServiceItem
>
> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>
> So we make the Entry's the client's interested in, the only Entry's
> that'll be unmarshalled, those and the ServiceID.
>
> Cheers,
>
> Peter.
>
>
>
Re: MarshalledServiceItem
Posted by jg...@simulexinc.com.
To state the obvious, matching entries that the client passes in sounds like tuplespace template matching.
Perhaps this is a case where we'd benefit from having around a tuplespace data structure, in addition to the service?
jamesG
-----Original Message-----
From: "Peter Firmstone" <ji...@zeus.net.au>
Sent: Saturday, February 5, 2011 5:28am
To: river-dev@incubator.apache.org
Subject: Re: MarshalledServiceItem
Ok, good reasoning, we can keep the Entry's explicit, in the call.
So we make the Entry's the client's interested in, the only Entry's
that'll be unmarshalled, those and the ServiceID.
Cheers,
Peter.
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Ok, done.
Dan Creswell wrote:
> Solid - probably ought to be a constructor that doesn't add defaults
> too.....and maybe a note about thread safety on add.
>
> On 7 February 2011 04:29, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> Dan Creswell wrote:
>>
>>
>>> Sorry, what you meant was the builder generates a default array or Set of
>>>
>>>> Entry classes required to support the platform, additional Entry classes
>>>> the
>>>> client needs can be added, then it builds the array to pass as a
>>>> parameter
>>>> to the lookup service.
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Yep.
>>>
>>>
>>>
>>>
>>>
>> How's this?
>>
>> Cheers,
>>
>> Peter.
>>
>>
>> /*
>> * 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.river.api.lookup;
>>
>> import java.util.HashSet;
>> import java.util.Set;
>> import net.jini.lookup.entry.Address;
>> import net.jini.lookup.entry.Comment;
>> import net.jini.lookup.entry.Location;
>> import net.jini.lookup.entry.Name;
>> import net.jini.lookup.entry.ServiceInfo;
>> import net.jini.lookup.entry.Status;
>> import net.jini.lookup.entry.UIDescriptor;
>>
>> /**
>> * A little builder utility class that creates an array of Entry classes to
>> * be used as a parameter for StreamServiceRegistrar. All the platform
>> * Entry's are included.
>> *
>> * Suggested by Dan Creswell.
>> * @author peter
>> */
>> public class DefaultEntries {
>> private final Set<Class> entrys;
>> public DefaultEntries() {
>> entrys = new HashSet<Class>(16);
>> add(Comment.class);
>> add(Location.class);
>> add(Name.class);
>> add(ServiceInfo.class);
>> add(Status.class);
>> add(UIDescriptor.class);
>> add(Address.class);
>> }
>> public DefaultEntries add(Class cl){
>> entrys.add(cl);
>> return this;
>> }
>> public Class[] getEntries(){
>> return entrys.toArray(new Class[entrys.size()]);
>> }
>>
>> }
>>
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Sim IJskes - QCG <si...@qcg.nl>.
On 07-02-11 11:56, Peter Firmstone wrote:
> @Override
> public String toString(){
> String newline = System.getProperty("line.separator");
> StringBuilder sb = new StringBuilder(256);
> sb.append("DefaultEntries:");
> sb.append(newline);
> Iterator<Class> it = entrys.iterator();
> while (it.hasNext()){
> sb.append(it.next().getName());
> sb.append(newline);
> }
> return sb.toString();
> }
Can we have the toString fitting in 1 line, ex [a,b,c] prefixed with
Class.getSimpleName()?
Gr. Sim
Re: MarshalledServiceItem
Posted by Peter <ji...@zeus.net.au>.
----- Original message -----
> Gregg Wonderly wrote:
> > On 2/8/2011 10:51 AM, Patricia Shanahan wrote:
> > > There are some negatives to using CHM compared to wrapping a HashMap in a
> > > synchronized map. It is easy to write methods for compound operations
> > > such as
> > > removing a key-value pair if, and only if, some other key is present.
> >
> > Yes, this is true. If we do need some compound operations, then it
> > would be necessary to add a lock to synchronize on, and then everything
> > else referencing the structure would need to be synchronized since CHM
> > uses internal locking which does not involve synchronized(this).
>
> Or switch implementations if there is a problem with the initial choice.
> If the code uses the Map interface, implemented by both CHM and a
> synchronized map wrapping a HashMap, it should just be a matter of
> changing the initialization expression.
>
> Patricia
Well almost, put if absent requires a check on the return value, often you need to create a new object, then do a put if absent, if there was an intervening put, throw away the new object and instead use the existing one.
The synchronised collections wrappers are directly substitutable, I've created similar multi read single write wrappers that are directly substitutable, these also return a snapshot iterator that won't throw a concurrent modification exception.
The good part about using the wrappers is that concurrency concerns are not reimplemented in each class, instead you've only got one place to do concurrency debugging and maintenance.
Peter.
Re: MarshalledServiceItem
Posted by Patricia Shanahan <pa...@acm.org>.
Gregg Wonderly wrote:
> On 2/8/2011 10:51 AM, Patricia Shanahan wrote:
>> There are some negatives to using CHM compared to wrapping a HashMap in a
>> synchronized map. It is easy to write methods for compound operations
>> such as
>> removing a key-value pair if, and only if, some other key is present.
>
> Yes, this is true. If we do need some compound operations, then it
> would be necessary to add a lock to synchronize on, and then everything
> else referencing the structure would need to be synchronized since CHM
> uses internal locking which does not involve synchronized(this).
Or switch implementations if there is a problem with the initial choice.
If the code uses the Map interface, implemented by both CHM and a
synchronized map wrapping a HashMap, it should just be a matter of
changing the initialization expression.
Patricia
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
On 2/8/2011 10:51 AM, Patricia Shanahan wrote:
> There are some negatives to using CHM compared to wrapping a HashMap in a
> synchronized map. It is easy to write methods for compound operations such as
> removing a key-value pair if, and only if, some other key is present.
Yes, this is true. If we do need some compound operations, then it would be
necessary to add a lock to synchronize on, and then everything else referencing
the structure would need to be synchronized since CHM uses internal locking
which does not involve synchronized(this).
Gregg Wonderly
>
> On 2/8/2011 8:26 AM, Dan Creswell wrote:
>> No friction, simplest thing that could possibly work is the only thing
>> running through my head.
>>
>> I'm happy to see CHM used if people deem it appropriate - as is so often the
>> case, I'm not writing the code so my opinion should only carry so much
>> weight.
>>
>> On 8 February 2011 15:12, Gregg Wonderly<gr...@wonderly.org> wrote:
>>
>>> On 2/8/2011 9:00 AM, Dan Creswell wrote:
>>>
>>>> It's all about expected usage patterns.
>>>>
>>>> Locking in this case will be per instance and the likelihood of contention
>>>> is low given no one's going to call add a lot or indeed toString a lot in
>>>> a
>>>> short space of time.
>>>>
>>>> So given:
>>>>
>>>> Define how concurrency is handled then implement
>>>>
>>>> And assuming it's in line with the above contention model I'd say
>>>> synchronized would be adequate.
>>>>
>>>
>>> I believe this is the case. But, I also know that it can come back to
>>> bite.
>>>
>>> CHM solves it without synchronized, and that, I believe is a better choice
>>> because it eliminates the problem. Any additional methods or usage patterns
>>> that fall out of the life cycle of this object will not have any new or
>>> different behavior or synchronization requirements.
>>>
>>> Is there an attribute of CHM that you find unattractive Dan? I'm not sure
>>> I understand the friction I am sensing.
>>>
>>> Gregg
>>>
>>>
>>> On 8 February 2011 14:54, Gregg Wonderly<gr...@wonderly.org> wrote:
>>>>
>>>> On 2/7/2011 5:28 PM, Peter Firmstone wrote:
>>>>>
>>>>> Do we really need a concurrent version of this class? How often will
>>>>>> Entry
>>>>>> classes change?
>>>>>>
>>>>>>
>>>>> My choice is always to consider concurrency first, unless there is some
>>>>> element of performance that this impacts. The simple fact is that there
>>>>> is
>>>>> a toString() that traverses the contents. So, you either must
>>>>> synchronize
>>>>> all access to the contents, or use a CHM which solves the problem without
>>>>> any future concurrency surprises.
>>>>>
>>>>> I'm really serious about this, because of how I've encountered tons of
>>>>> "synchronized" blocks in river which introduce huge latency in
>>>>> "processing"
>>>>> because they cause everyone to wait in line for stuff which very often is
>>>>> quite independent.
>>>>>
>>>>> Yes, this structure is mostly one time mutated. But, its design exposes
>>>>> a
>>>>> continuous mutation capability. Thus, any "read" of the contents has to
>>>>> take that into account.
>>>>>
>>>>> Gregg Wonderly
>>>>>
>>>>>
>>>>> Gregg Wonderly wrote:
>>>>>
>>>>>>
>>>>>> Yes definitely the case. CHM just makes it a lot easier to not worry
>>>>>>> about map
>>>>>>> and set data structures in terms of concurrent access of mutating data.
>>>>>>> Set
>>>>>>> and HashSet are useful, but not always in concurrent mutating data
>>>>>>> management.
>>>>>>>
>>>>>>> I still prefer Vector over ArrayList just because it eliminates
>>>>>>> iteration
>>>>>>> problems that alway require the same lines of code to resolve.
>>>>>>>
>>>>>>> Gregg
>>>>>>>
>>>>>>> Sent from my iPhone
>>>>>>>
>>>>>>> On Feb 7, 2011, at 2:08 PM, Dan Creswell<da...@gmail.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>> All true, still need to document the concurrent contract for this
>>>>>>> class
>>>>>>>
>>>>>>>> and
>>>>>>>> implement accordingly.
>>>>>>>>
>>>>>>>> i.e. We can say "toString" is thread safe etc and then use
>>>>>>>> ConcurrentHashMap
>>>>>>>> and friends.
>>>>>>>>
>>>>>>>> But we gotta do it right....
>>>>>>>>
>>>>>>>> On 7 February 2011 19:57, Gregg Wonderly<gr...@wonderly.org> wrote:
>>>>>>>>
>>>>>>>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Sorry, I've got my nit-picking hat on...
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> The null check in the equals method isn't needed because you get a
>>>>>>>>>> free one by using "instanceof".
>>>>>>>>>>
>>>>>>>>>> I know you've warned that the class is not thread-safe, but people
>>>>>>>>>> often forget that doing a sysout of an object calls toString(). I'd
>>>>>>>>>> still be tempted to whack some protection into toString to stop it
>>>>>>>>>> blowing up when people start printing lots of debug messages.
>>>>>>>>>>
>>>>>>>>>> Other than that it looks good to me.
>>>>>>>>>>
>>>>>>>>>> I'd suggest that it would be easy enough to just use
>>>>>>>>>>
>>>>>>>>> ConcurrentHashMap
>>>>>>>>> instead of HashSet if we are going to move to Java 5 anyway. Then,
>>>>>>>>> you
>>>>>>>>> don't have to worry about concurrency issues with toString() etc.
>>>>>>>>>
>>>>>>>>> Gregg Wonderly
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>>>>>>>>
>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> Dan Creswell wrote:
>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Solid - probably ought to be a constructor that doesn't add
>>>>>>>>>>> defaults
>>>>>>>>>>>
>>>>>>>>>>>> too.....and maybe a note about thread safety on add.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> The finished article.
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> /*
>>>>>>>>>>> * 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.river.api.lookup;
>>>>>>>>>>>
>>>>>>>>>>> import java.util.HashSet;
>>>>>>>>>>> import java.util.Iterator;
>>>>>>>>>>> import java.util.Set;
>>>>>>>>>>> import net.jini.lookup.entry.Address;
>>>>>>>>>>> import net.jini.lookup.entry.Comment;
>>>>>>>>>>> import net.jini.lookup.entry.Location;
>>>>>>>>>>> import net.jini.lookup.entry.Name;
>>>>>>>>>>> import net.jini.lookup.entry.ServiceInfo;
>>>>>>>>>>> import net.jini.lookup.entry.Status;
>>>>>>>>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>>>>>>>>
>>>>>>>>>>> /**
>>>>>>>>>>> * A little builder utility class that creates an array of Entry
>>>>>>>>>>> classes
>>>>>>>>>>> to
>>>>>>>>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>>>>>>>>> platform
>>>>>>>>>>> * Entry's are included by default.
>>>>>>>>>>> *
>>>>>>>>>>> * Note: This class is not threadsafe, use external synchronization
>>>>>>>>>>> if
>>>>>>>>>>> required.
>>>>>>>>>>> *
>>>>>>>>>>> * Suggested by Dan Creswell.
>>>>>>>>>>> * @author peter
>>>>>>>>>>> */
>>>>>>>>>>> public class DefaultEntries {
>>>>>>>>>>> private final Set<Class> entrys;
>>>>>>>>>>> public DefaultEntries() {
>>>>>>>>>>> entrys = new HashSet<Class>(16);
>>>>>>>>>>> }
>>>>>>>>>>> /**
>>>>>>>>>>> * Add an Entry class.
>>>>>>>>>>> * @param cl - class
>>>>>>>>>>> * @return this
>>>>>>>>>>> */
>>>>>>>>>>> public DefaultEntries add(Class cl){
>>>>>>>>>>> entrys.add(cl);
>>>>>>>>>>> return this;
>>>>>>>>>>> }
>>>>>>>>>>> /**
>>>>>>>>>>> * All all the Jini Platform Entry's
>>>>>>>>>>> * @return
>>>>>>>>>>> */
>>>>>>>>>>> public DefaultEntries addPlatformEntries(){
>>>>>>>>>>> add(Comment.class);
>>>>>>>>>>> add(Location.class);
>>>>>>>>>>> add(Name.class);
>>>>>>>>>>> add(ServiceInfo.class);
>>>>>>>>>>> add(Status.class);
>>>>>>>>>>> add(UIDescriptor.class);
>>>>>>>>>>> add(Address.class);
>>>>>>>>>>> return this;
>>>>>>>>>>> }
>>>>>>>>>>> /**
>>>>>>>>>>> * Remove all Entry's
>>>>>>>>>>> */
>>>>>>>>>>> public void reset(){
>>>>>>>>>>> entrys.clear();
>>>>>>>>>>> }
>>>>>>>>>>> /**
>>>>>>>>>>> * Generate a new array containing all Entry's added since last
>>>>>>>>>>> reset.
>>>>>>>>>>> * @return
>>>>>>>>>>> */
>>>>>>>>>>> public Class[] getEntries(){
>>>>>>>>>>> return entrys.toArray(new Class[entrys.size()]);
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> @Override
>>>>>>>>>>> public int hashCode() {
>>>>>>>>>>> int hash = 3;
>>>>>>>>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>>>>>>>>> 0);
>>>>>>>>>>> return hash;
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> @Override
>>>>>>>>>>> public boolean equals(Object o){
>>>>>>>>>>> if (o == null) return false;
>>>>>>>>>>> if (o instanceof DefaultEntries){
>>>>>>>>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>>>>>>>>> }
>>>>>>>>>>> return false;
>>>>>>>>>>> }
>>>>>>>>>>> @Override
>>>>>>>>>>> public String toString(){
>>>>>>>>>>> String newline = System.getProperty("line.separator");
>>>>>>>>>>> StringBuilder sb = new StringBuilder(256);
>>>>>>>>>>> sb.append("DefaultEntries:");
>>>>>>>>>>> sb.append(newline);
>>>>>>>>>>> Iterator<Class> it = entrys.iterator();
>>>>>>>>>>> while (it.hasNext()){
>>>>>>>>>>> sb.append(it.next().getName());
>>>>>>>>>>> sb.append(newline);
>>>>>>>>>>> }
>>>>>>>>>>> return sb.toString();
>>>>>>>>>>> }
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Patricia Shanahan <pa...@acm.org>.
There are some negatives to using CHM compared to wrapping a HashMap in
a synchronized map. It is easy to write methods for compound operations
such as removing a key-value pair if, and only if, some other key is
present.
Patricia
On 2/8/2011 8:26 AM, Dan Creswell wrote:
> No friction, simplest thing that could possibly work is the only thing
> running through my head.
>
> I'm happy to see CHM used if people deem it appropriate - as is so often the
> case, I'm not writing the code so my opinion should only carry so much
> weight.
>
> On 8 February 2011 15:12, Gregg Wonderly<gr...@wonderly.org> wrote:
>
>> On 2/8/2011 9:00 AM, Dan Creswell wrote:
>>
>>> It's all about expected usage patterns.
>>>
>>> Locking in this case will be per instance and the likelihood of contention
>>> is low given no one's going to call add a lot or indeed toString a lot in
>>> a
>>> short space of time.
>>>
>>> So given:
>>>
>>> Define how concurrency is handled then implement
>>>
>>> And assuming it's in line with the above contention model I'd say
>>> synchronized would be adequate.
>>>
>>
>> I believe this is the case. But, I also know that it can come back to
>> bite.
>>
>> CHM solves it without synchronized, and that, I believe is a better choice
>> because it eliminates the problem. Any additional methods or usage patterns
>> that fall out of the life cycle of this object will not have any new or
>> different behavior or synchronization requirements.
>>
>> Is there an attribute of CHM that you find unattractive Dan? I'm not sure
>> I understand the friction I am sensing.
>>
>> Gregg
>>
>>
>> On 8 February 2011 14:54, Gregg Wonderly<gr...@wonderly.org> wrote:
>>>
>>> On 2/7/2011 5:28 PM, Peter Firmstone wrote:
>>>>
>>>> Do we really need a concurrent version of this class? How often will
>>>>> Entry
>>>>> classes change?
>>>>>
>>>>>
>>>> My choice is always to consider concurrency first, unless there is some
>>>> element of performance that this impacts. The simple fact is that there
>>>> is
>>>> a toString() that traverses the contents. So, you either must
>>>> synchronize
>>>> all access to the contents, or use a CHM which solves the problem without
>>>> any future concurrency surprises.
>>>>
>>>> I'm really serious about this, because of how I've encountered tons of
>>>> "synchronized" blocks in river which introduce huge latency in
>>>> "processing"
>>>> because they cause everyone to wait in line for stuff which very often is
>>>> quite independent.
>>>>
>>>> Yes, this structure is mostly one time mutated. But, its design exposes
>>>> a
>>>> continuous mutation capability. Thus, any "read" of the contents has to
>>>> take that into account.
>>>>
>>>> Gregg Wonderly
>>>>
>>>>
>>>> Gregg Wonderly wrote:
>>>>
>>>>>
>>>>> Yes definitely the case. CHM just makes it a lot easier to not worry
>>>>>> about map
>>>>>> and set data structures in terms of concurrent access of mutating data.
>>>>>> Set
>>>>>> and HashSet are useful, but not always in concurrent mutating data
>>>>>> management.
>>>>>>
>>>>>> I still prefer Vector over ArrayList just because it eliminates
>>>>>> iteration
>>>>>> problems that alway require the same lines of code to resolve.
>>>>>>
>>>>>> Gregg
>>>>>>
>>>>>> Sent from my iPhone
>>>>>>
>>>>>> On Feb 7, 2011, at 2:08 PM, Dan Creswell<da...@gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>> All true, still need to document the concurrent contract for this
>>>>>> class
>>>>>>
>>>>>>> and
>>>>>>> implement accordingly.
>>>>>>>
>>>>>>> i.e. We can say "toString" is thread safe etc and then use
>>>>>>> ConcurrentHashMap
>>>>>>> and friends.
>>>>>>>
>>>>>>> But we gotta do it right....
>>>>>>>
>>>>>>> On 7 February 2011 19:57, Gregg Wonderly<gr...@wonderly.org> wrote:
>>>>>>>
>>>>>>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>>>>>>
>>>>>>>>
>>>>>>>> Sorry, I've got my nit-picking hat on...
>>>>>>>>
>>>>>>>>>
>>>>>>>>> The null check in the equals method isn't needed because you get a
>>>>>>>>> free one by using "instanceof".
>>>>>>>>>
>>>>>>>>> I know you've warned that the class is not thread-safe, but people
>>>>>>>>> often forget that doing a sysout of an object calls toString(). I'd
>>>>>>>>> still be tempted to whack some protection into toString to stop it
>>>>>>>>> blowing up when people start printing lots of debug messages.
>>>>>>>>>
>>>>>>>>> Other than that it looks good to me.
>>>>>>>>>
>>>>>>>>> I'd suggest that it would be easy enough to just use
>>>>>>>>>
>>>>>>>> ConcurrentHashMap
>>>>>>>> instead of HashSet if we are going to move to Java 5 anyway. Then,
>>>>>>>> you
>>>>>>>> don't have to worry about concurrency issues with toString() etc.
>>>>>>>>
>>>>>>>> Gregg Wonderly
>>>>>>>>
>>>>>>>>
>>>>>>>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>>>>>>>
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> Dan Creswell wrote:
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Solid - probably ought to be a constructor that doesn't add
>>>>>>>>>> defaults
>>>>>>>>>>
>>>>>>>>>>> too.....and maybe a note about thread safety on add.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> The finished article.
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> /*
>>>>>>>>>> * 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.river.api.lookup;
>>>>>>>>>>
>>>>>>>>>> import java.util.HashSet;
>>>>>>>>>> import java.util.Iterator;
>>>>>>>>>> import java.util.Set;
>>>>>>>>>> import net.jini.lookup.entry.Address;
>>>>>>>>>> import net.jini.lookup.entry.Comment;
>>>>>>>>>> import net.jini.lookup.entry.Location;
>>>>>>>>>> import net.jini.lookup.entry.Name;
>>>>>>>>>> import net.jini.lookup.entry.ServiceInfo;
>>>>>>>>>> import net.jini.lookup.entry.Status;
>>>>>>>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>>>>>>>
>>>>>>>>>> /**
>>>>>>>>>> * A little builder utility class that creates an array of Entry
>>>>>>>>>> classes
>>>>>>>>>> to
>>>>>>>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>>>>>>>> platform
>>>>>>>>>> * Entry's are included by default.
>>>>>>>>>> *
>>>>>>>>>> * Note: This class is not threadsafe, use external synchronization
>>>>>>>>>> if
>>>>>>>>>> required.
>>>>>>>>>> *
>>>>>>>>>> * Suggested by Dan Creswell.
>>>>>>>>>> * @author peter
>>>>>>>>>> */
>>>>>>>>>> public class DefaultEntries {
>>>>>>>>>> private final Set<Class> entrys;
>>>>>>>>>> public DefaultEntries() {
>>>>>>>>>> entrys = new HashSet<Class>(16);
>>>>>>>>>> }
>>>>>>>>>> /**
>>>>>>>>>> * Add an Entry class.
>>>>>>>>>> * @param cl - class
>>>>>>>>>> * @return this
>>>>>>>>>> */
>>>>>>>>>> public DefaultEntries add(Class cl){
>>>>>>>>>> entrys.add(cl);
>>>>>>>>>> return this;
>>>>>>>>>> }
>>>>>>>>>> /**
>>>>>>>>>> * All all the Jini Platform Entry's
>>>>>>>>>> * @return
>>>>>>>>>> */
>>>>>>>>>> public DefaultEntries addPlatformEntries(){
>>>>>>>>>> add(Comment.class);
>>>>>>>>>> add(Location.class);
>>>>>>>>>> add(Name.class);
>>>>>>>>>> add(ServiceInfo.class);
>>>>>>>>>> add(Status.class);
>>>>>>>>>> add(UIDescriptor.class);
>>>>>>>>>> add(Address.class);
>>>>>>>>>> return this;
>>>>>>>>>> }
>>>>>>>>>> /**
>>>>>>>>>> * Remove all Entry's
>>>>>>>>>> */
>>>>>>>>>> public void reset(){
>>>>>>>>>> entrys.clear();
>>>>>>>>>> }
>>>>>>>>>> /**
>>>>>>>>>> * Generate a new array containing all Entry's added since last
>>>>>>>>>> reset.
>>>>>>>>>> * @return
>>>>>>>>>> */
>>>>>>>>>> public Class[] getEntries(){
>>>>>>>>>> return entrys.toArray(new Class[entrys.size()]);
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> @Override
>>>>>>>>>> public int hashCode() {
>>>>>>>>>> int hash = 3;
>>>>>>>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>>>>>>>> 0);
>>>>>>>>>> return hash;
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> @Override
>>>>>>>>>> public boolean equals(Object o){
>>>>>>>>>> if (o == null) return false;
>>>>>>>>>> if (o instanceof DefaultEntries){
>>>>>>>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>>>>>>>> }
>>>>>>>>>> return false;
>>>>>>>>>> }
>>>>>>>>>> @Override
>>>>>>>>>> public String toString(){
>>>>>>>>>> String newline = System.getProperty("line.separator");
>>>>>>>>>> StringBuilder sb = new StringBuilder(256);
>>>>>>>>>> sb.append("DefaultEntries:");
>>>>>>>>>> sb.append(newline);
>>>>>>>>>> Iterator<Class> it = entrys.iterator();
>>>>>>>>>> while (it.hasNext()){
>>>>>>>>>> sb.append(it.next().getName());
>>>>>>>>>> sb.append(newline);
>>>>>>>>>> }
>>>>>>>>>> return sb.toString();
>>>>>>>>>> }
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
No friction, simplest thing that could possibly work is the only thing
running through my head.
I'm happy to see CHM used if people deem it appropriate - as is so often the
case, I'm not writing the code so my opinion should only carry so much
weight.
On 8 February 2011 15:12, Gregg Wonderly <gr...@wonderly.org> wrote:
> On 2/8/2011 9:00 AM, Dan Creswell wrote:
>
>> It's all about expected usage patterns.
>>
>> Locking in this case will be per instance and the likelihood of contention
>> is low given no one's going to call add a lot or indeed toString a lot in
>> a
>> short space of time.
>>
>> So given:
>>
>> Define how concurrency is handled then implement
>>
>> And assuming it's in line with the above contention model I'd say
>> synchronized would be adequate.
>>
>
> I believe this is the case. But, I also know that it can come back to
> bite.
>
> CHM solves it without synchronized, and that, I believe is a better choice
> because it eliminates the problem. Any additional methods or usage patterns
> that fall out of the life cycle of this object will not have any new or
> different behavior or synchronization requirements.
>
> Is there an attribute of CHM that you find unattractive Dan? I'm not sure
> I understand the friction I am sensing.
>
> Gregg
>
>
> On 8 February 2011 14:54, Gregg Wonderly<gr...@wonderly.org> wrote:
>>
>> On 2/7/2011 5:28 PM, Peter Firmstone wrote:
>>>
>>> Do we really need a concurrent version of this class? How often will
>>>> Entry
>>>> classes change?
>>>>
>>>>
>>> My choice is always to consider concurrency first, unless there is some
>>> element of performance that this impacts. The simple fact is that there
>>> is
>>> a toString() that traverses the contents. So, you either must
>>> synchronize
>>> all access to the contents, or use a CHM which solves the problem without
>>> any future concurrency surprises.
>>>
>>> I'm really serious about this, because of how I've encountered tons of
>>> "synchronized" blocks in river which introduce huge latency in
>>> "processing"
>>> because they cause everyone to wait in line for stuff which very often is
>>> quite independent.
>>>
>>> Yes, this structure is mostly one time mutated. But, its design exposes
>>> a
>>> continuous mutation capability. Thus, any "read" of the contents has to
>>> take that into account.
>>>
>>> Gregg Wonderly
>>>
>>>
>>> Gregg Wonderly wrote:
>>>
>>>>
>>>> Yes definitely the case. CHM just makes it a lot easier to not worry
>>>>> about map
>>>>> and set data structures in terms of concurrent access of mutating data.
>>>>> Set
>>>>> and HashSet are useful, but not always in concurrent mutating data
>>>>> management.
>>>>>
>>>>> I still prefer Vector over ArrayList just because it eliminates
>>>>> iteration
>>>>> problems that alway require the same lines of code to resolve.
>>>>>
>>>>> Gregg
>>>>>
>>>>> Sent from my iPhone
>>>>>
>>>>> On Feb 7, 2011, at 2:08 PM, Dan Creswell<da...@gmail.com>
>>>>> wrote:
>>>>>
>>>>> All true, still need to document the concurrent contract for this
>>>>> class
>>>>>
>>>>>> and
>>>>>> implement accordingly.
>>>>>>
>>>>>> i.e. We can say "toString" is thread safe etc and then use
>>>>>> ConcurrentHashMap
>>>>>> and friends.
>>>>>>
>>>>>> But we gotta do it right....
>>>>>>
>>>>>> On 7 February 2011 19:57, Gregg Wonderly<gr...@wonderly.org> wrote:
>>>>>>
>>>>>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>>>>>
>>>>>>>
>>>>>>> Sorry, I've got my nit-picking hat on...
>>>>>>>
>>>>>>>>
>>>>>>>> The null check in the equals method isn't needed because you get a
>>>>>>>> free one by using "instanceof".
>>>>>>>>
>>>>>>>> I know you've warned that the class is not thread-safe, but people
>>>>>>>> often forget that doing a sysout of an object calls toString(). I'd
>>>>>>>> still be tempted to whack some protection into toString to stop it
>>>>>>>> blowing up when people start printing lots of debug messages.
>>>>>>>>
>>>>>>>> Other than that it looks good to me.
>>>>>>>>
>>>>>>>> I'd suggest that it would be easy enough to just use
>>>>>>>>
>>>>>>> ConcurrentHashMap
>>>>>>> instead of HashSet if we are going to move to Java 5 anyway. Then,
>>>>>>> you
>>>>>>> don't have to worry about concurrency issues with toString() etc.
>>>>>>>
>>>>>>> Gregg Wonderly
>>>>>>>
>>>>>>>
>>>>>>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>>>>>>
>>>>>>> wrote:
>>>>>>>>
>>>>>>>> Dan Creswell wrote:
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Solid - probably ought to be a constructor that doesn't add
>>>>>>>>> defaults
>>>>>>>>>
>>>>>>>>>> too.....and maybe a note about thread safety on add.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> The finished article.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> /*
>>>>>>>>> * 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.river.api.lookup;
>>>>>>>>>
>>>>>>>>> import java.util.HashSet;
>>>>>>>>> import java.util.Iterator;
>>>>>>>>> import java.util.Set;
>>>>>>>>> import net.jini.lookup.entry.Address;
>>>>>>>>> import net.jini.lookup.entry.Comment;
>>>>>>>>> import net.jini.lookup.entry.Location;
>>>>>>>>> import net.jini.lookup.entry.Name;
>>>>>>>>> import net.jini.lookup.entry.ServiceInfo;
>>>>>>>>> import net.jini.lookup.entry.Status;
>>>>>>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>>>>>>
>>>>>>>>> /**
>>>>>>>>> * A little builder utility class that creates an array of Entry
>>>>>>>>> classes
>>>>>>>>> to
>>>>>>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>>>>>>> platform
>>>>>>>>> * Entry's are included by default.
>>>>>>>>> *
>>>>>>>>> * Note: This class is not threadsafe, use external synchronization
>>>>>>>>> if
>>>>>>>>> required.
>>>>>>>>> *
>>>>>>>>> * Suggested by Dan Creswell.
>>>>>>>>> * @author peter
>>>>>>>>> */
>>>>>>>>> public class DefaultEntries {
>>>>>>>>> private final Set<Class> entrys;
>>>>>>>>> public DefaultEntries() {
>>>>>>>>> entrys = new HashSet<Class>(16);
>>>>>>>>> }
>>>>>>>>> /**
>>>>>>>>> * Add an Entry class.
>>>>>>>>> * @param cl - class
>>>>>>>>> * @return this
>>>>>>>>> */
>>>>>>>>> public DefaultEntries add(Class cl){
>>>>>>>>> entrys.add(cl);
>>>>>>>>> return this;
>>>>>>>>> }
>>>>>>>>> /**
>>>>>>>>> * All all the Jini Platform Entry's
>>>>>>>>> * @return
>>>>>>>>> */
>>>>>>>>> public DefaultEntries addPlatformEntries(){
>>>>>>>>> add(Comment.class);
>>>>>>>>> add(Location.class);
>>>>>>>>> add(Name.class);
>>>>>>>>> add(ServiceInfo.class);
>>>>>>>>> add(Status.class);
>>>>>>>>> add(UIDescriptor.class);
>>>>>>>>> add(Address.class);
>>>>>>>>> return this;
>>>>>>>>> }
>>>>>>>>> /**
>>>>>>>>> * Remove all Entry's
>>>>>>>>> */
>>>>>>>>> public void reset(){
>>>>>>>>> entrys.clear();
>>>>>>>>> }
>>>>>>>>> /**
>>>>>>>>> * Generate a new array containing all Entry's added since last
>>>>>>>>> reset.
>>>>>>>>> * @return
>>>>>>>>> */
>>>>>>>>> public Class[] getEntries(){
>>>>>>>>> return entrys.toArray(new Class[entrys.size()]);
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> @Override
>>>>>>>>> public int hashCode() {
>>>>>>>>> int hash = 3;
>>>>>>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>>>>>>> 0);
>>>>>>>>> return hash;
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> @Override
>>>>>>>>> public boolean equals(Object o){
>>>>>>>>> if (o == null) return false;
>>>>>>>>> if (o instanceof DefaultEntries){
>>>>>>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>>>>>>> }
>>>>>>>>> return false;
>>>>>>>>> }
>>>>>>>>> @Override
>>>>>>>>> public String toString(){
>>>>>>>>> String newline = System.getProperty("line.separator");
>>>>>>>>> StringBuilder sb = new StringBuilder(256);
>>>>>>>>> sb.append("DefaultEntries:");
>>>>>>>>> sb.append(newline);
>>>>>>>>> Iterator<Class> it = entrys.iterator();
>>>>>>>>> while (it.hasNext()){
>>>>>>>>> sb.append(it.next().getName());
>>>>>>>>> sb.append(newline);
>>>>>>>>> }
>>>>>>>>> return sb.toString();
>>>>>>>>> }
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
On 2/8/2011 9:00 AM, Dan Creswell wrote:
> It's all about expected usage patterns.
>
> Locking in this case will be per instance and the likelihood of contention
> is low given no one's going to call add a lot or indeed toString a lot in a
> short space of time.
>
> So given:
>
> Define how concurrency is handled then implement
>
> And assuming it's in line with the above contention model I'd say
> synchronized would be adequate.
I believe this is the case. But, I also know that it can come back to bite.
CHM solves it without synchronized, and that, I believe is a better choice
because it eliminates the problem. Any additional methods or usage patterns
that fall out of the life cycle of this object will not have any new or
different behavior or synchronization requirements.
Is there an attribute of CHM that you find unattractive Dan? I'm not sure I
understand the friction I am sensing.
Gregg
> On 8 February 2011 14:54, Gregg Wonderly<gr...@wonderly.org> wrote:
>
>> On 2/7/2011 5:28 PM, Peter Firmstone wrote:
>>
>>> Do we really need a concurrent version of this class? How often will Entry
>>> classes change?
>>>
>>
>> My choice is always to consider concurrency first, unless there is some
>> element of performance that this impacts. The simple fact is that there is
>> a toString() that traverses the contents. So, you either must synchronize
>> all access to the contents, or use a CHM which solves the problem without
>> any future concurrency surprises.
>>
>> I'm really serious about this, because of how I've encountered tons of
>> "synchronized" blocks in river which introduce huge latency in "processing"
>> because they cause everyone to wait in line for stuff which very often is
>> quite independent.
>>
>> Yes, this structure is mostly one time mutated. But, its design exposes a
>> continuous mutation capability. Thus, any "read" of the contents has to
>> take that into account.
>>
>> Gregg Wonderly
>>
>>
>> Gregg Wonderly wrote:
>>>
>>>> Yes definitely the case. CHM just makes it a lot easier to not worry
>>>> about map
>>>> and set data structures in terms of concurrent access of mutating data.
>>>> Set
>>>> and HashSet are useful, but not always in concurrent mutating data
>>>> management.
>>>>
>>>> I still prefer Vector over ArrayList just because it eliminates iteration
>>>> problems that alway require the same lines of code to resolve.
>>>>
>>>> Gregg
>>>>
>>>> Sent from my iPhone
>>>>
>>>> On Feb 7, 2011, at 2:08 PM, Dan Creswell<da...@gmail.com> wrote:
>>>>
>>>> All true, still need to document the concurrent contract for this class
>>>>> and
>>>>> implement accordingly.
>>>>>
>>>>> i.e. We can say "toString" is thread safe etc and then use
>>>>> ConcurrentHashMap
>>>>> and friends.
>>>>>
>>>>> But we gotta do it right....
>>>>>
>>>>> On 7 February 2011 19:57, Gregg Wonderly<gr...@wonderly.org> wrote:
>>>>>
>>>>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>>>>>
>>>>>> Sorry, I've got my nit-picking hat on...
>>>>>>>
>>>>>>> The null check in the equals method isn't needed because you get a
>>>>>>> free one by using "instanceof".
>>>>>>>
>>>>>>> I know you've warned that the class is not thread-safe, but people
>>>>>>> often forget that doing a sysout of an object calls toString(). I'd
>>>>>>> still be tempted to whack some protection into toString to stop it
>>>>>>> blowing up when people start printing lots of debug messages.
>>>>>>>
>>>>>>> Other than that it looks good to me.
>>>>>>>
>>>>>>> I'd suggest that it would be easy enough to just use
>>>>>> ConcurrentHashMap
>>>>>> instead of HashSet if we are going to move to Java 5 anyway. Then, you
>>>>>> don't have to worry about concurrency issues with toString() etc.
>>>>>>
>>>>>> Gregg Wonderly
>>>>>>
>>>>>>
>>>>>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>>>>>
>>>>>>> wrote:
>>>>>>>
>>>>>>> Dan Creswell wrote:
>>>>>>>>
>>>>>>>> Solid - probably ought to be a constructor that doesn't add defaults
>>>>>>>>> too.....and maybe a note about thread safety on add.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> The finished article.
>>>>>>>>
>>>>>>>> /*
>>>>>>>> * 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.river.api.lookup;
>>>>>>>>
>>>>>>>> import java.util.HashSet;
>>>>>>>> import java.util.Iterator;
>>>>>>>> import java.util.Set;
>>>>>>>> import net.jini.lookup.entry.Address;
>>>>>>>> import net.jini.lookup.entry.Comment;
>>>>>>>> import net.jini.lookup.entry.Location;
>>>>>>>> import net.jini.lookup.entry.Name;
>>>>>>>> import net.jini.lookup.entry.ServiceInfo;
>>>>>>>> import net.jini.lookup.entry.Status;
>>>>>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>>>>>
>>>>>>>> /**
>>>>>>>> * A little builder utility class that creates an array of Entry
>>>>>>>> classes
>>>>>>>> to
>>>>>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>>>>>> platform
>>>>>>>> * Entry's are included by default.
>>>>>>>> *
>>>>>>>> * Note: This class is not threadsafe, use external synchronization if
>>>>>>>> required.
>>>>>>>> *
>>>>>>>> * Suggested by Dan Creswell.
>>>>>>>> * @author peter
>>>>>>>> */
>>>>>>>> public class DefaultEntries {
>>>>>>>> private final Set<Class> entrys;
>>>>>>>> public DefaultEntries() {
>>>>>>>> entrys = new HashSet<Class>(16);
>>>>>>>> }
>>>>>>>> /**
>>>>>>>> * Add an Entry class.
>>>>>>>> * @param cl - class
>>>>>>>> * @return this
>>>>>>>> */
>>>>>>>> public DefaultEntries add(Class cl){
>>>>>>>> entrys.add(cl);
>>>>>>>> return this;
>>>>>>>> }
>>>>>>>> /**
>>>>>>>> * All all the Jini Platform Entry's
>>>>>>>> * @return
>>>>>>>> */
>>>>>>>> public DefaultEntries addPlatformEntries(){
>>>>>>>> add(Comment.class);
>>>>>>>> add(Location.class);
>>>>>>>> add(Name.class);
>>>>>>>> add(ServiceInfo.class);
>>>>>>>> add(Status.class);
>>>>>>>> add(UIDescriptor.class);
>>>>>>>> add(Address.class);
>>>>>>>> return this;
>>>>>>>> }
>>>>>>>> /**
>>>>>>>> * Remove all Entry's
>>>>>>>> */
>>>>>>>> public void reset(){
>>>>>>>> entrys.clear();
>>>>>>>> }
>>>>>>>> /**
>>>>>>>> * Generate a new array containing all Entry's added since last reset.
>>>>>>>> * @return
>>>>>>>> */
>>>>>>>> public Class[] getEntries(){
>>>>>>>> return entrys.toArray(new Class[entrys.size()]);
>>>>>>>> }
>>>>>>>>
>>>>>>>> @Override
>>>>>>>> public int hashCode() {
>>>>>>>> int hash = 3;
>>>>>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>>>>>> 0);
>>>>>>>> return hash;
>>>>>>>> }
>>>>>>>>
>>>>>>>> @Override
>>>>>>>> public boolean equals(Object o){
>>>>>>>> if (o == null) return false;
>>>>>>>> if (o instanceof DefaultEntries){
>>>>>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>>>>>> }
>>>>>>>> return false;
>>>>>>>> }
>>>>>>>> @Override
>>>>>>>> public String toString(){
>>>>>>>> String newline = System.getProperty("line.separator");
>>>>>>>> StringBuilder sb = new StringBuilder(256);
>>>>>>>> sb.append("DefaultEntries:");
>>>>>>>> sb.append(newline);
>>>>>>>> Iterator<Class> it = entrys.iterator();
>>>>>>>> while (it.hasNext()){
>>>>>>>> sb.append(it.next().getName());
>>>>>>>> sb.append(newline);
>>>>>>>> }
>>>>>>>> return sb.toString();
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>
>>>
>>>
>>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
It's all about expected usage patterns.
Locking in this case will be per instance and the likelihood of contention
is low given no one's going to call add a lot or indeed toString a lot in a
short space of time.
So given:
Define how concurrency is handled then implement
And assuming it's in line with the above contention model I'd say
synchronized would be adequate.
On 8 February 2011 14:54, Gregg Wonderly <gr...@wonderly.org> wrote:
> On 2/7/2011 5:28 PM, Peter Firmstone wrote:
>
>> Do we really need a concurrent version of this class? How often will Entry
>> classes change?
>>
>
> My choice is always to consider concurrency first, unless there is some
> element of performance that this impacts. The simple fact is that there is
> a toString() that traverses the contents. So, you either must synchronize
> all access to the contents, or use a CHM which solves the problem without
> any future concurrency surprises.
>
> I'm really serious about this, because of how I've encountered tons of
> "synchronized" blocks in river which introduce huge latency in "processing"
> because they cause everyone to wait in line for stuff which very often is
> quite independent.
>
> Yes, this structure is mostly one time mutated. But, its design exposes a
> continuous mutation capability. Thus, any "read" of the contents has to
> take that into account.
>
> Gregg Wonderly
>
>
> Gregg Wonderly wrote:
>>
>>> Yes definitely the case. CHM just makes it a lot easier to not worry
>>> about map
>>> and set data structures in terms of concurrent access of mutating data.
>>> Set
>>> and HashSet are useful, but not always in concurrent mutating data
>>> management.
>>>
>>> I still prefer Vector over ArrayList just because it eliminates iteration
>>> problems that alway require the same lines of code to resolve.
>>>
>>> Gregg
>>>
>>> Sent from my iPhone
>>>
>>> On Feb 7, 2011, at 2:08 PM, Dan Creswell <da...@gmail.com> wrote:
>>>
>>> All true, still need to document the concurrent contract for this class
>>>> and
>>>> implement accordingly.
>>>>
>>>> i.e. We can say "toString" is thread safe etc and then use
>>>> ConcurrentHashMap
>>>> and friends.
>>>>
>>>> But we gotta do it right....
>>>>
>>>> On 7 February 2011 19:57, Gregg Wonderly <gr...@wonderly.org> wrote:
>>>>
>>>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>>>>
>>>>> Sorry, I've got my nit-picking hat on...
>>>>>>
>>>>>> The null check in the equals method isn't needed because you get a
>>>>>> free one by using "instanceof".
>>>>>>
>>>>>> I know you've warned that the class is not thread-safe, but people
>>>>>> often forget that doing a sysout of an object calls toString(). I'd
>>>>>> still be tempted to whack some protection into toString to stop it
>>>>>> blowing up when people start printing lots of debug messages.
>>>>>>
>>>>>> Other than that it looks good to me.
>>>>>>
>>>>>> I'd suggest that it would be easy enough to just use
>>>>> ConcurrentHashMap
>>>>> instead of HashSet if we are going to move to Java 5 anyway. Then, you
>>>>> don't have to worry about concurrency issues with toString() etc.
>>>>>
>>>>> Gregg Wonderly
>>>>>
>>>>>
>>>>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>>>>
>>>>>> wrote:
>>>>>>
>>>>>> Dan Creswell wrote:
>>>>>>>
>>>>>>> Solid - probably ought to be a constructor that doesn't add defaults
>>>>>>>> too.....and maybe a note about thread safety on add.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> The finished article.
>>>>>>>
>>>>>>> /*
>>>>>>> * 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.river.api.lookup;
>>>>>>>
>>>>>>> import java.util.HashSet;
>>>>>>> import java.util.Iterator;
>>>>>>> import java.util.Set;
>>>>>>> import net.jini.lookup.entry.Address;
>>>>>>> import net.jini.lookup.entry.Comment;
>>>>>>> import net.jini.lookup.entry.Location;
>>>>>>> import net.jini.lookup.entry.Name;
>>>>>>> import net.jini.lookup.entry.ServiceInfo;
>>>>>>> import net.jini.lookup.entry.Status;
>>>>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>>>>
>>>>>>> /**
>>>>>>> * A little builder utility class that creates an array of Entry
>>>>>>> classes
>>>>>>> to
>>>>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>>>>> platform
>>>>>>> * Entry's are included by default.
>>>>>>> *
>>>>>>> * Note: This class is not threadsafe, use external synchronization if
>>>>>>> required.
>>>>>>> *
>>>>>>> * Suggested by Dan Creswell.
>>>>>>> * @author peter
>>>>>>> */
>>>>>>> public class DefaultEntries {
>>>>>>> private final Set<Class> entrys;
>>>>>>> public DefaultEntries() {
>>>>>>> entrys = new HashSet<Class>(16);
>>>>>>> }
>>>>>>> /**
>>>>>>> * Add an Entry class.
>>>>>>> * @param cl - class
>>>>>>> * @return this
>>>>>>> */
>>>>>>> public DefaultEntries add(Class cl){
>>>>>>> entrys.add(cl);
>>>>>>> return this;
>>>>>>> }
>>>>>>> /**
>>>>>>> * All all the Jini Platform Entry's
>>>>>>> * @return
>>>>>>> */
>>>>>>> public DefaultEntries addPlatformEntries(){
>>>>>>> add(Comment.class);
>>>>>>> add(Location.class);
>>>>>>> add(Name.class);
>>>>>>> add(ServiceInfo.class);
>>>>>>> add(Status.class);
>>>>>>> add(UIDescriptor.class);
>>>>>>> add(Address.class);
>>>>>>> return this;
>>>>>>> }
>>>>>>> /**
>>>>>>> * Remove all Entry's
>>>>>>> */
>>>>>>> public void reset(){
>>>>>>> entrys.clear();
>>>>>>> }
>>>>>>> /**
>>>>>>> * Generate a new array containing all Entry's added since last reset.
>>>>>>> * @return
>>>>>>> */
>>>>>>> public Class[] getEntries(){
>>>>>>> return entrys.toArray(new Class[entrys.size()]);
>>>>>>> }
>>>>>>>
>>>>>>> @Override
>>>>>>> public int hashCode() {
>>>>>>> int hash = 3;
>>>>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>>>>> 0);
>>>>>>> return hash;
>>>>>>> }
>>>>>>>
>>>>>>> @Override
>>>>>>> public boolean equals(Object o){
>>>>>>> if (o == null) return false;
>>>>>>> if (o instanceof DefaultEntries){
>>>>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>>>>> }
>>>>>>> return false;
>>>>>>> }
>>>>>>> @Override
>>>>>>> public String toString(){
>>>>>>> String newline = System.getProperty("line.separator");
>>>>>>> StringBuilder sb = new StringBuilder(256);
>>>>>>> sb.append("DefaultEntries:");
>>>>>>> sb.append(newline);
>>>>>>> Iterator<Class> it = entrys.iterator();
>>>>>>> while (it.hasNext()){
>>>>>>> sb.append(it.next().getName());
>>>>>>> sb.append(newline);
>>>>>>> }
>>>>>>> return sb.toString();
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>>
>>>
>>
>>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
There we go, bells & whistles included.
Cheers,
Peter.
/*
* 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.river.api.lookup;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.jini.lookup.entry.Address;
import net.jini.lookup.entry.Comment;
import net.jini.lookup.entry.Location;
import net.jini.lookup.entry.Name;
import net.jini.lookup.entry.ServiceInfo;
import net.jini.lookup.entry.Status;
import net.jini.lookup.entry.UIDescriptor;
import org.apache.river.impl.util.ConcurrentCollections;
/**
* A little builder utility class that creates an array of Entry classes to
* be used as a parameter for StreamServiceRegistrar.
*
* Note: This class is thread safe.
*
* The toString method will return a snapshot of the Entry classes
contained at
* the time of the toString method call, the String returned will be a
* space delimited list of all Entry classes.
*
*
* Suggested by Dan Creswell.
* @author peter
*/
public class DefaultEntries {
private final Set<Class> entrys;
public DefaultEntries() {
Set<Class> set = new HashSet<Class>(16);
entrys = ConcurrentCollections.multiReadSet(set);
}
/**
* Add an Entry class.
* @param cl - class
* @return this
*/
public DefaultEntries add(Class cl){
entrys.add(cl);
return this;
}
/**
* All all the Jini Platform Entry's
* @return
*/
public DefaultEntries addPlatformEntries(){
add(Comment.class);
add(Location.class);
add(Name.class);
add(ServiceInfo.class);
add(Status.class);
add(UIDescriptor.class);
add(Address.class);
return this;
}
/**
* Remove all Entry's
*/
public void reset(){
entrys.clear();
}
/**
* Generate a new array containing all Entry's added since last reset.
*
* @return
*/
public Class[] getEntries(){
/* An empty array is passed in, it will be replaced by the correct
* size array. Checking the Set size first, then creating an
array of
* sufficient size would not be atomic and may lead to an array
* filled with null's if reset was called between size and
* passing the array into the entrys Set.
*/
return entrys.toArray(new Class[0]);
}
@Override
public int hashCode() {
int hash = 3;
hash = 29 * hash + this.entrys.hashCode();
return hash;
}
@Override
public boolean equals(Object o){
if (o instanceof DefaultEntries){
if (entrys.equals(((DefaultEntries)o).entrys)) return true;
}
return false;
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder(256);
sb.append("DefaultEntries:");
Iterator<Class> it = entrys.iterator();
while (it.hasNext()){
sb.append(" ");
sb.append(it.next().getSimpleName());
}
return sb.toString();
}
}
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
On 2/7/2011 5:28 PM, Peter Firmstone wrote:
> Do we really need a concurrent version of this class? How often will Entry
> classes change?
My choice is always to consider concurrency first, unless there is some element
of performance that this impacts. The simple fact is that there is a toString()
that traverses the contents. So, you either must synchronize all access to the
contents, or use a CHM which solves the problem without any future concurrency
surprises.
I'm really serious about this, because of how I've encountered tons of
"synchronized" blocks in river which introduce huge latency in "processing"
because they cause everyone to wait in line for stuff which very often is quite
independent.
Yes, this structure is mostly one time mutated. But, its design exposes a
continuous mutation capability. Thus, any "read" of the contents has to take
that into account.
Gregg Wonderly
> Gregg Wonderly wrote:
>> Yes definitely the case. CHM just makes it a lot easier to not worry about map
>> and set data structures in terms of concurrent access of mutating data. Set
>> and HashSet are useful, but not always in concurrent mutating data management.
>>
>> I still prefer Vector over ArrayList just because it eliminates iteration
>> problems that alway require the same lines of code to resolve.
>>
>> Gregg
>>
>> Sent from my iPhone
>>
>> On Feb 7, 2011, at 2:08 PM, Dan Creswell <da...@gmail.com> wrote:
>>
>>> All true, still need to document the concurrent contract for this class and
>>> implement accordingly.
>>>
>>> i.e. We can say "toString" is thread safe etc and then use ConcurrentHashMap
>>> and friends.
>>>
>>> But we gotta do it right....
>>>
>>> On 7 February 2011 19:57, Gregg Wonderly <gr...@wonderly.org> wrote:
>>>
>>>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>>>
>>>>> Sorry, I've got my nit-picking hat on...
>>>>>
>>>>> The null check in the equals method isn't needed because you get a
>>>>> free one by using "instanceof".
>>>>>
>>>>> I know you've warned that the class is not thread-safe, but people
>>>>> often forget that doing a sysout of an object calls toString(). I'd
>>>>> still be tempted to whack some protection into toString to stop it
>>>>> blowing up when people start printing lots of debug messages.
>>>>>
>>>>> Other than that it looks good to me.
>>>>>
>>>> I'd suggest that it would be easy enough to just use ConcurrentHashMap
>>>> instead of HashSet if we are going to move to Java 5 anyway. Then, you
>>>> don't have to worry about concurrency issues with toString() etc.
>>>>
>>>> Gregg Wonderly
>>>>
>>>>
>>>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>>>> wrote:
>>>>>
>>>>>> Dan Creswell wrote:
>>>>>>
>>>>>>> Solid - probably ought to be a constructor that doesn't add defaults
>>>>>>> too.....and maybe a note about thread safety on add.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> The finished article.
>>>>>>
>>>>>> /*
>>>>>> * 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.river.api.lookup;
>>>>>>
>>>>>> import java.util.HashSet;
>>>>>> import java.util.Iterator;
>>>>>> import java.util.Set;
>>>>>> import net.jini.lookup.entry.Address;
>>>>>> import net.jini.lookup.entry.Comment;
>>>>>> import net.jini.lookup.entry.Location;
>>>>>> import net.jini.lookup.entry.Name;
>>>>>> import net.jini.lookup.entry.ServiceInfo;
>>>>>> import net.jini.lookup.entry.Status;
>>>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>>>
>>>>>> /**
>>>>>> * A little builder utility class that creates an array of Entry classes
>>>>>> to
>>>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>>>> platform
>>>>>> * Entry's are included by default.
>>>>>> *
>>>>>> * Note: This class is not threadsafe, use external synchronization if
>>>>>> required.
>>>>>> *
>>>>>> * Suggested by Dan Creswell.
>>>>>> * @author peter
>>>>>> */
>>>>>> public class DefaultEntries {
>>>>>> private final Set<Class> entrys;
>>>>>> public DefaultEntries() {
>>>>>> entrys = new HashSet<Class>(16);
>>>>>> }
>>>>>> /**
>>>>>> * Add an Entry class.
>>>>>> * @param cl - class
>>>>>> * @return this
>>>>>> */
>>>>>> public DefaultEntries add(Class cl){
>>>>>> entrys.add(cl);
>>>>>> return this;
>>>>>> }
>>>>>> /**
>>>>>> * All all the Jini Platform Entry's
>>>>>> * @return
>>>>>> */
>>>>>> public DefaultEntries addPlatformEntries(){
>>>>>> add(Comment.class);
>>>>>> add(Location.class);
>>>>>> add(Name.class);
>>>>>> add(ServiceInfo.class);
>>>>>> add(Status.class);
>>>>>> add(UIDescriptor.class);
>>>>>> add(Address.class);
>>>>>> return this;
>>>>>> }
>>>>>> /**
>>>>>> * Remove all Entry's
>>>>>> */
>>>>>> public void reset(){
>>>>>> entrys.clear();
>>>>>> }
>>>>>> /**
>>>>>> * Generate a new array containing all Entry's added since last reset.
>>>>>> * @return
>>>>>> */
>>>>>> public Class[] getEntries(){
>>>>>> return entrys.toArray(new Class[entrys.size()]);
>>>>>> }
>>>>>>
>>>>>> @Override
>>>>>> public int hashCode() {
>>>>>> int hash = 3;
>>>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>>>> 0);
>>>>>> return hash;
>>>>>> }
>>>>>>
>>>>>> @Override
>>>>>> public boolean equals(Object o){
>>>>>> if (o == null) return false;
>>>>>> if (o instanceof DefaultEntries){
>>>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>>>> }
>>>>>> return false;
>>>>>> }
>>>>>> @Override
>>>>>> public String toString(){
>>>>>> String newline = System.getProperty("line.separator");
>>>>>> StringBuilder sb = new StringBuilder(256);
>>>>>> sb.append("DefaultEntries:");
>>>>>> sb.append(newline);
>>>>>> Iterator<Class> it = entrys.iterator();
>>>>>> while (it.hasNext()){
>>>>>> sb.append(it.next().getName());
>>>>>> sb.append(newline);
>>>>>> }
>>>>>> return sb.toString();
>>>>>> }
>>>>>> }
>>>>>>
>>>>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Do we really need a concurrent version of this class? How often will
Entry classes change?
Gregg Wonderly wrote:
> Yes definitely the case. CHM just makes it a lot easier to not worry about map and set data structures in terms of concurrent access of mutating data. Set and HashSet are useful, but not always in concurrent mutating data management.
>
> I still prefer Vector over ArrayList just because it eliminates iteration problems that alway require the same lines of code to resolve.
>
> Gregg
>
> Sent from my iPhone
>
> On Feb 7, 2011, at 2:08 PM, Dan Creswell <da...@gmail.com> wrote:
>
>
>> All true, still need to document the concurrent contract for this class and
>> implement accordingly.
>>
>> i.e. We can say "toString" is thread safe etc and then use ConcurrentHashMap
>> and friends.
>>
>> But we gotta do it right....
>>
>> On 7 February 2011 19:57, Gregg Wonderly <gr...@wonderly.org> wrote:
>>
>>
>>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>>
>>>
>>>> Sorry, I've got my nit-picking hat on...
>>>>
>>>> The null check in the equals method isn't needed because you get a
>>>> free one by using "instanceof".
>>>>
>>>> I know you've warned that the class is not thread-safe, but people
>>>> often forget that doing a sysout of an object calls toString(). I'd
>>>> still be tempted to whack some protection into toString to stop it
>>>> blowing up when people start printing lots of debug messages.
>>>>
>>>> Other than that it looks good to me.
>>>>
>>>>
>>> I'd suggest that it would be easy enough to just use ConcurrentHashMap
>>> instead of HashSet if we are going to move to Java 5 anyway. Then, you
>>> don't have to worry about concurrency issues with toString() etc.
>>>
>>> Gregg Wonderly
>>>
>>>
>>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>>
>>>> wrote:
>>>>
>>>>
>>>>> Dan Creswell wrote:
>>>>>
>>>>>
>>>>>> Solid - probably ought to be a constructor that doesn't add defaults
>>>>>> too.....and maybe a note about thread safety on add.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> The finished article.
>>>>>
>>>>> /*
>>>>> * 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.river.api.lookup;
>>>>>
>>>>> import java.util.HashSet;
>>>>> import java.util.Iterator;
>>>>> import java.util.Set;
>>>>> import net.jini.lookup.entry.Address;
>>>>> import net.jini.lookup.entry.Comment;
>>>>> import net.jini.lookup.entry.Location;
>>>>> import net.jini.lookup.entry.Name;
>>>>> import net.jini.lookup.entry.ServiceInfo;
>>>>> import net.jini.lookup.entry.Status;
>>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>>
>>>>> /**
>>>>> * A little builder utility class that creates an array of Entry classes
>>>>> to
>>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>>> platform
>>>>> * Entry's are included by default.
>>>>> *
>>>>> * Note: This class is not threadsafe, use external synchronization if
>>>>> required.
>>>>> *
>>>>> * Suggested by Dan Creswell.
>>>>> * @author peter
>>>>> */
>>>>> public class DefaultEntries {
>>>>> private final Set<Class> entrys;
>>>>> public DefaultEntries() {
>>>>> entrys = new HashSet<Class>(16);
>>>>> }
>>>>> /**
>>>>> * Add an Entry class.
>>>>> * @param cl - class
>>>>> * @return this
>>>>> */
>>>>> public DefaultEntries add(Class cl){
>>>>> entrys.add(cl);
>>>>> return this;
>>>>> }
>>>>> /**
>>>>> * All all the Jini Platform Entry's
>>>>> * @return
>>>>> */
>>>>> public DefaultEntries addPlatformEntries(){
>>>>> add(Comment.class);
>>>>> add(Location.class);
>>>>> add(Name.class);
>>>>> add(ServiceInfo.class);
>>>>> add(Status.class);
>>>>> add(UIDescriptor.class);
>>>>> add(Address.class);
>>>>> return this;
>>>>> }
>>>>> /**
>>>>> * Remove all Entry's
>>>>> */
>>>>> public void reset(){
>>>>> entrys.clear();
>>>>> }
>>>>> /**
>>>>> * Generate a new array containing all Entry's added since last reset.
>>>>> * @return
>>>>> */
>>>>> public Class[] getEntries(){
>>>>> return entrys.toArray(new Class[entrys.size()]);
>>>>> }
>>>>>
>>>>> @Override
>>>>> public int hashCode() {
>>>>> int hash = 3;
>>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>>> 0);
>>>>> return hash;
>>>>> }
>>>>>
>>>>> @Override
>>>>> public boolean equals(Object o){
>>>>> if (o == null) return false;
>>>>> if (o instanceof DefaultEntries){
>>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>>> }
>>>>> return false;
>>>>> }
>>>>> @Override
>>>>> public String toString(){
>>>>> String newline = System.getProperty("line.separator");
>>>>> StringBuilder sb = new StringBuilder(256);
>>>>> sb.append("DefaultEntries:");
>>>>> sb.append(newline);
>>>>> Iterator<Class> it = entrys.iterator();
>>>>> while (it.hasNext()){
>>>>> sb.append(it.next().getName());
>>>>> sb.append(newline);
>>>>> }
>>>>> return sb.toString();
>>>>> }
>>>>> }
>>>>>
>>>>>
>>>>>
>
>
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@gmail.com>.
Yes definitely the case. CHM just makes it a lot easier to not worry about map and set data structures in terms of concurrent access of mutating data. Set and HashSet are useful, but not always in concurrent mutating data management.
I still prefer Vector over ArrayList just because it eliminates iteration problems that alway require the same lines of code to resolve.
Gregg
Sent from my iPhone
On Feb 7, 2011, at 2:08 PM, Dan Creswell <da...@gmail.com> wrote:
> All true, still need to document the concurrent contract for this class and
> implement accordingly.
>
> i.e. We can say "toString" is thread safe etc and then use ConcurrentHashMap
> and friends.
>
> But we gotta do it right....
>
> On 7 February 2011 19:57, Gregg Wonderly <gr...@wonderly.org> wrote:
>
>> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>>
>>> Sorry, I've got my nit-picking hat on...
>>>
>>> The null check in the equals method isn't needed because you get a
>>> free one by using "instanceof".
>>>
>>> I know you've warned that the class is not thread-safe, but people
>>> often forget that doing a sysout of an object calls toString(). I'd
>>> still be tempted to whack some protection into toString to stop it
>>> blowing up when people start printing lots of debug messages.
>>>
>>> Other than that it looks good to me.
>>>
>>
>> I'd suggest that it would be easy enough to just use ConcurrentHashMap
>> instead of HashSet if we are going to move to Java 5 anyway. Then, you
>> don't have to worry about concurrency issues with toString() etc.
>>
>> Gregg Wonderly
>>
>>
>> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>>> wrote:
>>>
>>>> Dan Creswell wrote:
>>>>
>>>>>
>>>>> Solid - probably ought to be a constructor that doesn't add defaults
>>>>> too.....and maybe a note about thread safety on add.
>>>>>
>>>>>
>>>>>
>>>>>
>>>> The finished article.
>>>>
>>>> /*
>>>> * 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.river.api.lookup;
>>>>
>>>> import java.util.HashSet;
>>>> import java.util.Iterator;
>>>> import java.util.Set;
>>>> import net.jini.lookup.entry.Address;
>>>> import net.jini.lookup.entry.Comment;
>>>> import net.jini.lookup.entry.Location;
>>>> import net.jini.lookup.entry.Name;
>>>> import net.jini.lookup.entry.ServiceInfo;
>>>> import net.jini.lookup.entry.Status;
>>>> import net.jini.lookup.entry.UIDescriptor;
>>>>
>>>> /**
>>>> * A little builder utility class that creates an array of Entry classes
>>>> to
>>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>>> platform
>>>> * Entry's are included by default.
>>>> *
>>>> * Note: This class is not threadsafe, use external synchronization if
>>>> required.
>>>> *
>>>> * Suggested by Dan Creswell.
>>>> * @author peter
>>>> */
>>>> public class DefaultEntries {
>>>> private final Set<Class> entrys;
>>>> public DefaultEntries() {
>>>> entrys = new HashSet<Class>(16);
>>>> }
>>>> /**
>>>> * Add an Entry class.
>>>> * @param cl - class
>>>> * @return this
>>>> */
>>>> public DefaultEntries add(Class cl){
>>>> entrys.add(cl);
>>>> return this;
>>>> }
>>>> /**
>>>> * All all the Jini Platform Entry's
>>>> * @return
>>>> */
>>>> public DefaultEntries addPlatformEntries(){
>>>> add(Comment.class);
>>>> add(Location.class);
>>>> add(Name.class);
>>>> add(ServiceInfo.class);
>>>> add(Status.class);
>>>> add(UIDescriptor.class);
>>>> add(Address.class);
>>>> return this;
>>>> }
>>>> /**
>>>> * Remove all Entry's
>>>> */
>>>> public void reset(){
>>>> entrys.clear();
>>>> }
>>>> /**
>>>> * Generate a new array containing all Entry's added since last reset.
>>>> * @return
>>>> */
>>>> public Class[] getEntries(){
>>>> return entrys.toArray(new Class[entrys.size()]);
>>>> }
>>>>
>>>> @Override
>>>> public int hashCode() {
>>>> int hash = 3;
>>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>>> 0);
>>>> return hash;
>>>> }
>>>>
>>>> @Override
>>>> public boolean equals(Object o){
>>>> if (o == null) return false;
>>>> if (o instanceof DefaultEntries){
>>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>>> }
>>>> return false;
>>>> }
>>>> @Override
>>>> public String toString(){
>>>> String newline = System.getProperty("line.separator");
>>>> StringBuilder sb = new StringBuilder(256);
>>>> sb.append("DefaultEntries:");
>>>> sb.append(newline);
>>>> Iterator<Class> it = entrys.iterator();
>>>> while (it.hasNext()){
>>>> sb.append(it.next().getName());
>>>> sb.append(newline);
>>>> }
>>>> return sb.toString();
>>>> }
>>>> }
>>>>
>>>>
>>>
>>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
All true, still need to document the concurrent contract for this class and
implement accordingly.
i.e. We can say "toString" is thread safe etc and then use ConcurrentHashMap
and friends.
But we gotta do it right....
On 7 February 2011 19:57, Gregg Wonderly <gr...@wonderly.org> wrote:
> On 2/7/2011 5:24 AM, Tom Hobbs wrote:
>
>> Sorry, I've got my nit-picking hat on...
>>
>> The null check in the equals method isn't needed because you get a
>> free one by using "instanceof".
>>
>> I know you've warned that the class is not thread-safe, but people
>> often forget that doing a sysout of an object calls toString(). I'd
>> still be tempted to whack some protection into toString to stop it
>> blowing up when people start printing lots of debug messages.
>>
>> Other than that it looks good to me.
>>
>
> I'd suggest that it would be easy enough to just use ConcurrentHashMap
> instead of HashSet if we are going to move to Java 5 anyway. Then, you
> don't have to worry about concurrency issues with toString() etc.
>
> Gregg Wonderly
>
>
> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au>
>> wrote:
>>
>>> Dan Creswell wrote:
>>>
>>>>
>>>> Solid - probably ought to be a constructor that doesn't add defaults
>>>> too.....and maybe a note about thread safety on add.
>>>>
>>>>
>>>>
>>>>
>>> The finished article.
>>>
>>> /*
>>> * 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.river.api.lookup;
>>>
>>> import java.util.HashSet;
>>> import java.util.Iterator;
>>> import java.util.Set;
>>> import net.jini.lookup.entry.Address;
>>> import net.jini.lookup.entry.Comment;
>>> import net.jini.lookup.entry.Location;
>>> import net.jini.lookup.entry.Name;
>>> import net.jini.lookup.entry.ServiceInfo;
>>> import net.jini.lookup.entry.Status;
>>> import net.jini.lookup.entry.UIDescriptor;
>>>
>>> /**
>>> * A little builder utility class that creates an array of Entry classes
>>> to
>>> * be used as a parameter for StreamServiceRegistrar. All the jini
>>> platform
>>> * Entry's are included by default.
>>> *
>>> * Note: This class is not threadsafe, use external synchronization if
>>> required.
>>> *
>>> * Suggested by Dan Creswell.
>>> * @author peter
>>> */
>>> public class DefaultEntries {
>>> private final Set<Class> entrys;
>>> public DefaultEntries() {
>>> entrys = new HashSet<Class>(16);
>>> }
>>> /**
>>> * Add an Entry class.
>>> * @param cl - class
>>> * @return this
>>> */
>>> public DefaultEntries add(Class cl){
>>> entrys.add(cl);
>>> return this;
>>> }
>>> /**
>>> * All all the Jini Platform Entry's
>>> * @return
>>> */
>>> public DefaultEntries addPlatformEntries(){
>>> add(Comment.class);
>>> add(Location.class);
>>> add(Name.class);
>>> add(ServiceInfo.class);
>>> add(Status.class);
>>> add(UIDescriptor.class);
>>> add(Address.class);
>>> return this;
>>> }
>>> /**
>>> * Remove all Entry's
>>> */
>>> public void reset(){
>>> entrys.clear();
>>> }
>>> /**
>>> * Generate a new array containing all Entry's added since last reset.
>>> * @return
>>> */
>>> public Class[] getEntries(){
>>> return entrys.toArray(new Class[entrys.size()]);
>>> }
>>>
>>> @Override
>>> public int hashCode() {
>>> int hash = 3;
>>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() :
>>> 0);
>>> return hash;
>>> }
>>>
>>> @Override
>>> public boolean equals(Object o){
>>> if (o == null) return false;
>>> if (o instanceof DefaultEntries){
>>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>>> }
>>> return false;
>>> }
>>> @Override
>>> public String toString(){
>>> String newline = System.getProperty("line.separator");
>>> StringBuilder sb = new StringBuilder(256);
>>> sb.append("DefaultEntries:");
>>> sb.append(newline);
>>> Iterator<Class> it = entrys.iterator();
>>> while (it.hasNext()){
>>> sb.append(it.next().getName());
>>> sb.append(newline);
>>> }
>>> return sb.toString();
>>> }
>>> }
>>>
>>>
>>
>
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
On 2/7/2011 5:24 AM, Tom Hobbs wrote:
> Sorry, I've got my nit-picking hat on...
>
> The null check in the equals method isn't needed because you get a
> free one by using "instanceof".
>
> I know you've warned that the class is not thread-safe, but people
> often forget that doing a sysout of an object calls toString(). I'd
> still be tempted to whack some protection into toString to stop it
> blowing up when people start printing lots of debug messages.
>
> Other than that it looks good to me.
I'd suggest that it would be easy enough to just use ConcurrentHashMap instead
of HashSet if we are going to move to Java 5 anyway. Then, you don't have to
worry about concurrency issues with toString() etc.
Gregg Wonderly
> On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone<ji...@zeus.net.au> wrote:
>> Dan Creswell wrote:
>>>
>>> Solid - probably ought to be a constructor that doesn't add defaults
>>> too.....and maybe a note about thread safety on add.
>>>
>>>
>>>
>>
>> The finished article.
>>
>> /*
>> * 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.river.api.lookup;
>>
>> import java.util.HashSet;
>> import java.util.Iterator;
>> import java.util.Set;
>> import net.jini.lookup.entry.Address;
>> import net.jini.lookup.entry.Comment;
>> import net.jini.lookup.entry.Location;
>> import net.jini.lookup.entry.Name;
>> import net.jini.lookup.entry.ServiceInfo;
>> import net.jini.lookup.entry.Status;
>> import net.jini.lookup.entry.UIDescriptor;
>>
>> /**
>> * A little builder utility class that creates an array of Entry classes to
>> * be used as a parameter for StreamServiceRegistrar. All the jini platform
>> * Entry's are included by default.
>> *
>> * Note: This class is not threadsafe, use external synchronization if
>> required.
>> *
>> * Suggested by Dan Creswell.
>> * @author peter
>> */
>> public class DefaultEntries {
>> private final Set<Class> entrys;
>> public DefaultEntries() {
>> entrys = new HashSet<Class>(16);
>> }
>> /**
>> * Add an Entry class.
>> * @param cl - class
>> * @return this
>> */
>> public DefaultEntries add(Class cl){
>> entrys.add(cl);
>> return this;
>> }
>> /**
>> * All all the Jini Platform Entry's
>> * @return
>> */
>> public DefaultEntries addPlatformEntries(){
>> add(Comment.class);
>> add(Location.class);
>> add(Name.class);
>> add(ServiceInfo.class);
>> add(Status.class);
>> add(UIDescriptor.class);
>> add(Address.class);
>> return this;
>> }
>> /**
>> * Remove all Entry's
>> */
>> public void reset(){
>> entrys.clear();
>> }
>> /**
>> * Generate a new array containing all Entry's added since last reset.
>> * @return
>> */
>> public Class[] getEntries(){
>> return entrys.toArray(new Class[entrys.size()]);
>> }
>>
>> @Override
>> public int hashCode() {
>> int hash = 3;
>> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() : 0);
>> return hash;
>> }
>>
>> @Override
>> public boolean equals(Object o){
>> if (o == null) return false;
>> if (o instanceof DefaultEntries){
>> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
>> }
>> return false;
>> }
>> @Override
>> public String toString(){
>> String newline = System.getProperty("line.separator");
>> StringBuilder sb = new StringBuilder(256);
>> sb.append("DefaultEntries:");
>> sb.append(newline);
>> Iterator<Class> it = entrys.iterator();
>> while (it.hasNext()){
>> sb.append(it.next().getName());
>> sb.append(newline);
>> }
>> return sb.toString();
>> }
>> }
>>
>
Re: MarshalledServiceItem
Posted by Tom Hobbs <tv...@googlemail.com>.
Sorry, I've got my nit-picking hat on...
The null check in the equals method isn't needed because you get a
free one by using "instanceof".
I know you've warned that the class is not thread-safe, but people
often forget that doing a sysout of an object calls toString(). I'd
still be tempted to whack some protection into toString to stop it
blowing up when people start printing lots of debug messages.
Other than that it looks good to me.
On Mon, Feb 7, 2011 at 10:56 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
> Dan Creswell wrote:
>>
>> Solid - probably ought to be a constructor that doesn't add defaults
>> too.....and maybe a note about thread safety on add.
>>
>>
>>
>
> The finished article.
>
> /*
> * 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.river.api.lookup;
>
> import java.util.HashSet;
> import java.util.Iterator;
> import java.util.Set;
> import net.jini.lookup.entry.Address;
> import net.jini.lookup.entry.Comment;
> import net.jini.lookup.entry.Location;
> import net.jini.lookup.entry.Name;
> import net.jini.lookup.entry.ServiceInfo;
> import net.jini.lookup.entry.Status;
> import net.jini.lookup.entry.UIDescriptor;
>
> /**
> * A little builder utility class that creates an array of Entry classes to
> * be used as a parameter for StreamServiceRegistrar. All the jini platform
> * Entry's are included by default.
> *
> * Note: This class is not threadsafe, use external synchronization if
> required.
> *
> * Suggested by Dan Creswell.
> * @author peter
> */
> public class DefaultEntries {
> private final Set<Class> entrys;
> public DefaultEntries() {
> entrys = new HashSet<Class>(16);
> }
> /**
> * Add an Entry class.
> * @param cl - class
> * @return this
> */
> public DefaultEntries add(Class cl){
> entrys.add(cl);
> return this;
> }
> /**
> * All all the Jini Platform Entry's
> * @return
> */
> public DefaultEntries addPlatformEntries(){
> add(Comment.class);
> add(Location.class);
> add(Name.class);
> add(ServiceInfo.class);
> add(Status.class);
> add(UIDescriptor.class);
> add(Address.class);
> return this;
> }
> /**
> * Remove all Entry's
> */
> public void reset(){
> entrys.clear();
> }
> /**
> * Generate a new array containing all Entry's added since last reset.
> * @return
> */
> public Class[] getEntries(){
> return entrys.toArray(new Class[entrys.size()]);
> }
>
> @Override
> public int hashCode() {
> int hash = 3;
> hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode() : 0);
> return hash;
> }
>
> @Override
> public boolean equals(Object o){
> if (o == null) return false;
> if (o instanceof DefaultEntries){
> if (entrys.equals(((DefaultEntries)o).entrys)) return true;
> }
> return false;
> }
> @Override
> public String toString(){
> String newline = System.getProperty("line.separator");
> StringBuilder sb = new StringBuilder(256);
> sb.append("DefaultEntries:");
> sb.append(newline);
> Iterator<Class> it = entrys.iterator();
> while (it.hasNext()){
> sb.append(it.next().getName());
> sb.append(newline);
> }
> return sb.toString();
> }
> }
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
> Solid - probably ought to be a constructor that doesn't add defaults
> too.....and maybe a note about thread safety on add.
>
>
>
The finished article.
/*
* 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.river.api.lookup;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.jini.lookup.entry.Address;
import net.jini.lookup.entry.Comment;
import net.jini.lookup.entry.Location;
import net.jini.lookup.entry.Name;
import net.jini.lookup.entry.ServiceInfo;
import net.jini.lookup.entry.Status;
import net.jini.lookup.entry.UIDescriptor;
/**
* A little builder utility class that creates an array of Entry classes to
* be used as a parameter for StreamServiceRegistrar. All the jini platform
* Entry's are included by default.
*
* Note: This class is not threadsafe, use external synchronization if
required.
*
* Suggested by Dan Creswell.
* @author peter
*/
public class DefaultEntries {
private final Set<Class> entrys;
public DefaultEntries() {
entrys = new HashSet<Class>(16);
}
/**
* Add an Entry class.
* @param cl - class
* @return this
*/
public DefaultEntries add(Class cl){
entrys.add(cl);
return this;
}
/**
* All all the Jini Platform Entry's
* @return
*/
public DefaultEntries addPlatformEntries(){
add(Comment.class);
add(Location.class);
add(Name.class);
add(ServiceInfo.class);
add(Status.class);
add(UIDescriptor.class);
add(Address.class);
return this;
}
/**
* Remove all Entry's
*/
public void reset(){
entrys.clear();
}
/**
* Generate a new array containing all Entry's added since last reset.
* @return
*/
public Class[] getEntries(){
return entrys.toArray(new Class[entrys.size()]);
}
@Override
public int hashCode() {
int hash = 3;
hash = 29 * hash + (this.entrys != null ? this.entrys.hashCode()
: 0);
return hash;
}
@Override
public boolean equals(Object o){
if (o == null) return false;
if (o instanceof DefaultEntries){
if (entrys.equals(((DefaultEntries)o).entrys)) return true;
}
return false;
}
@Override
public String toString(){
String newline = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder(256);
sb.append("DefaultEntries:");
sb.append(newline);
Iterator<Class> it = entrys.iterator();
while (it.hasNext()){
sb.append(it.next().getName());
sb.append(newline);
}
return sb.toString();
}
}
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
Solid - probably ought to be a constructor that doesn't add defaults
too.....and maybe a note about thread safety on add.
On 7 February 2011 04:29, Peter Firmstone <ji...@zeus.net.au> wrote:
> Dan Creswell wrote:
>
>>
>> Sorry, what you meant was the builder generates a default array or Set of
>>> Entry classes required to support the platform, additional Entry classes
>>> the
>>> client needs can be added, then it builds the array to pass as a
>>> parameter
>>> to the lookup service.
>>>
>>>
>>>
>>>
>> Yep.
>>
>>
>>
>>
>
> How's this?
>
> Cheers,
>
> Peter.
>
>
> /*
> * 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.river.api.lookup;
>
> import java.util.HashSet;
> import java.util.Set;
> import net.jini.lookup.entry.Address;
> import net.jini.lookup.entry.Comment;
> import net.jini.lookup.entry.Location;
> import net.jini.lookup.entry.Name;
> import net.jini.lookup.entry.ServiceInfo;
> import net.jini.lookup.entry.Status;
> import net.jini.lookup.entry.UIDescriptor;
>
> /**
> * A little builder utility class that creates an array of Entry classes to
> * be used as a parameter for StreamServiceRegistrar. All the platform
> * Entry's are included.
> *
> * Suggested by Dan Creswell.
> * @author peter
> */
> public class DefaultEntries {
> private final Set<Class> entrys;
> public DefaultEntries() {
> entrys = new HashSet<Class>(16);
> add(Comment.class);
> add(Location.class);
> add(Name.class);
> add(ServiceInfo.class);
> add(Status.class);
> add(UIDescriptor.class);
> add(Address.class);
> }
> public DefaultEntries add(Class cl){
> entrys.add(cl);
> return this;
> }
> public Class[] getEntries(){
> return entrys.toArray(new Class[entrys.size()]);
> }
>
> }
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
>
>> Sorry, what you meant was the builder generates a default array or Set of
>> Entry classes required to support the platform, additional Entry classes the
>> client needs can be added, then it builds the array to pass as a parameter
>> to the lookup service.
>>
>>
>>
> Yep.
>
>
>
How's this?
Cheers,
Peter.
/*
* 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.river.api.lookup;
import java.util.HashSet;
import java.util.Set;
import net.jini.lookup.entry.Address;
import net.jini.lookup.entry.Comment;
import net.jini.lookup.entry.Location;
import net.jini.lookup.entry.Name;
import net.jini.lookup.entry.ServiceInfo;
import net.jini.lookup.entry.Status;
import net.jini.lookup.entry.UIDescriptor;
/**
* A little builder utility class that creates an array of Entry classes to
* be used as a parameter for StreamServiceRegistrar. All the platform
* Entry's are included.
*
* Suggested by Dan Creswell.
* @author peter
*/
public class DefaultEntries {
private final Set<Class> entrys;
public DefaultEntries() {
entrys = new HashSet<Class>(16);
add(Comment.class);
add(Location.class);
add(Name.class);
add(ServiceInfo.class);
add(Status.class);
add(UIDescriptor.class);
add(Address.class);
}
public DefaultEntries add(Class cl){
entrys.add(cl);
return this;
}
public Class[] getEntries(){
return entrys.toArray(new Class[entrys.size()]);
}
}
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
S'cool.
On 6 February 2011 19:45, Peter Firmstone <ji...@zeus.net.au> wrote:
> I was thinking about post filtering on an Entry's contents after the lookup
> method returns.
>
>
Well, there might be a use case there as well, not sure but than haven't
thought about it....
> Sorry, what you meant was the builder generates a default array or Set of
> Entry classes required to support the platform, additional Entry classes the
> client needs can be added, then it builds the array to pass as a parameter
> to the lookup service.
>
>
Yep.
> Do you think we need to pass all classes related to the Entry's (fields) or
> just the Entry classes? I'm thinking it'd be simpler if it's just the Entry
> classes.
>
>
I'm thinking classes, anything more than that is more specific selection
that a client wants to do and hasn't accounted for in the original lookup
(which would seem to be a "broken" client?)
>
> Cheers,
>
> Peter.
>
> Dan Creswell wrote:
>
>> I was assuming a filter was inclusive by default. i.e. You specify just
>> the
>> things you're interested in a client seeing.
>>
>> There seems less value in removal given a client specifies its interests
>> somewhat in relation to what is on its classpath....
>>
>> On 6 February 2011 11:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>>
>>
>>
>>> A filter could also collect, rather than just remove.
>>>
>>> Do you think query/filter builders should be specific to a particular
>>> Entry
>>> type?
>>>
>>>
>>> Cheers,
>>>
>>> Peter.
>>>
>>> Dan Creswell wrote:
>>>
>>>
>>>
>>>> Yep.
>>>>
>>>> On 5 February 2011 10:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> Sounds interesting, looks like a builder?
>>>>>
>>>>>
>>>>> Dan Creswell wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> I'm also figuring you might have some wise defaults that people could
>>>>>> add
>>>>>> to
>>>>>> for constructing a filter/matchset.
>>>>>>
>>>>>> Something like:
>>>>>>
>>>>>> DefaultEntrys.add(...).add(....)
>>>>>>
>>>>>> DefaultEntrys probably includes something like ServiceInfo, Name and
>>>>>> such
>>>>>> -
>>>>>> all stock options in the platform...
>>>>>>
>>>>>> On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>>>>>>>
>>>>>>> So we make the Entry's the client's interested in, the only Entry's
>>>>>>> that'll
>>>>>>> be unmarshalled, those and the ServiceID.
>>>>>>>
>>>>>>>
>>>>>>> Cheers,
>>>>>>>
>>>>>>> Peter.
>>>>>>>
>>>>>>> Dan Creswell wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> ...
>>>>>>>>
>>>>>>>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> Dan Creswell wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> "ServiceClasspathSubItem is intended for client side filtering of
>>>>>>>>>> lookup
>>>>>>>>>> * service results prior to clients using a service, the lookup
>>>>>>>>>> service
>>>>>>>>>> * that implements this class, implements #getServiceItem(), so
>>>>>>>>>> clients
>>>>>>>>>> * can obtain a complete ServiceItem when required after
>>>>>>>>>> filtering."
>>>>>>>>>>
>>>>>>>>>> I'm still wondering if it wouldn't be better for a client to send
>>>>>>>>>> a
>>>>>>>>>> list
>>>>>>>>>> of
>>>>>>>>>> Entry's it's interested in seeing, separate from the set for
>>>>>>>>>> matching
>>>>>>>>>> to
>>>>>>>>>> the
>>>>>>>>>> Registrar. The Registrar can then return ServiceItems for the
>>>>>>>>>> matches
>>>>>>>>>> and
>>>>>>>>>> pre-filter the Entry's per item. Especially given:
>>>>>>>>>>
>>>>>>>>>> "Some fields in ServiceClasspathSubItem may be null, fields in
>>>>>>>>>> Entry's
>>>>>>>>>> may
>>>>>>>>>> * be null or even the service reference may be null, these fields
>>>>>>>>>> would
>>>>>>>>>> be
>>>>>>>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>>>>>>>> downloaded
>>>>>>>>>> * code or a remote codebase."
>>>>>>>>>>
>>>>>>>>>> I think, if we do the filtering as I suggest, much of the comment
>>>>>>>>>> re:
>>>>>>>>>> nulls
>>>>>>>>>> above still applies in implementation but ultimately, the client
>>>>>>>>>> will
>>>>>>>>>> pick
>>>>>>>>>> Entry's for which it has the classpath such that it always deals
>>>>>>>>>> in
>>>>>>>>>> complete
>>>>>>>>>> Entry's and can have a level of predictability in respect of what
>>>>>>>>>> is
>>>>>>>>>> or
>>>>>>>>>> is
>>>>>>>>>> not null. This might save clients having to do endless null checks
>>>>>>>>>> etc
>>>>>>>>>> that
>>>>>>>>>> can be a rich source of bugs and ugly code.
>>>>>>>>>>
>>>>>>>>>> We might need the filter list to include specific subclasses as
>>>>>>>>>> well....
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>> Hmm, null is a problem, we could still have fields missing subclass
>>>>>>>>> classes, which might prevent a subclass from unmarshalling.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Yeah, which is why I'm tempted to have the client be explicit about
>>>>>>>> which
>>>>>>>> Entry's (and that would include subclasses of those Entry's it can
>>>>>>>> tolerate). In this way the client can provide high-level explicit
>>>>>>>> guidance
>>>>>>>> as to what's right. No need for code to try and be clever and guess
>>>>>>>> the
>>>>>>>> client intent which is always ugly.
>>>>>>>>
>>>>>>>> Many times I suspect the Entry set used for matching will be the
>>>>>>>> same
>>>>>>>> as
>>>>>>>> the
>>>>>>>> filter set, probably can provide a nice method signature to help
>>>>>>>> that.
>>>>>>>>
>>>>>>>> Is there a way we can catch a class not found exception or similar
>>>>>>>> and
>>>>>>>> still
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> get the state of the superclass, or would this violate
>>>>>>>>> polymorphism,
>>>>>>>>> method
>>>>>>>>> overrides etc?
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Probably but again this is building clever code to try and
>>>>>>>> compensate.
>>>>>>>> It's
>>>>>>>> the same as writing all the null handling if you will albeit hidden
>>>>>>>> inside
>>>>>>>> the River libraries.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> I guess the likelihood of having null values is reduced, although
>>>>>>>>> not
>>>>>>>>> eliminated.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Quite.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> If we compact the final array of Entry's so null entry's are
>>>>>>>>> removed,
>>>>>>>>> the
>>>>>>>>> client only needs to find the Entry's it's interested in, likely
>>>>>>>>> ignoring
>>>>>>>>> the others anyway.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Sure but then the client has to explicitly construct filter code,
>>>>>>>> albeit
>>>>>>>> clean of null checks to go through the list of Entry's to find what
>>>>>>>> it's
>>>>>>>> interested in. Unless we return a HashMap(EntryClass.getName,
>>>>>>>> EntryClass.instance) to make that easier. Even so, you're still
>>>>>>>> returning
>>>>>>>> a
>>>>>>>> bunch of Entry's only some of which may be interesting to the
>>>>>>>> client....
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> So the client needs to ensure the Entry's are resolvable from the
>>>>>>>>> classpath.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Absolutely - and the fact that it must means it can thus construct a
>>>>>>>> proper
>>>>>>>> filter list of Entrys of interest.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> I have thought about the case where a proxy uses the lookup service
>>>>>>>>> and
>>>>>>>>> has
>>>>>>>>> Entry's in it's proxy classloader, but this could be subject to
>>>>>>>>> security
>>>>>>>>> issues, where two services with different Subject's end up sharing
>>>>>>>>> state.
>>>>>>>>>
>>>>>>>>> We might also consider only including Entry's that don't have null
>>>>>>>>> field
>>>>>>>>> values, this puts the impetus on the implementer to consider the
>>>>>>>>> Entry
>>>>>>>>> field
>>>>>>>>> classes.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Again, I think we're venturing into attempting to imply intent by
>>>>>>>> examining
>>>>>>>> null fields. If the implementer makes a mistake in their analysis
>>>>>>>> they
>>>>>>>> end
>>>>>>>> up with unexpected results come lookup. Personally I don't like this
>>>>>>>> sort
>>>>>>>> of
>>>>>>>> thing, I like explicit methods to guide an implementer and eliminate
>>>>>>>> opportunities for these kinds of confusion.
>>>>>>>>
>>>>>>>> That last bit is really why I'm down on trying to solve all these
>>>>>>>> problems
>>>>>>>> (including the bandwidth ones) with clever management of
>>>>>>>> class-downloading,
>>>>>>>> reflection and such. It's implicit, makes assumptions about usage
>>>>>>>> that
>>>>>>>> are
>>>>>>>> difficult for users to account for. It also leads to complicated,
>>>>>>>> brittle
>>>>>>>> code with many an opportunity for dark-corners/unhandled edge cases
>>>>>>>> that
>>>>>>>> cause confusion and are difficult to identify and fix for River
>>>>>>>> implementers
>>>>>>>> and users.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> Cheers,
>>>>>>>>>
>>>>>>>>> Peter.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
One thing I wanted to do is document the list of classnames that I found
necessary to "neverPrefer" in order to keep PreferredClassLoader from
downloading anything during Entry unmarshalling. There are some of my own
classnames in this list, but also there are lots of different low level class
names which all get resolved as part of the ClassLoading triggered by
PreferredClassLoader using the codebase's class loader (usually set as the
Thread's contextClassLoader).
neverPrefer( Name.class.getName() );
neverPrefer( ServiceInfo.class.getName() );
neverPrefer( ServiceType.class.getName() );
neverPrefer( ConsistentMap.class.getName() );
neverPrefer( DesktopIcon.class.getName() );
neverPrefer( DesktopCodebase.class.getName() );
neverPrefer( DesktopEntry.class.getName() );
neverPrefer( DesktopGroup.class.getName() );
neverPrefer( URL.class.getName() );
neverPrefer( URI.class.getName() );
neverPrefer( UIDescriptor.class.getName() );
neverPrefer( "org.wonderly.jini2.browse.ApplicationUIDescriptor" );
neverPrefer( "com.cytetech.jini.ApplicationUIDescriptor" );
neverPrefer( AdminDescriptor.class.getName() );
neverPrefer( JavaHelpEntry.class.getName() );
neverPrefer( HtmlHelpEntry.class.getName() );
neverPrefer( HelpEntry.class.getName() );
neverPrefer( MarshalledObject.class.getName() );
neverPrefer( java.lang.reflect.Proxy.class.getName() );
neverPrefer( net.jini.jeri.BasicInvocationHandler.class.getName() );
neverPrefer( net.jini.jeri.BasicObjectEndpoint.class.getName() );
neverPrefer( net.jini.jeri.BasicInvocationHandler.class.getName() );
neverPrefer( net.jini.jeri.ssl.SslEndpoint.class.getName() );
neverPrefer( net.jini.jeri.tcp.TcpEndpoint.class.getName() );
neverPrefer( net.jini.id.UuidFactory.class.getName() );
neverPrefer( net.jini.id.Uuid.class.getName() );
neverPrefer( com.artima.lookup.util.ConsistentSet.class.getName() );
neverPrefer( Object[].class.getName() );
neverPrefer( byte[].class.getName() );
If we keep the codebase ClassLoader out of view, then we can not really worry
too much about this list. But, I just wanted to make it clear to others, that
don't understand what's happening under the covers, that there are considerable
points of class resolution where the codebase's class loader can be accessed.
Gregg Wonderly
On 2/6/2011 1:45 PM, Peter Firmstone wrote:
> I was thinking about post filtering on an Entry's contents after the lookup
> method returns.
>
> Sorry, what you meant was the builder generates a default array or Set of Entry
> classes required to support the platform, additional Entry classes the client
> needs can be added, then it builds the array to pass as a parameter to the
> lookup service.
>
> Do you think we need to pass all classes related to the Entry's (fields) or just
> the Entry classes? I'm thinking it'd be simpler if it's just the Entry classes.
>
> Cheers,
>
> Peter.
>
> Dan Creswell wrote:
>> I was assuming a filter was inclusive by default. i.e. You specify just the
>> things you're interested in a client seeing.
>>
>> There seems less value in removal given a client specifies its interests
>> somewhat in relation to what is on its classpath....
>>
>> On 6 February 2011 11:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>>
>>> A filter could also collect, rather than just remove.
>>>
>>> Do you think query/filter builders should be specific to a particular Entry
>>> type?
>>>
>>>
>>> Cheers,
>>>
>>> Peter.
>>>
>>> Dan Creswell wrote:
>>>
>>>> Yep.
>>>>
>>>> On 5 February 2011 10:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>
>>>>
>>>>
>>>>> Sounds interesting, looks like a builder?
>>>>>
>>>>>
>>>>> Dan Creswell wrote:
>>>>>
>>>>>
>>>>>
>>>>>> I'm also figuring you might have some wise defaults that people could
>>>>>> add
>>>>>> to
>>>>>> for constructing a filter/matchset.
>>>>>>
>>>>>> Something like:
>>>>>>
>>>>>> DefaultEntrys.add(...).add(....)
>>>>>>
>>>>>> DefaultEntrys probably includes something like ServiceInfo, Name and
>>>>>> such
>>>>>> -
>>>>>> all stock options in the platform...
>>>>>>
>>>>>> On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>>>>>>>
>>>>>>> So we make the Entry's the client's interested in, the only Entry's
>>>>>>> that'll
>>>>>>> be unmarshalled, those and the ServiceID.
>>>>>>>
>>>>>>>
>>>>>>> Cheers,
>>>>>>>
>>>>>>> Peter.
>>>>>>>
>>>>>>> Dan Creswell wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> ...
>>>>>>>>
>>>>>>>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> Dan Creswell wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> "ServiceClasspathSubItem is intended for client side filtering of
>>>>>>>>>> lookup
>>>>>>>>>> * service results prior to clients using a service, the lookup
>>>>>>>>>> service
>>>>>>>>>> * that implements this class, implements #getServiceItem(), so
>>>>>>>>>> clients
>>>>>>>>>> * can obtain a complete ServiceItem when required after filtering."
>>>>>>>>>>
>>>>>>>>>> I'm still wondering if it wouldn't be better for a client to send a
>>>>>>>>>> list
>>>>>>>>>> of
>>>>>>>>>> Entry's it's interested in seeing, separate from the set for
>>>>>>>>>> matching
>>>>>>>>>> to
>>>>>>>>>> the
>>>>>>>>>> Registrar. The Registrar can then return ServiceItems for the
>>>>>>>>>> matches
>>>>>>>>>> and
>>>>>>>>>> pre-filter the Entry's per item. Especially given:
>>>>>>>>>>
>>>>>>>>>> "Some fields in ServiceClasspathSubItem may be null, fields in
>>>>>>>>>> Entry's
>>>>>>>>>> may
>>>>>>>>>> * be null or even the service reference may be null, these fields
>>>>>>>>>> would
>>>>>>>>>> be
>>>>>>>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>>>>>>>> downloaded
>>>>>>>>>> * code or a remote codebase."
>>>>>>>>>>
>>>>>>>>>> I think, if we do the filtering as I suggest, much of the comment
>>>>>>>>>> re:
>>>>>>>>>> nulls
>>>>>>>>>> above still applies in implementation but ultimately, the client
>>>>>>>>>> will
>>>>>>>>>> pick
>>>>>>>>>> Entry's for which it has the classpath such that it always deals in
>>>>>>>>>> complete
>>>>>>>>>> Entry's and can have a level of predictability in respect of what is
>>>>>>>>>> or
>>>>>>>>>> is
>>>>>>>>>> not null. This might save clients having to do endless null checks
>>>>>>>>>> etc
>>>>>>>>>> that
>>>>>>>>>> can be a rich source of bugs and ugly code.
>>>>>>>>>>
>>>>>>>>>> We might need the filter list to include specific subclasses as
>>>>>>>>>> well....
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>> Hmm, null is a problem, we could still have fields missing subclass
>>>>>>>>> classes, which might prevent a subclass from unmarshalling.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Yeah, which is why I'm tempted to have the client be explicit about
>>>>>>>> which
>>>>>>>> Entry's (and that would include subclasses of those Entry's it can
>>>>>>>> tolerate). In this way the client can provide high-level explicit
>>>>>>>> guidance
>>>>>>>> as to what's right. No need for code to try and be clever and guess
>>>>>>>> the
>>>>>>>> client intent which is always ugly.
>>>>>>>>
>>>>>>>> Many times I suspect the Entry set used for matching will be the same
>>>>>>>> as
>>>>>>>> the
>>>>>>>> filter set, probably can provide a nice method signature to help that.
>>>>>>>>
>>>>>>>> Is there a way we can catch a class not found exception or similar and
>>>>>>>> still
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> get the state of the superclass, or would this violate polymorphism,
>>>>>>>>> method
>>>>>>>>> overrides etc?
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Probably but again this is building clever code to try and compensate.
>>>>>>>> It's
>>>>>>>> the same as writing all the null handling if you will albeit hidden
>>>>>>>> inside
>>>>>>>> the River libraries.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> I guess the likelihood of having null values is reduced, although not
>>>>>>>>> eliminated.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Quite.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> If we compact the final array of Entry's so null entry's are removed,
>>>>>>>>> the
>>>>>>>>> client only needs to find the Entry's it's interested in, likely
>>>>>>>>> ignoring
>>>>>>>>> the others anyway.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Sure but then the client has to explicitly construct filter code,
>>>>>>>> albeit
>>>>>>>> clean of null checks to go through the list of Entry's to find what
>>>>>>>> it's
>>>>>>>> interested in. Unless we return a HashMap(EntryClass.getName,
>>>>>>>> EntryClass.instance) to make that easier. Even so, you're still
>>>>>>>> returning
>>>>>>>> a
>>>>>>>> bunch of Entry's only some of which may be interesting to the
>>>>>>>> client....
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> So the client needs to ensure the Entry's are resolvable from the
>>>>>>>>> classpath.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Absolutely - and the fact that it must means it can thus construct a
>>>>>>>> proper
>>>>>>>> filter list of Entrys of interest.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> I have thought about the case where a proxy uses the lookup service
>>>>>>>>> and
>>>>>>>>> has
>>>>>>>>> Entry's in it's proxy classloader, but this could be subject to
>>>>>>>>> security
>>>>>>>>> issues, where two services with different Subject's end up sharing
>>>>>>>>> state.
>>>>>>>>>
>>>>>>>>> We might also consider only including Entry's that don't have null
>>>>>>>>> field
>>>>>>>>> values, this puts the impetus on the implementer to consider the
>>>>>>>>> Entry
>>>>>>>>> field
>>>>>>>>> classes.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Again, I think we're venturing into attempting to imply intent by
>>>>>>>> examining
>>>>>>>> null fields. If the implementer makes a mistake in their analysis they
>>>>>>>> end
>>>>>>>> up with unexpected results come lookup. Personally I don't like this
>>>>>>>> sort
>>>>>>>> of
>>>>>>>> thing, I like explicit methods to guide an implementer and eliminate
>>>>>>>> opportunities for these kinds of confusion.
>>>>>>>>
>>>>>>>> That last bit is really why I'm down on trying to solve all these
>>>>>>>> problems
>>>>>>>> (including the bandwidth ones) with clever management of
>>>>>>>> class-downloading,
>>>>>>>> reflection and such. It's implicit, makes assumptions about usage that
>>>>>>>> are
>>>>>>>> difficult for users to account for. It also leads to complicated,
>>>>>>>> brittle
>>>>>>>> code with many an opportunity for dark-corners/unhandled edge cases
>>>>>>>> that
>>>>>>>> cause confusion and are difficult to identify and fix for River
>>>>>>>> implementers
>>>>>>>> and users.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> Cheers,
>>>>>>>>>
>>>>>>>>> Peter.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
I was thinking about post filtering on an Entry's contents after the
lookup method returns.
Sorry, what you meant was the builder generates a default array or Set
of Entry classes required to support the platform, additional Entry
classes the client needs can be added, then it builds the array to pass
as a parameter to the lookup service.
Do you think we need to pass all classes related to the Entry's (fields)
or just the Entry classes? I'm thinking it'd be simpler if it's just
the Entry classes.
Cheers,
Peter.
Dan Creswell wrote:
> I was assuming a filter was inclusive by default. i.e. You specify just the
> things you're interested in a client seeing.
>
> There seems less value in removal given a client specifies its interests
> somewhat in relation to what is on its classpath....
>
> On 6 February 2011 11:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> A filter could also collect, rather than just remove.
>>
>> Do you think query/filter builders should be specific to a particular Entry
>> type?
>>
>>
>> Cheers,
>>
>> Peter.
>>
>> Dan Creswell wrote:
>>
>>
>>> Yep.
>>>
>>> On 5 February 2011 10:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>
>>>
>>>
>>>
>>>> Sounds interesting, looks like a builder?
>>>>
>>>>
>>>> Dan Creswell wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> I'm also figuring you might have some wise defaults that people could
>>>>> add
>>>>> to
>>>>> for constructing a filter/matchset.
>>>>>
>>>>> Something like:
>>>>>
>>>>> DefaultEntrys.add(...).add(....)
>>>>>
>>>>> DefaultEntrys probably includes something like ServiceInfo, Name and
>>>>> such
>>>>> -
>>>>> all stock options in the platform...
>>>>>
>>>>> On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>>>>>>
>>>>>> So we make the Entry's the client's interested in, the only Entry's
>>>>>> that'll
>>>>>> be unmarshalled, those and the ServiceID.
>>>>>>
>>>>>>
>>>>>> Cheers,
>>>>>>
>>>>>> Peter.
>>>>>>
>>>>>> Dan Creswell wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> ...
>>>>>>>
>>>>>>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> Dan Creswell wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> "ServiceClasspathSubItem is intended for client side filtering of
>>>>>>>>> lookup
>>>>>>>>> * service results prior to clients using a service, the lookup
>>>>>>>>> service
>>>>>>>>> * that implements this class, implements #getServiceItem(), so
>>>>>>>>> clients
>>>>>>>>> * can obtain a complete ServiceItem when required after filtering."
>>>>>>>>>
>>>>>>>>> I'm still wondering if it wouldn't be better for a client to send a
>>>>>>>>> list
>>>>>>>>> of
>>>>>>>>> Entry's it's interested in seeing, separate from the set for
>>>>>>>>> matching
>>>>>>>>> to
>>>>>>>>> the
>>>>>>>>> Registrar. The Registrar can then return ServiceItems for the
>>>>>>>>> matches
>>>>>>>>> and
>>>>>>>>> pre-filter the Entry's per item. Especially given:
>>>>>>>>>
>>>>>>>>> "Some fields in ServiceClasspathSubItem may be null, fields in
>>>>>>>>> Entry's
>>>>>>>>> may
>>>>>>>>> * be null or even the service reference may be null, these fields
>>>>>>>>> would
>>>>>>>>> be
>>>>>>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>>>>>>> downloaded
>>>>>>>>> * code or a remote codebase."
>>>>>>>>>
>>>>>>>>> I think, if we do the filtering as I suggest, much of the comment
>>>>>>>>> re:
>>>>>>>>> nulls
>>>>>>>>> above still applies in implementation but ultimately, the client
>>>>>>>>> will
>>>>>>>>> pick
>>>>>>>>> Entry's for which it has the classpath such that it always deals in
>>>>>>>>> complete
>>>>>>>>> Entry's and can have a level of predictability in respect of what is
>>>>>>>>> or
>>>>>>>>> is
>>>>>>>>> not null. This might save clients having to do endless null checks
>>>>>>>>> etc
>>>>>>>>> that
>>>>>>>>> can be a rich source of bugs and ugly code.
>>>>>>>>>
>>>>>>>>> We might need the filter list to include specific subclasses as
>>>>>>>>> well....
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Hmm, null is a problem, we could still have fields missing subclass
>>>>>>>> classes, which might prevent a subclass from unmarshalling.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Yeah, which is why I'm tempted to have the client be explicit about
>>>>>>> which
>>>>>>> Entry's (and that would include subclasses of those Entry's it can
>>>>>>> tolerate). In this way the client can provide high-level explicit
>>>>>>> guidance
>>>>>>> as to what's right. No need for code to try and be clever and guess
>>>>>>> the
>>>>>>> client intent which is always ugly.
>>>>>>>
>>>>>>> Many times I suspect the Entry set used for matching will be the same
>>>>>>> as
>>>>>>> the
>>>>>>> filter set, probably can provide a nice method signature to help that.
>>>>>>>
>>>>>>> Is there a way we can catch a class not found exception or similar and
>>>>>>> still
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> get the state of the superclass, or would this violate polymorphism,
>>>>>>>> method
>>>>>>>> overrides etc?
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Probably but again this is building clever code to try and compensate.
>>>>>>> It's
>>>>>>> the same as writing all the null handling if you will albeit hidden
>>>>>>> inside
>>>>>>> the River libraries.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> I guess the likelihood of having null values is reduced, although not
>>>>>>>> eliminated.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Quite.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> If we compact the final array of Entry's so null entry's are removed,
>>>>>>>> the
>>>>>>>> client only needs to find the Entry's it's interested in, likely
>>>>>>>> ignoring
>>>>>>>> the others anyway.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Sure but then the client has to explicitly construct filter code,
>>>>>>> albeit
>>>>>>> clean of null checks to go through the list of Entry's to find what
>>>>>>> it's
>>>>>>> interested in. Unless we return a HashMap(EntryClass.getName,
>>>>>>> EntryClass.instance) to make that easier. Even so, you're still
>>>>>>> returning
>>>>>>> a
>>>>>>> bunch of Entry's only some of which may be interesting to the
>>>>>>> client....
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> So the client needs to ensure the Entry's are resolvable from the
>>>>>>>> classpath.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Absolutely - and the fact that it must means it can thus construct a
>>>>>>> proper
>>>>>>> filter list of Entrys of interest.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> I have thought about the case where a proxy uses the lookup service
>>>>>>>> and
>>>>>>>> has
>>>>>>>> Entry's in it's proxy classloader, but this could be subject to
>>>>>>>> security
>>>>>>>> issues, where two services with different Subject's end up sharing
>>>>>>>> state.
>>>>>>>>
>>>>>>>> We might also consider only including Entry's that don't have null
>>>>>>>> field
>>>>>>>> values, this puts the impetus on the implementer to consider the
>>>>>>>> Entry
>>>>>>>> field
>>>>>>>> classes.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Again, I think we're venturing into attempting to imply intent by
>>>>>>> examining
>>>>>>> null fields. If the implementer makes a mistake in their analysis they
>>>>>>> end
>>>>>>> up with unexpected results come lookup. Personally I don't like this
>>>>>>> sort
>>>>>>> of
>>>>>>> thing, I like explicit methods to guide an implementer and eliminate
>>>>>>> opportunities for these kinds of confusion.
>>>>>>>
>>>>>>> That last bit is really why I'm down on trying to solve all these
>>>>>>> problems
>>>>>>> (including the bandwidth ones) with clever management of
>>>>>>> class-downloading,
>>>>>>> reflection and such. It's implicit, makes assumptions about usage that
>>>>>>> are
>>>>>>> difficult for users to account for. It also leads to complicated,
>>>>>>> brittle
>>>>>>> code with many an opportunity for dark-corners/unhandled edge cases
>>>>>>> that
>>>>>>> cause confusion and are difficult to identify and fix for River
>>>>>>> implementers
>>>>>>> and users.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> Cheers,
>>>>>>>>
>>>>>>>> Peter.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
I was assuming a filter was inclusive by default. i.e. You specify just the
things you're interested in a client seeing.
There seems less value in removal given a client specifies its interests
somewhat in relation to what is on its classpath....
On 6 February 2011 11:45, Peter Firmstone <ji...@zeus.net.au> wrote:
> A filter could also collect, rather than just remove.
>
> Do you think query/filter builders should be specific to a particular Entry
> type?
>
>
> Cheers,
>
> Peter.
>
> Dan Creswell wrote:
>
>> Yep.
>>
>> On 5 February 2011 10:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>>
>>
>>
>>> Sounds interesting, looks like a builder?
>>>
>>>
>>> Dan Creswell wrote:
>>>
>>>
>>>
>>>> I'm also figuring you might have some wise defaults that people could
>>>> add
>>>> to
>>>> for constructing a filter/matchset.
>>>>
>>>> Something like:
>>>>
>>>> DefaultEntrys.add(...).add(....)
>>>>
>>>> DefaultEntrys probably includes something like ServiceInfo, Name and
>>>> such
>>>> -
>>>> all stock options in the platform...
>>>>
>>>> On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>>>>>
>>>>> So we make the Entry's the client's interested in, the only Entry's
>>>>> that'll
>>>>> be unmarshalled, those and the ServiceID.
>>>>>
>>>>>
>>>>> Cheers,
>>>>>
>>>>> Peter.
>>>>>
>>>>> Dan Creswell wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> ...
>>>>>>
>>>>>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> Dan Creswell wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> "ServiceClasspathSubItem is intended for client side filtering of
>>>>>>>> lookup
>>>>>>>> * service results prior to clients using a service, the lookup
>>>>>>>> service
>>>>>>>> * that implements this class, implements #getServiceItem(), so
>>>>>>>> clients
>>>>>>>> * can obtain a complete ServiceItem when required after filtering."
>>>>>>>>
>>>>>>>> I'm still wondering if it wouldn't be better for a client to send a
>>>>>>>> list
>>>>>>>> of
>>>>>>>> Entry's it's interested in seeing, separate from the set for
>>>>>>>> matching
>>>>>>>> to
>>>>>>>> the
>>>>>>>> Registrar. The Registrar can then return ServiceItems for the
>>>>>>>> matches
>>>>>>>> and
>>>>>>>> pre-filter the Entry's per item. Especially given:
>>>>>>>>
>>>>>>>> "Some fields in ServiceClasspathSubItem may be null, fields in
>>>>>>>> Entry's
>>>>>>>> may
>>>>>>>> * be null or even the service reference may be null, these fields
>>>>>>>> would
>>>>>>>> be
>>>>>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>>>>>> downloaded
>>>>>>>> * code or a remote codebase."
>>>>>>>>
>>>>>>>> I think, if we do the filtering as I suggest, much of the comment
>>>>>>>> re:
>>>>>>>> nulls
>>>>>>>> above still applies in implementation but ultimately, the client
>>>>>>>> will
>>>>>>>> pick
>>>>>>>> Entry's for which it has the classpath such that it always deals in
>>>>>>>> complete
>>>>>>>> Entry's and can have a level of predictability in respect of what is
>>>>>>>> or
>>>>>>>> is
>>>>>>>> not null. This might save clients having to do endless null checks
>>>>>>>> etc
>>>>>>>> that
>>>>>>>> can be a rich source of bugs and ugly code.
>>>>>>>>
>>>>>>>> We might need the filter list to include specific subclasses as
>>>>>>>> well....
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Hmm, null is a problem, we could still have fields missing subclass
>>>>>>> classes, which might prevent a subclass from unmarshalling.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Yeah, which is why I'm tempted to have the client be explicit about
>>>>>> which
>>>>>> Entry's (and that would include subclasses of those Entry's it can
>>>>>> tolerate). In this way the client can provide high-level explicit
>>>>>> guidance
>>>>>> as to what's right. No need for code to try and be clever and guess
>>>>>> the
>>>>>> client intent which is always ugly.
>>>>>>
>>>>>> Many times I suspect the Entry set used for matching will be the same
>>>>>> as
>>>>>> the
>>>>>> filter set, probably can provide a nice method signature to help that.
>>>>>>
>>>>>> Is there a way we can catch a class not found exception or similar and
>>>>>> still
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> get the state of the superclass, or would this violate polymorphism,
>>>>>>> method
>>>>>>> overrides etc?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Probably but again this is building clever code to try and compensate.
>>>>>> It's
>>>>>> the same as writing all the null handling if you will albeit hidden
>>>>>> inside
>>>>>> the River libraries.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> I guess the likelihood of having null values is reduced, although not
>>>>>>> eliminated.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Quite.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> If we compact the final array of Entry's so null entry's are removed,
>>>>>>> the
>>>>>>> client only needs to find the Entry's it's interested in, likely
>>>>>>> ignoring
>>>>>>> the others anyway.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Sure but then the client has to explicitly construct filter code,
>>>>>> albeit
>>>>>> clean of null checks to go through the list of Entry's to find what
>>>>>> it's
>>>>>> interested in. Unless we return a HashMap(EntryClass.getName,
>>>>>> EntryClass.instance) to make that easier. Even so, you're still
>>>>>> returning
>>>>>> a
>>>>>> bunch of Entry's only some of which may be interesting to the
>>>>>> client....
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> So the client needs to ensure the Entry's are resolvable from the
>>>>>>> classpath.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Absolutely - and the fact that it must means it can thus construct a
>>>>>> proper
>>>>>> filter list of Entrys of interest.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> I have thought about the case where a proxy uses the lookup service
>>>>>>> and
>>>>>>> has
>>>>>>> Entry's in it's proxy classloader, but this could be subject to
>>>>>>> security
>>>>>>> issues, where two services with different Subject's end up sharing
>>>>>>> state.
>>>>>>>
>>>>>>> We might also consider only including Entry's that don't have null
>>>>>>> field
>>>>>>> values, this puts the impetus on the implementer to consider the
>>>>>>> Entry
>>>>>>> field
>>>>>>> classes.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Again, I think we're venturing into attempting to imply intent by
>>>>>> examining
>>>>>> null fields. If the implementer makes a mistake in their analysis they
>>>>>> end
>>>>>> up with unexpected results come lookup. Personally I don't like this
>>>>>> sort
>>>>>> of
>>>>>> thing, I like explicit methods to guide an implementer and eliminate
>>>>>> opportunities for these kinds of confusion.
>>>>>>
>>>>>> That last bit is really why I'm down on trying to solve all these
>>>>>> problems
>>>>>> (including the bandwidth ones) with clever management of
>>>>>> class-downloading,
>>>>>> reflection and such. It's implicit, makes assumptions about usage that
>>>>>> are
>>>>>> difficult for users to account for. It also leads to complicated,
>>>>>> brittle
>>>>>> code with many an opportunity for dark-corners/unhandled edge cases
>>>>>> that
>>>>>> cause confusion and are difficult to identify and fix for River
>>>>>> implementers
>>>>>> and users.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> Cheers,
>>>>>>>
>>>>>>> Peter.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
A filter could also collect, rather than just remove.
Do you think query/filter builders should be specific to a particular
Entry type?
Cheers,
Peter.
Dan Creswell wrote:
> Yep.
>
> On 5 February 2011 10:45, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> Sounds interesting, looks like a builder?
>>
>>
>> Dan Creswell wrote:
>>
>>
>>> I'm also figuring you might have some wise defaults that people could add
>>> to
>>> for constructing a filter/matchset.
>>>
>>> Something like:
>>>
>>> DefaultEntrys.add(...).add(....)
>>>
>>> DefaultEntrys probably includes something like ServiceInfo, Name and such
>>> -
>>> all stock options in the platform...
>>>
>>> On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>
>>>
>>>
>>>
>>>> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>>>>
>>>> So we make the Entry's the client's interested in, the only Entry's
>>>> that'll
>>>> be unmarshalled, those and the ServiceID.
>>>>
>>>>
>>>> Cheers,
>>>>
>>>> Peter.
>>>>
>>>> Dan Creswell wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> ...
>>>>>
>>>>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> Dan Creswell wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> "ServiceClasspathSubItem is intended for client side filtering of
>>>>>>> lookup
>>>>>>> * service results prior to clients using a service, the lookup service
>>>>>>> * that implements this class, implements #getServiceItem(), so clients
>>>>>>> * can obtain a complete ServiceItem when required after filtering."
>>>>>>>
>>>>>>> I'm still wondering if it wouldn't be better for a client to send a
>>>>>>> list
>>>>>>> of
>>>>>>> Entry's it's interested in seeing, separate from the set for matching
>>>>>>> to
>>>>>>> the
>>>>>>> Registrar. The Registrar can then return ServiceItems for the matches
>>>>>>> and
>>>>>>> pre-filter the Entry's per item. Especially given:
>>>>>>>
>>>>>>> "Some fields in ServiceClasspathSubItem may be null, fields in Entry's
>>>>>>> may
>>>>>>> * be null or even the service reference may be null, these fields
>>>>>>> would
>>>>>>> be
>>>>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>>>>> downloaded
>>>>>>> * code or a remote codebase."
>>>>>>>
>>>>>>> I think, if we do the filtering as I suggest, much of the comment re:
>>>>>>> nulls
>>>>>>> above still applies in implementation but ultimately, the client will
>>>>>>> pick
>>>>>>> Entry's for which it has the classpath such that it always deals in
>>>>>>> complete
>>>>>>> Entry's and can have a level of predictability in respect of what is
>>>>>>> or
>>>>>>> is
>>>>>>> not null. This might save clients having to do endless null checks etc
>>>>>>> that
>>>>>>> can be a rich source of bugs and ugly code.
>>>>>>>
>>>>>>> We might need the filter list to include specific subclasses as
>>>>>>> well....
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Hmm, null is a problem, we could still have fields missing subclass
>>>>>> classes, which might prevent a subclass from unmarshalling.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Yeah, which is why I'm tempted to have the client be explicit about
>>>>> which
>>>>> Entry's (and that would include subclasses of those Entry's it can
>>>>> tolerate). In this way the client can provide high-level explicit
>>>>> guidance
>>>>> as to what's right. No need for code to try and be clever and guess the
>>>>> client intent which is always ugly.
>>>>>
>>>>> Many times I suspect the Entry set used for matching will be the same as
>>>>> the
>>>>> filter set, probably can provide a nice method signature to help that.
>>>>>
>>>>> Is there a way we can catch a class not found exception or similar and
>>>>> still
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> get the state of the superclass, or would this violate polymorphism,
>>>>>> method
>>>>>> overrides etc?
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Probably but again this is building clever code to try and compensate.
>>>>> It's
>>>>> the same as writing all the null handling if you will albeit hidden
>>>>> inside
>>>>> the River libraries.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> I guess the likelihood of having null values is reduced, although not
>>>>>> eliminated.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Quite.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> If we compact the final array of Entry's so null entry's are removed,
>>>>>> the
>>>>>> client only needs to find the Entry's it's interested in, likely
>>>>>> ignoring
>>>>>> the others anyway.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Sure but then the client has to explicitly construct filter code, albeit
>>>>> clean of null checks to go through the list of Entry's to find what it's
>>>>> interested in. Unless we return a HashMap(EntryClass.getName,
>>>>> EntryClass.instance) to make that easier. Even so, you're still
>>>>> returning
>>>>> a
>>>>> bunch of Entry's only some of which may be interesting to the client....
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> So the client needs to ensure the Entry's are resolvable from the
>>>>>> classpath.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Absolutely - and the fact that it must means it can thus construct a
>>>>> proper
>>>>> filter list of Entrys of interest.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> I have thought about the case where a proxy uses the lookup service and
>>>>>> has
>>>>>> Entry's in it's proxy classloader, but this could be subject to
>>>>>> security
>>>>>> issues, where two services with different Subject's end up sharing
>>>>>> state.
>>>>>>
>>>>>> We might also consider only including Entry's that don't have null
>>>>>> field
>>>>>> values, this puts the impetus on the implementer to consider the Entry
>>>>>> field
>>>>>> classes.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Again, I think we're venturing into attempting to imply intent by
>>>>> examining
>>>>> null fields. If the implementer makes a mistake in their analysis they
>>>>> end
>>>>> up with unexpected results come lookup. Personally I don't like this
>>>>> sort
>>>>> of
>>>>> thing, I like explicit methods to guide an implementer and eliminate
>>>>> opportunities for these kinds of confusion.
>>>>>
>>>>> That last bit is really why I'm down on trying to solve all these
>>>>> problems
>>>>> (including the bandwidth ones) with clever management of
>>>>> class-downloading,
>>>>> reflection and such. It's implicit, makes assumptions about usage that
>>>>> are
>>>>> difficult for users to account for. It also leads to complicated,
>>>>> brittle
>>>>> code with many an opportunity for dark-corners/unhandled edge cases that
>>>>> cause confusion and are difficult to identify and fix for River
>>>>> implementers
>>>>> and users.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> Cheers,
>>>>>>
>>>>>> Peter.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
Yep.
On 5 February 2011 10:45, Peter Firmstone <ji...@zeus.net.au> wrote:
> Sounds interesting, looks like a builder?
>
>
> Dan Creswell wrote:
>
>> I'm also figuring you might have some wise defaults that people could add
>> to
>> for constructing a filter/matchset.
>>
>> Something like:
>>
>> DefaultEntrys.add(...).add(....)
>>
>> DefaultEntrys probably includes something like ServiceInfo, Name and such
>> -
>> all stock options in the platform...
>>
>> On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
>>
>>
>>
>>> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>>>
>>> So we make the Entry's the client's interested in, the only Entry's
>>> that'll
>>> be unmarshalled, those and the ServiceID.
>>>
>>>
>>> Cheers,
>>>
>>> Peter.
>>>
>>> Dan Creswell wrote:
>>>
>>>
>>>
>>>> ...
>>>>
>>>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> Dan Creswell wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> "ServiceClasspathSubItem is intended for client side filtering of
>>>>>> lookup
>>>>>> * service results prior to clients using a service, the lookup service
>>>>>> * that implements this class, implements #getServiceItem(), so clients
>>>>>> * can obtain a complete ServiceItem when required after filtering."
>>>>>>
>>>>>> I'm still wondering if it wouldn't be better for a client to send a
>>>>>> list
>>>>>> of
>>>>>> Entry's it's interested in seeing, separate from the set for matching
>>>>>> to
>>>>>> the
>>>>>> Registrar. The Registrar can then return ServiceItems for the matches
>>>>>> and
>>>>>> pre-filter the Entry's per item. Especially given:
>>>>>>
>>>>>> "Some fields in ServiceClasspathSubItem may be null, fields in Entry's
>>>>>> may
>>>>>> * be null or even the service reference may be null, these fields
>>>>>> would
>>>>>> be
>>>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>>>> downloaded
>>>>>> * code or a remote codebase."
>>>>>>
>>>>>> I think, if we do the filtering as I suggest, much of the comment re:
>>>>>> nulls
>>>>>> above still applies in implementation but ultimately, the client will
>>>>>> pick
>>>>>> Entry's for which it has the classpath such that it always deals in
>>>>>> complete
>>>>>> Entry's and can have a level of predictability in respect of what is
>>>>>> or
>>>>>> is
>>>>>> not null. This might save clients having to do endless null checks etc
>>>>>> that
>>>>>> can be a rich source of bugs and ugly code.
>>>>>>
>>>>>> We might need the filter list to include specific subclasses as
>>>>>> well....
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> Hmm, null is a problem, we could still have fields missing subclass
>>>>> classes, which might prevent a subclass from unmarshalling.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Yeah, which is why I'm tempted to have the client be explicit about
>>>> which
>>>> Entry's (and that would include subclasses of those Entry's it can
>>>> tolerate). In this way the client can provide high-level explicit
>>>> guidance
>>>> as to what's right. No need for code to try and be clever and guess the
>>>> client intent which is always ugly.
>>>>
>>>> Many times I suspect the Entry set used for matching will be the same as
>>>> the
>>>> filter set, probably can provide a nice method signature to help that.
>>>>
>>>> Is there a way we can catch a class not found exception or similar and
>>>> still
>>>>
>>>>
>>>>
>>>>
>>>>> get the state of the superclass, or would this violate polymorphism,
>>>>> method
>>>>> overrides etc?
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Probably but again this is building clever code to try and compensate.
>>>> It's
>>>> the same as writing all the null handling if you will albeit hidden
>>>> inside
>>>> the River libraries.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> I guess the likelihood of having null values is reduced, although not
>>>>> eliminated.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Quite.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> If we compact the final array of Entry's so null entry's are removed,
>>>>> the
>>>>> client only needs to find the Entry's it's interested in, likely
>>>>> ignoring
>>>>> the others anyway.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Sure but then the client has to explicitly construct filter code, albeit
>>>> clean of null checks to go through the list of Entry's to find what it's
>>>> interested in. Unless we return a HashMap(EntryClass.getName,
>>>> EntryClass.instance) to make that easier. Even so, you're still
>>>> returning
>>>> a
>>>> bunch of Entry's only some of which may be interesting to the client....
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> So the client needs to ensure the Entry's are resolvable from the
>>>>> classpath.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Absolutely - and the fact that it must means it can thus construct a
>>>> proper
>>>> filter list of Entrys of interest.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> I have thought about the case where a proxy uses the lookup service and
>>>>> has
>>>>> Entry's in it's proxy classloader, but this could be subject to
>>>>> security
>>>>> issues, where two services with different Subject's end up sharing
>>>>> state.
>>>>>
>>>>> We might also consider only including Entry's that don't have null
>>>>> field
>>>>> values, this puts the impetus on the implementer to consider the Entry
>>>>> field
>>>>> classes.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Again, I think we're venturing into attempting to imply intent by
>>>> examining
>>>> null fields. If the implementer makes a mistake in their analysis they
>>>> end
>>>> up with unexpected results come lookup. Personally I don't like this
>>>> sort
>>>> of
>>>> thing, I like explicit methods to guide an implementer and eliminate
>>>> opportunities for these kinds of confusion.
>>>>
>>>> That last bit is really why I'm down on trying to solve all these
>>>> problems
>>>> (including the bandwidth ones) with clever management of
>>>> class-downloading,
>>>> reflection and such. It's implicit, makes assumptions about usage that
>>>> are
>>>> difficult for users to account for. It also leads to complicated,
>>>> brittle
>>>> code with many an opportunity for dark-corners/unhandled edge cases that
>>>> cause confusion and are difficult to identify and fix for River
>>>> implementers
>>>> and users.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> Cheers,
>>>>>
>>>>> Peter.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Sounds interesting, looks like a builder?
Dan Creswell wrote:
> I'm also figuring you might have some wise defaults that people could add to
> for constructing a filter/matchset.
>
> Something like:
>
> DefaultEntrys.add(...).add(....)
>
> DefaultEntrys probably includes something like ServiceInfo, Name and such -
> all stock options in the platform...
>
> On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>>
>> So we make the Entry's the client's interested in, the only Entry's that'll
>> be unmarshalled, those and the ServiceID.
>>
>>
>> Cheers,
>>
>> Peter.
>>
>> Dan Creswell wrote:
>>
>>
>>> ...
>>>
>>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>
>>>
>>>
>>>
>>>> Dan Creswell wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> "ServiceClasspathSubItem is intended for client side filtering of lookup
>>>>> * service results prior to clients using a service, the lookup service
>>>>> * that implements this class, implements #getServiceItem(), so clients
>>>>> * can obtain a complete ServiceItem when required after filtering."
>>>>>
>>>>> I'm still wondering if it wouldn't be better for a client to send a list
>>>>> of
>>>>> Entry's it's interested in seeing, separate from the set for matching to
>>>>> the
>>>>> Registrar. The Registrar can then return ServiceItems for the matches
>>>>> and
>>>>> pre-filter the Entry's per item. Especially given:
>>>>>
>>>>> "Some fields in ServiceClasspathSubItem may be null, fields in Entry's
>>>>> may
>>>>> * be null or even the service reference may be null, these fields would
>>>>> be
>>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>>> downloaded
>>>>> * code or a remote codebase."
>>>>>
>>>>> I think, if we do the filtering as I suggest, much of the comment re:
>>>>> nulls
>>>>> above still applies in implementation but ultimately, the client will
>>>>> pick
>>>>> Entry's for which it has the classpath such that it always deals in
>>>>> complete
>>>>> Entry's and can have a level of predictability in respect of what is or
>>>>> is
>>>>> not null. This might save clients having to do endless null checks etc
>>>>> that
>>>>> can be a rich source of bugs and ugly code.
>>>>>
>>>>> We might need the filter list to include specific subclasses as well....
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> Hmm, null is a problem, we could still have fields missing subclass
>>>> classes, which might prevent a subclass from unmarshalling.
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Yeah, which is why I'm tempted to have the client be explicit about which
>>> Entry's (and that would include subclasses of those Entry's it can
>>> tolerate). In this way the client can provide high-level explicit guidance
>>> as to what's right. No need for code to try and be clever and guess the
>>> client intent which is always ugly.
>>>
>>> Many times I suspect the Entry set used for matching will be the same as
>>> the
>>> filter set, probably can provide a nice method signature to help that.
>>>
>>> Is there a way we can catch a class not found exception or similar and
>>> still
>>>
>>>
>>>
>>>> get the state of the superclass, or would this violate polymorphism,
>>>> method
>>>> overrides etc?
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Probably but again this is building clever code to try and compensate.
>>> It's
>>> the same as writing all the null handling if you will albeit hidden inside
>>> the River libraries.
>>>
>>>
>>>
>>>
>>>
>>>> I guess the likelihood of having null values is reduced, although not
>>>> eliminated.
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Quite.
>>>
>>>
>>>
>>>
>>>
>>>> If we compact the final array of Entry's so null entry's are removed, the
>>>> client only needs to find the Entry's it's interested in, likely ignoring
>>>> the others anyway.
>>>>
>>>>
>>>>
>>>>
>>> Sure but then the client has to explicitly construct filter code, albeit
>>> clean of null checks to go through the list of Entry's to find what it's
>>> interested in. Unless we return a HashMap(EntryClass.getName,
>>> EntryClass.instance) to make that easier. Even so, you're still returning
>>> a
>>> bunch of Entry's only some of which may be interesting to the client....
>>>
>>>
>>>
>>>
>>>
>>>> So the client needs to ensure the Entry's are resolvable from the
>>>> classpath.
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Absolutely - and the fact that it must means it can thus construct a
>>> proper
>>> filter list of Entrys of interest.
>>>
>>>
>>>
>>>
>>>
>>>> I have thought about the case where a proxy uses the lookup service and
>>>> has
>>>> Entry's in it's proxy classloader, but this could be subject to security
>>>> issues, where two services with different Subject's end up sharing state.
>>>>
>>>> We might also consider only including Entry's that don't have null field
>>>> values, this puts the impetus on the implementer to consider the Entry
>>>> field
>>>> classes.
>>>>
>>>>
>>>>
>>>>
>>> Again, I think we're venturing into attempting to imply intent by
>>> examining
>>> null fields. If the implementer makes a mistake in their analysis they end
>>> up with unexpected results come lookup. Personally I don't like this sort
>>> of
>>> thing, I like explicit methods to guide an implementer and eliminate
>>> opportunities for these kinds of confusion.
>>>
>>> That last bit is really why I'm down on trying to solve all these problems
>>> (including the bandwidth ones) with clever management of
>>> class-downloading,
>>> reflection and such. It's implicit, makes assumptions about usage that are
>>> difficult for users to account for. It also leads to complicated, brittle
>>> code with many an opportunity for dark-corners/unhandled edge cases that
>>> cause confusion and are difficult to identify and fix for River
>>> implementers
>>> and users.
>>>
>>>
>>>
>>>
>>>
>>>> Cheers,
>>>>
>>>> Peter.
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
I'm also figuring you might have some wise defaults that people could add to
for constructing a filter/matchset.
Something like:
DefaultEntrys.add(...).add(....)
DefaultEntrys probably includes something like ServiceInfo, Name and such -
all stock options in the platform...
On 5 February 2011 10:28, Peter Firmstone <ji...@zeus.net.au> wrote:
> Ok, good reasoning, we can keep the Entry's explicit, in the call.
>
> So we make the Entry's the client's interested in, the only Entry's that'll
> be unmarshalled, those and the ServiceID.
>
>
> Cheers,
>
> Peter.
>
> Dan Creswell wrote:
>
>> ...
>>
>> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>>
>>
>>
>>> Dan Creswell wrote:
>>>
>>>
>>>
>>>> "ServiceClasspathSubItem is intended for client side filtering of lookup
>>>> * service results prior to clients using a service, the lookup service
>>>> * that implements this class, implements #getServiceItem(), so clients
>>>> * can obtain a complete ServiceItem when required after filtering."
>>>>
>>>> I'm still wondering if it wouldn't be better for a client to send a list
>>>> of
>>>> Entry's it's interested in seeing, separate from the set for matching to
>>>> the
>>>> Registrar. The Registrar can then return ServiceItems for the matches
>>>> and
>>>> pre-filter the Entry's per item. Especially given:
>>>>
>>>> "Some fields in ServiceClasspathSubItem may be null, fields in Entry's
>>>> may
>>>> * be null or even the service reference may be null, these fields would
>>>> be
>>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>>> downloaded
>>>> * code or a remote codebase."
>>>>
>>>> I think, if we do the filtering as I suggest, much of the comment re:
>>>> nulls
>>>> above still applies in implementation but ultimately, the client will
>>>> pick
>>>> Entry's for which it has the classpath such that it always deals in
>>>> complete
>>>> Entry's and can have a level of predictability in respect of what is or
>>>> is
>>>> not null. This might save clients having to do endless null checks etc
>>>> that
>>>> can be a rich source of bugs and ugly code.
>>>>
>>>> We might need the filter list to include specific subclasses as well....
>>>>
>>>>
>>>>
>>>>
>>>>
>>> Hmm, null is a problem, we could still have fields missing subclass
>>> classes, which might prevent a subclass from unmarshalling.
>>>
>>>
>>>
>>>
>> Yeah, which is why I'm tempted to have the client be explicit about which
>> Entry's (and that would include subclasses of those Entry's it can
>> tolerate). In this way the client can provide high-level explicit guidance
>> as to what's right. No need for code to try and be clever and guess the
>> client intent which is always ugly.
>>
>> Many times I suspect the Entry set used for matching will be the same as
>> the
>> filter set, probably can provide a nice method signature to help that.
>>
>> Is there a way we can catch a class not found exception or similar and
>> still
>>
>>
>>> get the state of the superclass, or would this violate polymorphism,
>>> method
>>> overrides etc?
>>>
>>>
>>>
>>>
>> Probably but again this is building clever code to try and compensate.
>> It's
>> the same as writing all the null handling if you will albeit hidden inside
>> the River libraries.
>>
>>
>>
>>
>>> I guess the likelihood of having null values is reduced, although not
>>> eliminated.
>>>
>>>
>>>
>>>
>> Quite.
>>
>>
>>
>>
>>> If we compact the final array of Entry's so null entry's are removed, the
>>> client only needs to find the Entry's it's interested in, likely ignoring
>>> the others anyway.
>>>
>>>
>>>
>>
>> Sure but then the client has to explicitly construct filter code, albeit
>> clean of null checks to go through the list of Entry's to find what it's
>> interested in. Unless we return a HashMap(EntryClass.getName,
>> EntryClass.instance) to make that easier. Even so, you're still returning
>> a
>> bunch of Entry's only some of which may be interesting to the client....
>>
>>
>>
>>
>>> So the client needs to ensure the Entry's are resolvable from the
>>> classpath.
>>>
>>>
>>>
>>>
>> Absolutely - and the fact that it must means it can thus construct a
>> proper
>> filter list of Entrys of interest.
>>
>>
>>
>>
>>> I have thought about the case where a proxy uses the lookup service and
>>> has
>>> Entry's in it's proxy classloader, but this could be subject to security
>>> issues, where two services with different Subject's end up sharing state.
>>>
>>> We might also consider only including Entry's that don't have null field
>>> values, this puts the impetus on the implementer to consider the Entry
>>> field
>>> classes.
>>>
>>>
>>>
>>
>> Again, I think we're venturing into attempting to imply intent by
>> examining
>> null fields. If the implementer makes a mistake in their analysis they end
>> up with unexpected results come lookup. Personally I don't like this sort
>> of
>> thing, I like explicit methods to guide an implementer and eliminate
>> opportunities for these kinds of confusion.
>>
>> That last bit is really why I'm down on trying to solve all these problems
>> (including the bandwidth ones) with clever management of
>> class-downloading,
>> reflection and such. It's implicit, makes assumptions about usage that are
>> difficult for users to account for. It also leads to complicated, brittle
>> code with many an opportunity for dark-corners/unhandled edge cases that
>> cause confusion and are difficult to identify and fix for River
>> implementers
>> and users.
>>
>>
>>
>>
>>> Cheers,
>>>
>>> Peter.
>>>
>>>
>>>
>>
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Ok, good reasoning, we can keep the Entry's explicit, in the call.
So we make the Entry's the client's interested in, the only Entry's
that'll be unmarshalled, those and the ServiceID.
Cheers,
Peter.
Dan Creswell wrote:
> ...
>
> On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> Dan Creswell wrote:
>>
>>
>>> "ServiceClasspathSubItem is intended for client side filtering of lookup
>>> * service results prior to clients using a service, the lookup service
>>> * that implements this class, implements #getServiceItem(), so clients
>>> * can obtain a complete ServiceItem when required after filtering."
>>>
>>> I'm still wondering if it wouldn't be better for a client to send a list
>>> of
>>> Entry's it's interested in seeing, separate from the set for matching to
>>> the
>>> Registrar. The Registrar can then return ServiceItems for the matches and
>>> pre-filter the Entry's per item. Especially given:
>>>
>>> "Some fields in ServiceClasspathSubItem may be null, fields in Entry's may
>>> * be null or even the service reference may be null, these fields would be
>>> * non-null in a ServiceItem that resolves classes from dynamicly
>>> downloaded
>>> * code or a remote codebase."
>>>
>>> I think, if we do the filtering as I suggest, much of the comment re:
>>> nulls
>>> above still applies in implementation but ultimately, the client will pick
>>> Entry's for which it has the classpath such that it always deals in
>>> complete
>>> Entry's and can have a level of predictability in respect of what is or is
>>> not null. This might save clients having to do endless null checks etc
>>> that
>>> can be a rich source of bugs and ugly code.
>>>
>>> We might need the filter list to include specific subclasses as well....
>>>
>>>
>>>
>>>
>> Hmm, null is a problem, we could still have fields missing subclass
>> classes, which might prevent a subclass from unmarshalling.
>>
>>
>>
> Yeah, which is why I'm tempted to have the client be explicit about which
> Entry's (and that would include subclasses of those Entry's it can
> tolerate). In this way the client can provide high-level explicit guidance
> as to what's right. No need for code to try and be clever and guess the
> client intent which is always ugly.
>
> Many times I suspect the Entry set used for matching will be the same as the
> filter set, probably can provide a nice method signature to help that.
>
> Is there a way we can catch a class not found exception or similar and still
>
>> get the state of the superclass, or would this violate polymorphism, method
>> overrides etc?
>>
>>
>>
> Probably but again this is building clever code to try and compensate. It's
> the same as writing all the null handling if you will albeit hidden inside
> the River libraries.
>
>
>
>> I guess the likelihood of having null values is reduced, although not
>> eliminated.
>>
>>
>>
> Quite.
>
>
>
>> If we compact the final array of Entry's so null entry's are removed, the
>> client only needs to find the Entry's it's interested in, likely ignoring
>> the others anyway.
>>
>>
>
> Sure but then the client has to explicitly construct filter code, albeit
> clean of null checks to go through the list of Entry's to find what it's
> interested in. Unless we return a HashMap(EntryClass.getName,
> EntryClass.instance) to make that easier. Even so, you're still returning a
> bunch of Entry's only some of which may be interesting to the client....
>
>
>
>> So the client needs to ensure the Entry's are resolvable from the
>> classpath.
>>
>>
>>
> Absolutely - and the fact that it must means it can thus construct a proper
> filter list of Entrys of interest.
>
>
>
>> I have thought about the case where a proxy uses the lookup service and has
>> Entry's in it's proxy classloader, but this could be subject to security
>> issues, where two services with different Subject's end up sharing state.
>>
>> We might also consider only including Entry's that don't have null field
>> values, this puts the impetus on the implementer to consider the Entry field
>> classes.
>>
>>
>
> Again, I think we're venturing into attempting to imply intent by examining
> null fields. If the implementer makes a mistake in their analysis they end
> up with unexpected results come lookup. Personally I don't like this sort of
> thing, I like explicit methods to guide an implementer and eliminate
> opportunities for these kinds of confusion.
>
> That last bit is really why I'm down on trying to solve all these problems
> (including the bandwidth ones) with clever management of class-downloading,
> reflection and such. It's implicit, makes assumptions about usage that are
> difficult for users to account for. It also leads to complicated, brittle
> code with many an opportunity for dark-corners/unhandled edge cases that
> cause confusion and are difficult to identify and fix for River implementers
> and users.
>
>
>
>> Cheers,
>>
>> Peter.
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
How's this?
/*
* 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.river.api.lookup;
import java.io.IOException;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.lookup.ServiceItem;
import org.apache.river.api.util.ResultStream;
/**
* Defines an extension interface to the lookup service, for use on
large or
* global networks such as the internet or low bandwidth networks.
* The interface is not a remote interface; each implementation of the
* lookup service exports proxy objects that implement the
* StreamServiceRegistrar interface local to the client, using an
* implementation-specific protocol to communicate with the actual remote
* server. All of the proxy methods obey normal RMI remote interface
* semantics except where explicitly noted. Two proxy objects are equal if
* they are proxies for the same lookup service. Every method invocation
* (on both StreamServiceRegistrar and ServiceRegistration) is atomic with
* respect to other invocations.
*
* The StreamServiceRegistrar is intended to perform the same function
* as the ServiceRegistrar, but with the ability to return results as a
* stream, so memory consumption is minimised at the client and network
* communication is minimised between the client and lookup service server.
*
* All clients utilising ServiceRegistrar, should switch to the
* StreamServiceRegistrar.
*
* @see ServiceRegistrar
* @see PortableServiceRegistrar
* @see ServiceRegistration
* @author Peter Firmstone
* @since 2.2.0
*/
public interface StreamServiceRegistrar extends ServiceRegistrar{
/**
* Returns a ResultStream that provides access to
ServiceClasspathSubItem
* instances. The ResultStream terminates with a null value. The
result
* stream may be infinite, or limited by an integer limit value.
*
* A ServiceClasspathSubItem implementation instance is a
ServiceItem that
* contains only Objects that are resolvable on the local classpath,
* this is useful for clients to perform filtering before requiring a
* download of the actual ServiceItem.
*
* The ResultStream should be closed once the desired service has been
* found, or services have been processed.
*
* @param tmpl template to match
* specified template
*
* @param maxBatchSize held locally, larger batch sizes reduce network
* traffic, but may delay processing locally depending on
implementation.
* @param limit - Zero for infinite, otherwise limits the number of
matching
* results.
* @return ResultStream containing ServiceItem's
* @throws java.io.IOException
* @see ServiceItem
* @see ServiceClasspathSubItem
* @see ResultStream
* @see ServiceResultStreamFilter
* @see ResultStreamUnmarshaller
* @since 2.2.0
*/
ResultStream lookup(ServiceTemplate tmpl, Class[] entryClasses,
int maxBatchSize, int limit) throws IOException;
}
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
...
On 5 February 2011 09:48, Peter Firmstone <ji...@zeus.net.au> wrote:
> Dan Creswell wrote:
>
>> "ServiceClasspathSubItem is intended for client side filtering of lookup
>> * service results prior to clients using a service, the lookup service
>> * that implements this class, implements #getServiceItem(), so clients
>> * can obtain a complete ServiceItem when required after filtering."
>>
>> I'm still wondering if it wouldn't be better for a client to send a list
>> of
>> Entry's it's interested in seeing, separate from the set for matching to
>> the
>> Registrar. The Registrar can then return ServiceItems for the matches and
>> pre-filter the Entry's per item. Especially given:
>>
>> "Some fields in ServiceClasspathSubItem may be null, fields in Entry's may
>> * be null or even the service reference may be null, these fields would be
>> * non-null in a ServiceItem that resolves classes from dynamicly
>> downloaded
>> * code or a remote codebase."
>>
>> I think, if we do the filtering as I suggest, much of the comment re:
>> nulls
>> above still applies in implementation but ultimately, the client will pick
>> Entry's for which it has the classpath such that it always deals in
>> complete
>> Entry's and can have a level of predictability in respect of what is or is
>> not null. This might save clients having to do endless null checks etc
>> that
>> can be a rich source of bugs and ugly code.
>>
>> We might need the filter list to include specific subclasses as well....
>>
>>
>>
> Hmm, null is a problem, we could still have fields missing subclass
> classes, which might prevent a subclass from unmarshalling.
>
>
Yeah, which is why I'm tempted to have the client be explicit about which
Entry's (and that would include subclasses of those Entry's it can
tolerate). In this way the client can provide high-level explicit guidance
as to what's right. No need for code to try and be clever and guess the
client intent which is always ugly.
Many times I suspect the Entry set used for matching will be the same as the
filter set, probably can provide a nice method signature to help that.
Is there a way we can catch a class not found exception or similar and still
> get the state of the superclass, or would this violate polymorphism, method
> overrides etc?
>
>
Probably but again this is building clever code to try and compensate. It's
the same as writing all the null handling if you will albeit hidden inside
the River libraries.
> I guess the likelihood of having null values is reduced, although not
> eliminated.
>
>
Quite.
> If we compact the final array of Entry's so null entry's are removed, the
> client only needs to find the Entry's it's interested in, likely ignoring
> the others anyway.
>
Sure but then the client has to explicitly construct filter code, albeit
clean of null checks to go through the list of Entry's to find what it's
interested in. Unless we return a HashMap(EntryClass.getName,
EntryClass.instance) to make that easier. Even so, you're still returning a
bunch of Entry's only some of which may be interesting to the client....
>
> So the client needs to ensure the Entry's are resolvable from the
> classpath.
>
>
Absolutely - and the fact that it must means it can thus construct a proper
filter list of Entrys of interest.
> I have thought about the case where a proxy uses the lookup service and has
> Entry's in it's proxy classloader, but this could be subject to security
> issues, where two services with different Subject's end up sharing state.
>
> We might also consider only including Entry's that don't have null field
> values, this puts the impetus on the implementer to consider the Entry field
> classes.
>
Again, I think we're venturing into attempting to imply intent by examining
null fields. If the implementer makes a mistake in their analysis they end
up with unexpected results come lookup. Personally I don't like this sort of
thing, I like explicit methods to guide an implementer and eliminate
opportunities for these kinds of confusion.
That last bit is really why I'm down on trying to solve all these problems
(including the bandwidth ones) with clever management of class-downloading,
reflection and such. It's implicit, makes assumptions about usage that are
difficult for users to account for. It also leads to complicated, brittle
code with many an opportunity for dark-corners/unhandled edge cases that
cause confusion and are difficult to identify and fix for River implementers
and users.
>
> Cheers,
>
> Peter.
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
> "ServiceClasspathSubItem is intended for client side filtering of lookup
> * service results prior to clients using a service, the lookup service
> * that implements this class, implements #getServiceItem(), so clients
> * can obtain a complete ServiceItem when required after filtering."
>
> I'm still wondering if it wouldn't be better for a client to send a list of
> Entry's it's interested in seeing, separate from the set for matching to the
> Registrar. The Registrar can then return ServiceItems for the matches and
> pre-filter the Entry's per item. Especially given:
>
> "Some fields in ServiceClasspathSubItem may be null, fields in Entry's may
> * be null or even the service reference may be null, these fields would be
> * non-null in a ServiceItem that resolves classes from dynamicly downloaded
> * code or a remote codebase."
>
> I think, if we do the filtering as I suggest, much of the comment re: nulls
> above still applies in implementation but ultimately, the client will pick
> Entry's for which it has the classpath such that it always deals in complete
> Entry's and can have a level of predictability in respect of what is or is
> not null. This might save clients having to do endless null checks etc that
> can be a rich source of bugs and ugly code.
>
> We might need the filter list to include specific subclasses as well....
>
>
Hmm, null is a problem, we could still have fields missing subclass
classes, which might prevent a subclass from unmarshalling.
Is there a way we can catch a class not found exception or similar and
still get the state of the superclass, or would this violate
polymorphism, method overrides etc?
I guess the likelihood of having null values is reduced, although not
eliminated.
If we compact the final array of Entry's so null entry's are removed,
the client only needs to find the Entry's it's interested in, likely
ignoring the others anyway.
So the client needs to ensure the Entry's are resolvable from the classpath.
I have thought about the case where a proxy uses the lookup service and
has Entry's in it's proxy classloader, but this could be subject to
security issues, where two services with different Subject's end up
sharing state.
We might also consider only including Entry's that don't have null field
values, this puts the impetus on the implementer to consider the Entry
field classes.
Cheers,
Peter.
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
"ServiceClasspathSubItem is intended for client side filtering of lookup
* service results prior to clients using a service, the lookup service
* that implements this class, implements #getServiceItem(), so clients
* can obtain a complete ServiceItem when required after filtering."
I'm still wondering if it wouldn't be better for a client to send a list of
Entry's it's interested in seeing, separate from the set for matching to the
Registrar. The Registrar can then return ServiceItems for the matches and
pre-filter the Entry's per item. Especially given:
"Some fields in ServiceClasspathSubItem may be null, fields in Entry's may
* be null or even the service reference may be null, these fields would be
* non-null in a ServiceItem that resolves classes from dynamicly downloaded
* code or a remote codebase."
I think, if we do the filtering as I suggest, much of the comment re: nulls
above still applies in implementation but ultimately, the client will pick
Entry's for which it has the classpath such that it always deals in complete
Entry's and can have a level of predictability in respect of what is or is
not null. This might save clients having to do endless null checks etc that
can be a rich source of bugs and ugly code.
We might need the filter list to include specific subclasses as well....
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
By only using the classpath to resolve classes, the caller no longer
needs to provide Entry classes to StreamServiceRegistrar either.
Revised class below, the javadoc, class and method name have been changed.
/*
* 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.river.api.lookup;
import java.net.URI;
import java.security.CodeSource;
import net.jini.core.entry.Entry;
import net.jini.core.lookup.ServiceID;
import net.jini.core.lookup.ServiceItem;
/**
* ServiceClasspathSubItem is intended for client side filtering of lookup
* service results prior to clients using a service, the lookup service
* that implements this class, implements #getServiceItem(), so clients
* can obtain a complete ServiceItem when required after filtering.
*
* ServiceClasspathSubItem extends ServiceItem and can be used anywhere a
* ServiceItem is required for querying or inspecting Entry fields that are
* resolvable from the local classpath. If dynamically downloaded code is
* required, Remote or Serializable object references are not resolved,
* instead, such fields are set to null to avoid codebase download.
*
* ServiceClasspathSubItem inherits all fields from ServiceItem.
*
* Some fields in ServiceClasspathSubItem may be null, fields in Entry's
may
* be null or even the service reference may be null, these fields would be
* non-null in a ServiceItem that resolves classes from dynamicly
downloaded
* code or a remote codebase.
*
* The serviceID field shall be non-null always.
*
* ServiceItem's toString() method will return a different result for
* ServiceClasspathSubItem instances.
*
* When required, a new ServiceItem that is unmarshalled
* using remote codebases and dynamicly downloaded code can be obtained
* by calling #getServiceItem().
*
* @author Peter Firmstone.
*/
public abstract class ServiceClasspathSubItem extends ServiceItem{
private static final long SerialVersionUID = 1L;
protected ServiceClasspathSubItem(ServiceID id, Entry[]
unmarshalledEntries){
super(id, (Object) null, unmarshalledEntries);
}
/* Default constructor for serializable sub class.
*/
protected ServiceClasspathSubItem(){
super(null, null, null);
}
/**
* Using remote and local code as required getServiceItem returns a
* new ServiceItem.
*
* The returned ServiceItem must not be an instance of this class.
*
* @return ServiceItem, totally unmarshalled, using remote codebase
resources
* in addition to any local classpath or resources.
*/
public abstract ServiceItem getServiceItem();
}
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
It is a container object, it extends ServiceItem, it's essentially has
identical state (or a subset of it), but unlike a ServiceItem, no
attempt has been made to use or download remote codebases, only the
classpath is used to resolve and unmarshall any objects contained in the
ServiceItem. Object references are set to null if their classes cannot
be resolved locally, including the proxy, any Entry's or Entry fields.
A single method is provided to resolve the ServiceItem using remote
codebases in addition to the classpath, this method returns a new
ServiceItem.
The intent of the class is to provide access to Entry's for complex
queries, (<>|&) performed locally, without downloading any codebases.
Once the client has found a suitable service it can be retrieved after a
codebase download and unmarshalling.
The implementer may also decide to avoid downloading the marshalled
state of the service proxy, in addition to its codebase.
Other ideas:
PseudoServiceItem
PartialServiceItem
ServiceItemLocalSubset
Cheers,
Peter.
MICHAEL MCGRADY wrote:
> Could you state in a sentence what the class does? Then we can all suggest possible names?
>
> MG
>
>
> On Feb 3, 2011, at 1:40 PM, Peter Firmstone wrote:
>
>
>> Or one of these?
>>
>> ClasspathFencedServiceItem
>>
>> ClaspathBoundServiceItem
>>
>> ClasspathConstrainedServiceItem
>>
>> Dan Creswell wrote:
>>
>>> Thing is the ServiceItem is not the thing being resolved....
>>>
>>> On 3 February 2011 09:59, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>
>>>
>>>
>>>> How about LocallyResolvedServiceItem?
>>>>
>>>>
>>>> Dan Creswell wrote:
>>>>
>>>>
>>>>
>>>>> Sure, the method does indeed unmarshall but within specific constraints
>>>>> and
>>>>> those constraints are defined by the enclosing class (an instance of
>>>>> ServiceItem in this case).
>>>>>
>>>>> So I'm thinking we're really talking about is a ServiceItem that pulls
>>>>> from
>>>>> classpath so maybe LocallyResolvingServiceItem (not entirely keen on that
>>>>> but explains what's happening).
>>>>>
>>>>> On some level there's a bit of me that screams we have a broken design if
>>>>> we
>>>>> can't get decent names.....
>>>>>
>>>>> On 3 February 2011 09:10, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> Dan Creswell wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>> "In summary MarshalledServiceItem is a class that only resolves local
>>>>>>> code.
>>>>>>> Interestingly MarshalledServiceItem, might not be an appropriate name,
>>>>>>> perhaps LocalServiceItem to indicate that only local code is utilised,
>>>>>>> on
>>>>>>> this reasoning, I can't see any objection to reflective proxy's being
>>>>>>> non
>>>>>>> null either."
>>>>>>>
>>>>>>> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
>>>>>>> what's going on.....
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> The method unmarshall, sort of makes sense, can you think of a better
>>>>>> name?
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>
> Michael McGrady
> Chief Architect
> Topia Technology, Inc.
> Cel 1.253.720.3365
> Work 1.253.572.9712 extension 2037
> mmcgrady@topiatechnology.com
>
>
>
>
>
Re: MarshalledServiceItem
Posted by MICHAEL MCGRADY <mm...@topiatechnology.com>.
Could you state in a sentence what the class does? Then we can all suggest possible names?
MG
On Feb 3, 2011, at 1:40 PM, Peter Firmstone wrote:
> Or one of these?
>
> ClasspathFencedServiceItem
>
> ClaspathBoundServiceItem
>
> ClasspathConstrainedServiceItem
>
> Dan Creswell wrote:
>> Thing is the ServiceItem is not the thing being resolved....
>>
>> On 3 February 2011 09:59, Peter Firmstone <ji...@zeus.net.au> wrote:
>>
>>
>>> How about LocallyResolvedServiceItem?
>>>
>>>
>>> Dan Creswell wrote:
>>>
>>>
>>>> Sure, the method does indeed unmarshall but within specific constraints
>>>> and
>>>> those constraints are defined by the enclosing class (an instance of
>>>> ServiceItem in this case).
>>>>
>>>> So I'm thinking we're really talking about is a ServiceItem that pulls
>>>> from
>>>> classpath so maybe LocallyResolvingServiceItem (not entirely keen on that
>>>> but explains what's happening).
>>>>
>>>> On some level there's a bit of me that screams we have a broken design if
>>>> we
>>>> can't get decent names.....
>>>>
>>>> On 3 February 2011 09:10, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> Dan Creswell wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> "In summary MarshalledServiceItem is a class that only resolves local
>>>>>> code.
>>>>>> Interestingly MarshalledServiceItem, might not be an appropriate name,
>>>>>> perhaps LocalServiceItem to indicate that only local code is utilised,
>>>>>> on
>>>>>> this reasoning, I can't see any objection to reflective proxy's being
>>>>>> non
>>>>>> null either."
>>>>>>
>>>>>> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
>>>>>> what's going on.....
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> The method unmarshall, sort of makes sense, can you think of a better
>>>>> name?
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>>
>
Michael McGrady
Chief Architect
Topia Technology, Inc.
Cel 1.253.720.3365
Work 1.253.572.9712 extension 2037
mmcgrady@topiatechnology.com
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Or one of these?
ClasspathFencedServiceItem
ClaspathBoundServiceItem
ClasspathConstrainedServiceItem
Dan Creswell wrote:
> Thing is the ServiceItem is not the thing being resolved....
>
> On 3 February 2011 09:59, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> How about LocallyResolvedServiceItem?
>>
>>
>> Dan Creswell wrote:
>>
>>
>>> Sure, the method does indeed unmarshall but within specific constraints
>>> and
>>> those constraints are defined by the enclosing class (an instance of
>>> ServiceItem in this case).
>>>
>>> So I'm thinking we're really talking about is a ServiceItem that pulls
>>> from
>>> classpath so maybe LocallyResolvingServiceItem (not entirely keen on that
>>> but explains what's happening).
>>>
>>> On some level there's a bit of me that screams we have a broken design if
>>> we
>>> can't get decent names.....
>>>
>>> On 3 February 2011 09:10, Peter Firmstone <ji...@zeus.net.au> wrote:
>>>
>>>
>>>
>>>
>>>> Dan Creswell wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> "In summary MarshalledServiceItem is a class that only resolves local
>>>>> code.
>>>>> Interestingly MarshalledServiceItem, might not be an appropriate name,
>>>>> perhaps LocalServiceItem to indicate that only local code is utilised,
>>>>> on
>>>>> this reasoning, I can't see any objection to reflective proxy's being
>>>>> non
>>>>> null either."
>>>>>
>>>>> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
>>>>> what's going on.....
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>> The method unmarshall, sort of makes sense, can you think of a better
>>>> name?
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>
>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
Thing is the ServiceItem is not the thing being resolved....
On 3 February 2011 09:59, Peter Firmstone <ji...@zeus.net.au> wrote:
> How about LocallyResolvedServiceItem?
>
>
> Dan Creswell wrote:
>
>> Sure, the method does indeed unmarshall but within specific constraints
>> and
>> those constraints are defined by the enclosing class (an instance of
>> ServiceItem in this case).
>>
>> So I'm thinking we're really talking about is a ServiceItem that pulls
>> from
>> classpath so maybe LocallyResolvingServiceItem (not entirely keen on that
>> but explains what's happening).
>>
>> On some level there's a bit of me that screams we have a broken design if
>> we
>> can't get decent names.....
>>
>> On 3 February 2011 09:10, Peter Firmstone <ji...@zeus.net.au> wrote:
>>
>>
>>
>>> Dan Creswell wrote:
>>>
>>>
>>>
>>>> "In summary MarshalledServiceItem is a class that only resolves local
>>>> code.
>>>> Interestingly MarshalledServiceItem, might not be an appropriate name,
>>>> perhaps LocalServiceItem to indicate that only local code is utilised,
>>>> on
>>>> this reasoning, I can't see any objection to reflective proxy's being
>>>> non
>>>> null either."
>>>>
>>>> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
>>>> what's going on.....
>>>>
>>>>
>>>>
>>>>
>>>>
>>> The method unmarshall, sort of makes sense, can you think of a better
>>> name?
>>>
>>>
>>>
>>
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
How about LocallyResolvedServiceItem?
Dan Creswell wrote:
> Sure, the method does indeed unmarshall but within specific constraints and
> those constraints are defined by the enclosing class (an instance of
> ServiceItem in this case).
>
> So I'm thinking we're really talking about is a ServiceItem that pulls from
> classpath so maybe LocallyResolvingServiceItem (not entirely keen on that
> but explains what's happening).
>
> On some level there's a bit of me that screams we have a broken design if we
> can't get decent names.....
>
> On 3 February 2011 09:10, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> Dan Creswell wrote:
>>
>>
>>> "In summary MarshalledServiceItem is a class that only resolves local
>>> code.
>>> Interestingly MarshalledServiceItem, might not be an appropriate name,
>>> perhaps LocalServiceItem to indicate that only local code is utilised, on
>>> this reasoning, I can't see any objection to reflective proxy's being non
>>> null either."
>>>
>>> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
>>> what's going on.....
>>>
>>>
>>>
>>>
>> The method unmarshall, sort of makes sense, can you think of a better name?
>>
>>
>
>
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
Sure, the method does indeed unmarshall but within specific constraints and
those constraints are defined by the enclosing class (an instance of
ServiceItem in this case).
So I'm thinking we're really talking about is a ServiceItem that pulls from
classpath so maybe LocallyResolvingServiceItem (not entirely keen on that
but explains what's happening).
On some level there's a bit of me that screams we have a broken design if we
can't get decent names.....
On 3 February 2011 09:10, Peter Firmstone <ji...@zeus.net.au> wrote:
> Dan Creswell wrote:
>
>> "In summary MarshalledServiceItem is a class that only resolves local
>> code.
>> Interestingly MarshalledServiceItem, might not be an appropriate name,
>> perhaps LocalServiceItem to indicate that only local code is utilised, on
>> this reasoning, I can't see any objection to reflective proxy's being non
>> null either."
>>
>> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
>> what's going on.....
>>
>>
>>
> The method unmarshall, sort of makes sense, can you think of a better name?
>
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Dan Creswell wrote:
> "In summary MarshalledServiceItem is a class that only resolves local code.
> Interestingly MarshalledServiceItem, might not be an appropriate name,
> perhaps LocalServiceItem to indicate that only local code is utilised, on
> this reasoning, I can't see any objection to reflective proxy's being non
> null either."
>
> Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
> what's going on.....
>
>
The method unmarshall, sort of makes sense, can you think of a better name?
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
"In summary MarshalledServiceItem is a class that only resolves local code.
Interestingly MarshalledServiceItem, might not be an appropriate name,
perhaps LocalServiceItem to indicate that only local code is utilised, on
this reasoning, I can't see any objection to reflective proxy's being non
null either."
Indeed, the name MarshalledServiceItem is completely "out-of-whack" with
what's going on.....
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Gregg Wonderly wrote:
> On 2/2/2011 6:15 PM, Peter Firmstone wrote:
>> Michał Kłeczek wrote:
>>> On Thu, Feb 3, 2011 at 12:47 AM, Peter Firmstone <ji...@zeus.net.au>
>>> wrote:
>>>> 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.
>>>
>>> The problem with PREFERRED.LIST is more fundamental - for example
>>> every RemoteEvent producer is forced to download a jar file just to
>>> check that RemoteEventListener is not preferred. As such the issue
>>> cannot be solved at the LUS API level.
>>>
>>> Michal
>>>
>> Yes there are more fundamental problems with preferred classes,
>> ClassLoading etc
>> that remain to be solved.
>>
>> But rather than fix it on this occassion, MarshalledServiceItem is
>> just resolved
>> with local classes and preferred class loading is not used or needed.
>> When the
>> client unmarshalls the MarshalledServiceItem, then preferred class
>> loading will
>> be used and jar files downloaded. MarshalledServiceItem can provide a
>> significant amount of information by just resolving using local
>> classes, which
>> the client can utilise.
>>
>> In the long term I see it like this:
>>
>> We need to look into dependency inversion to remove implementation
>> classes from
>> the platform and application class loader, which is the problem that
>> preferred
>> class loading addresses.
>>
>> If implementation classes are not present in the platform, you don't
>> need
>> preferred classes for proxys to have their own copy of an
>> implementation class,
>> because those classes will be resolved by standard java classloading
>> rules in
>> the proxy class loader.
>
> One thing to note, is that I have used PreferredClassLoader to fix
> bugs by taking common classes that I use in GUI constructions that
> would have been resolved in the parent loader and switching them to be
> preferred so that I'd get the fixed version. I am not sure that there
> is a perfect "split" of implementation vs platform. Sometimes
> implementation can be a mini-platform of sorts. Just
> repackaging/rearranging jars is not a singular fix, always.
>
> Gregg Wonderly
>
Based on our discussions, I've made changes to MarshalledServiceItem and
StreamServiceRegistrar (see below), I have reduced
StreamServiceRegistrar to a single lookup method, my reasoning is, the
other methods, based on those already existing in ServiceRegistrar, are
there primarily to build a suitable ServiceTemplate to avoid downloading
proxy's, however since we're providing an alternate means
(MarshalledServiceItem) to avoid or delay downloading proxy's those 3
methods are less relevant.
So what we have is a new lookup service interface for the internet, that
extends ServiceRegistrar and provides one new method, with means to
provide Entry's that resolve locally for querying without downloading
any jar files, until such time as the client wants to, this could also
avoid downloading the MarshalledInstance of the proxy until
unmarshalling is performed.
In summary MarshalledServiceItem is a class that only resolves local
code. Interestingly MarshalledServiceItem, might not be an appropriate
name, perhaps LocalServiceItem to indicate that only local code is
utilised, on this reasoning, I can't see any objection to reflective
proxy's being non null either.
What ramifications does this have for proxy trust if we already trust
the lookup service?
MarshalledServiceItem's single method, unmarshall, is not declared to
throw an IOException or remote exception, for the case where a
ServiceItem cannot be unmarshalled, fields are set to null, as is the
current practice for ServiceItem. Does anyone think this method should
declare any exceptions?
Cheers,
Peter.
/*
* 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.river.api.lookup;
import java.net.URI;
import java.security.CodeSource;
import net.jini.core.entry.Entry;
import net.jini.core.lookup.ServiceID;
import net.jini.core.lookup.ServiceItem;
/**
* MarshalledServiceItem extends ServiceItem and can be used anywhere a
* ServiceItem can. A MarshalledServiceItem implementation instance
* contains the marshalled form of a Service and it's Entry's,
* the corresponding superclass ServiceItem however contains null values
* for the service and can exclude any Entry's, however where Entry
* classes already exist at the client, that they be unmarshalled.
*
* The ServiceID shall be in unmarshalled form always in the ServiceItem
super class.
*
* Since the ServiceItem.service is null, use of this class in existing
software
* will not return the service, however it will not break that software as
* ServiceItem's contract is to set service or Entry's to null when they
cannot
* be unmarshalled.
*
* ServiceItem's toString() method will return a different result for
* MarshalledServiceItem instances.
*
* If required, a new ServiceItem that is fully unmarshalled
* can be constructed from this class's methods and ServiceID.
*
* @author Peter Firmstone.
*/
public abstract class MarshalledServiceItem extends ServiceItem{
private static final long SerialVersionUID = 1L;
protected MarshalledServiceItem(ServiceID id, Entry[]
unmarshalledEntries){
super(id, (Object) null, unmarshalledEntries);
}
/* Default constructor for serializable sub class.
*/
protected MarshalledServiceItem(){
super(null, null, null);
}
/**
* Unmarshall the ServiceItem. The returned ServiceItem may have a
null service
* or entries , if unmarshalling is unsuccessful.
*
* @return ServiceItem, totally unmarshalled.
*/
public abstract ServiceItem unmarshall();
}
/*
* 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.river.api.lookup;
import java.io.IOException;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.lookup.ServiceItem;
import org.apache.river.api.util.ResultStream;
/**
* Defines the interface to the lookup service. The interface is not a
* remote interface; each implementation of the lookup service exports
* proxy objects that implement the StreamServiceRegistrar interface
local to
* the client, using an implementation-specific protocol to communicate
* with the actual remote server. All of the proxy methods obey normal
* RMI remote interface semantics except where explicitly noted. Two
* proxy objects are equal if they are proxies for the same lookup service.
* Every method invocation (on both StreamServiceRegistrar and
ServiceRegistration)
* is atomic with respect to other invocations.
*
* The StreamServiceRegistrar is intended to perform the same function
* as the ServiceRegistrar, but with the ability to return results as a
* stream, so memory consumption can be minimised at the client.
*
* All clients utilising ServiceRegistrar, should switch to the
* StreamServiceRegistrar.
*
* @see ServiceRegistrar
* @see PortableServiceRegistrar
* @see ServiceRegistration
* @author Peter Firmstone
* @since 2.2.0
*/
public interface StreamServiceRegistrar extends ServiceRegistrar{
/**
* Returns a ResultStream that provides access to MarshalledServiceItem
* instances. The ResultStream terminates with a null value. The
result
* stream may be infinite.
*
* MarshalledServiceItem extends ServiceItem and can be used anywhere a
* ServiceItem can. A MarshalledServiceItem implementation instance
* contains the marshalled form of a Service and it's Entry's,
* the corresponding superclass ServiceItem however contains null values
* for the service and excludes any Entry's that are not
specifically requested
* unmarshalled by this method. The ServiceID will be unmarshalled
always.
*
* This method is designed to allow the caller to control exactly what
* is unmarshalled and when, it allows unmarshalling of specific entries
* that the caller may wish to utilise for filtering. It is
* designed to allow both the caller and the implementer to deal
with very
* large result sets in an incremental fashion.
*
* It is absolutely essential that the caller closes and deletes any
references to
* the returned result stream as soon as it is no longer requried.
*
* @param tmpl template to match
* specified template
* @param unmarshalledEntries only Entry's with these classes will be in
* unmarshalled form.
* @param maxBatchSize Allows the caller to limit the number of results
* held locally, larger batch sizes reduce network traffic, but may
delay
* processing locally depending on implementation.
* @return ResultStream containing ServiceItem's
* @throws java.rmi.RemoteException
* @see MarshalledServiceItem
* @see ServiceItem
* @see ResultStream
* @see ServiceResultStreamFilter
* @see ResultStreamUnmarshaller
* @since 2.2.0
*/
ResultStream lookup(ServiceTemplate tmpl,
Class[] unmarshalledEntries, int maxBatchSize) throws IOException;
}
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
On 2/2/2011 6:15 PM, Peter Firmstone wrote:
> Michał Kłeczek wrote:
>> On Thu, Feb 3, 2011 at 12:47 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
>>> 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.
>>
>> The problem with PREFERRED.LIST is more fundamental - for example
>> every RemoteEvent producer is forced to download a jar file just to
>> check that RemoteEventListener is not preferred. As such the issue
>> cannot be solved at the LUS API level.
>>
>> Michal
>>
> Yes there are more fundamental problems with preferred classes, ClassLoading etc
> that remain to be solved.
>
> But rather than fix it on this occassion, MarshalledServiceItem is just resolved
> with local classes and preferred class loading is not used or needed. When the
> client unmarshalls the MarshalledServiceItem, then preferred class loading will
> be used and jar files downloaded. MarshalledServiceItem can provide a
> significant amount of information by just resolving using local classes, which
> the client can utilise.
>
> In the long term I see it like this:
>
> We need to look into dependency inversion to remove implementation classes from
> the platform and application class loader, which is the problem that preferred
> class loading addresses.
>
> If implementation classes are not present in the platform, you don't need
> preferred classes for proxys to have their own copy of an implementation class,
> because those classes will be resolved by standard java classloading rules in
> the proxy class loader.
One thing to note, is that I have used PreferredClassLoader to fix bugs by
taking common classes that I use in GUI constructions that would have been
resolved in the parent loader and switching them to be preferred so that I'd get
the fixed version. I am not sure that there is a perfect "split" of
implementation vs platform. Sometimes implementation can be a mini-platform of
sorts. Just repackaging/rearranging jars is not a singular fix, always.
Gregg Wonderly
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Michał Kłeczek wrote:
> On Thu, Feb 3, 2011 at 12:47 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>> 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.
>>
>
> The problem with PREFERRED.LIST is more fundamental - for example
> every RemoteEvent producer is forced to download a jar file just to
> check that RemoteEventListener is not preferred. As such the issue
> cannot be solved at the LUS API level.
>
> Michal
>
>
Yes there are more fundamental problems with preferred classes,
ClassLoading etc that remain to be solved.
But rather than fix it on this occassion, MarshalledServiceItem is just
resolved with local classes and preferred class loading is not used or
needed. When the client unmarshalls the MarshalledServiceItem, then
preferred class loading will be used and jar files downloaded.
MarshalledServiceItem can provide a significant amount of information by
just resolving using local classes, which the client can utilise.
In the long term I see it like this:
We need to look into dependency inversion to remove implementation
classes from the platform and application class loader, which is the
problem that preferred class loading addresses.
If implementation classes are not present in the platform, you don't
need preferred classes for proxys to have their own copy of an
implementation class, because those classes will be resolved by standard
java classloading rules in the proxy class loader.
Cheers,
Peter.
Re: MarshalledServiceItem
Posted by Michał Kłeczek <mi...@xpro.biz>.
On Thu, Feb 3, 2011 at 12:47 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
> 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.
The problem with PREFERRED.LIST is more fundamental - for example
every RemoteEvent producer is forced to download a jar file just to
check that RemoteEventListener is not preferred. As such the issue
cannot be solved at the LUS API level.
Michal
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
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
>
Re: MarshalledServiceItem
Posted by Gregg Wonderly <gr...@wonderly.org>.
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
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
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.
> 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?
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?
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.
>
> The technicians in my customers' business have a lot of windshield time and
> use their cellular connectivity or satellite based WAN networking for many
> tasks. This means that there is a lot of latency, cost for bandwidth in term
> of time and bandwidth both. So, for me to make a distributed network based
> services environment work, I have to limit network to only what is
> absolutely necessary.
>
> So, back to the two different changes that I made to service lookup and
> class resolution. The activities in ClassLoading to provide a
> "neverPreferred" functionality was instituted by having my client tell
> ClassLoading via public static API, which Entry classes and dependent
> classes should never be preferred. Recall, that in the beginning, the class
> loading mechanisms did have a "neverPreferred" policy for java.lang.* and
> for native types and arrays.
>
> This was removed in an update later on in 2.1 if I remember right. This
> kept classloading from being triggered in those cases. That functionality,
> when removed, was declared as nonessential/unused because normal class
> loading would keep that from happening. However, because
> PreferredClassLoading will never ask the parent class loader (especially
> without my patch to allow RMIClassLoaderSPI to not be used) to resolve a
> class until the PREFERRED.LIST is on hand, the codebase will always be
> accessed, requiring a download of at least the first jar.
>
> In my case, a customer with 100 codebases (5 machines) trying to use my
> desktop client, would experience 100 http connections and downloads of the
> first jar before they could see all the available services. And, because of
> the fact that not ever single codebase would be requested in parallel, any
> stuck codebase could potentially delay the display of available services for
> 3-5 minutes per problem codebase while TCP connect requests timeout.
>
> For me, this was just not an acceptable outcome. It was simply not
> possible to manage my product environment with these issues at hand. No
> matter how much the first jar required to be transferred, it would simply
> take way too long for them to see a useful client display.
>
> My changes in River-336 for RMIClassLoaderSPI override, use methods such as
> CodebaseAccessClassLoader.loadClass(...) which can be used to provide the
> "neverPreferred" functionality. So, I have a pluggable mechanism that
> allows me to manage this issue. So if no one else has such requirements,
> there is no need to discuss this as a point of argument for inclusion in
> River. I think it is a valid point of control because the client can
> declare the platform that they are compatible with by using this facility to
> never prefer certain classes which will then cause services overrides to not
> appear and the client could even provide some feedback when this happens by
> allow the CodebaseAccessClassLoader implementation to provide some data
> points about when it finds it is ignoring something declared as preferred.
>
> The other business at hand is the deferred unmarshalling. And in that
> case, I don't think that there is too much of an argument to be had. If we
> focus on just allowing the client to access the entries selectively, and
> defer unmarshalling of the service proxy/object separately, that's the
> basics of what I need for my environment.
>
> The API that I implemented allowed access to the list of classes and
> interfaces referred to by the Entry so that the client could discover that
> it can't unmarshall the Entry because it requires network access to download
> something that it doesn't have locally. If that usage pattern doesn't seem
> valuable, then something more along the lines of providing a Class object as
> Peter's API shows might work well enough. But we need to figure out how to
> deal with Entry values which are subclasses. If I pass in Name.class, and
> there are several subclasses of Name visible in the Entry values, then which
> one would you return? All of them? What if one of those contained a rather
> large object graph which was not what I wanted. Would I get it unmarshalled
> so that I could still inspect it to decide if it was the one I wanted to
> unmarshall and look at?
>
> Sorry for going on and on about this, but I wanted to try and put out all
> the details that I had dealt with and the thoughts around my path of
> solution.
>
> Gregg Wonderly
>
>
Re: MarshalledServiceItem
Posted by Michal Kleczek <kl...@gmail.com>.
On Wed, 2011-02-02 at 18:07 +1000, Peter Firmstone wrote:
> >> 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.
> >>
> >
> > I think I'm with Dan here - looks to me like a misuse of LUS. I see it
> > as a more or less dumb bootstrap mechanism - designed for _lookup_ not
> > _browsing_ .
> > Wouldn't a ServiceBrowserService (or a ServiceIndexingService) be a
> > solution?
> >
> Can you give an example?
>
import javax.swing.tree.TreeModel;
//the service is deployed in a Djinn - it keeps track of all available
//services and indexes them so that the client can just use a TreeModel
//to display available services
interface ServiceBrowserService {
TreeModel getServiceTree();
}
Don't really know what example you need - the point is that the problems
Greg described don't really have to be dealt with by the client but by
one of the services in Djinn that would provide clients with a _view_ of
all available services.
Paraphrasing:
"All problems in a Djinn can be solved by another service".
Michal
Re: MarshalledServiceItem
Posted by Peter Firmstone <ji...@zeus.net.au>.
Michal Kleczek wrote:
> On Tue, 2011-02-01 at 13:12 -0600, Gregg Wonderly wrote:
>
>>> 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.
>>
>
> I think I'm with Dan here - looks to me like a misuse of LUS. I see it
> as a more or less dumb bootstrap mechanism - designed for _lookup_ not
> _browsing_ .
> Wouldn't a ServiceBrowserService (or a ServiceIndexingService) be a
> solution?
>
> Michal
>
>
Can you give an example?
Peter.
Re: MarshalledServiceItem
Posted by Michal Kleczek <mi...@xpro.biz>.
On Tue, 2011-02-01 at 13:12 -0600, Gregg Wonderly wrote:
> > 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.
I think I'm with Dan here - looks to me like a misuse of LUS. I see it
as a more or less dumb bootstrap mechanism - designed for _lookup_ not
_browsing_ .
Wouldn't a ServiceBrowserService (or a ServiceIndexingService) be a
solution?
Michal
Re: MarshalledServiceItem
Posted by Gregg Wonderly <ge...@cox.net>.
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.
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.
The technicians in my customers' business have a lot of windshield time and use
their cellular connectivity or satellite based WAN networking for many tasks.
This means that there is a lot of latency, cost for bandwidth in term of time
and bandwidth both. So, for me to make a distributed network based services
environment work, I have to limit network to only what is absolutely necessary.
So, back to the two different changes that I made to service lookup and class
resolution. The activities in ClassLoading to provide a "neverPreferred"
functionality was instituted by having my client tell ClassLoading via public
static API, which Entry classes and dependent classes should never be preferred.
Recall, that in the beginning, the class loading mechanisms did have a
"neverPreferred" policy for java.lang.* and for native types and arrays.
This was removed in an update later on in 2.1 if I remember right. This kept
classloading from being triggered in those cases. That functionality, when
removed, was declared as nonessential/unused because normal class loading would
keep that from happening. However, because PreferredClassLoading will never ask
the parent class loader (especially without my patch to allow RMIClassLoaderSPI
to not be used) to resolve a class until the PREFERRED.LIST is on hand, the
codebase will always be accessed, requiring a download of at least the first jar.
In my case, a customer with 100 codebases (5 machines) trying to use my desktop
client, would experience 100 http connections and downloads of the first jar
before they could see all the available services. And, because of the fact that
not ever single codebase would be requested in parallel, any stuck codebase
could potentially delay the display of available services for 3-5 minutes per
problem codebase while TCP connect requests timeout.
For me, this was just not an acceptable outcome. It was simply not possible to
manage my product environment with these issues at hand. No matter how much the
first jar required to be transferred, it would simply take way too long for them
to see a useful client display.
My changes in River-336 for RMIClassLoaderSPI override, use methods such as
CodebaseAccessClassLoader.loadClass(...) which can be used to provide the
"neverPreferred" functionality. So, I have a pluggable mechanism that allows me
to manage this issue. So if no one else has such requirements, there is no need
to discuss this as a point of argument for inclusion in River. I think it is a
valid point of control because the client can declare the platform that they are
compatible with by using this facility to never prefer certain classes which
will then cause services overrides to not appear and the client could even
provide some feedback when this happens by allow the CodebaseAccessClassLoader
implementation to provide some data points about when it finds it is ignoring
something declared as preferred.
The other business at hand is the deferred unmarshalling. And in that case, I
don't think that there is too much of an argument to be had. If we focus on
just allowing the client to access the entries selectively, and defer
unmarshalling of the service proxy/object separately, that's the basics of what
I need for my environment.
The API that I implemented allowed access to the list of classes and interfaces
referred to by the Entry so that the client could discover that it can't
unmarshall the Entry because it requires network access to download something
that it doesn't have locally. If that usage pattern doesn't seem valuable, then
something more along the lines of providing a Class object as Peter's API shows
might work well enough. But we need to figure out how to deal with Entry values
which are subclasses. If I pass in Name.class, and there are several subclasses
of Name visible in the Entry values, then which one would you return? All of
them? What if one of those contained a rather large object graph which was not
what I wanted. Would I get it unmarshalled so that I could still inspect it to
decide if it was the one I wanted to unmarshall and look at?
Sorry for going on and on about this, but I wanted to try and put out all the
details that I had dealt with and the thoughts around my path of solution.
Gregg Wonderly
Re: MarshalledServiceItem
Posted by Dan Creswell <da...@gmail.com>.
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. Ultimately, I wanted to not have to worry about how the
> "codebase" was structured in order to minimize downloading. Some Jini
> deployers have done things to put a small jar at the front of the codebase
> that just has the preferred.list in it. Even that download, for me, would
> have been too much. My customers' deployments have nearly 50 codebases
> visible when my client starts up. Those 50 connections over a cellular or
> other high latency network would make service selection take way too long.
>
>
"deserialization of Entry's from the service object"? What does "service
object" refer to?
I think you _have_ to worry about how the codebase is structured. Anything
else is a hack and if we're going to do hacks there are better ones like
bundling up people's .jars for them etc so save on connections/add caching
and such. Doing it further downstream in the lookup mechanism is treating a
symptom not the problem. Not the sort of thing that keeps a design clean or
consistent.
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.
Which brings me to a point Peter made elsewhere: "delayed umarshalling and
selective unmarshalling of Entry's are very important features, missing from
River."
Important to whom? How many people are in the category?
If it's a lot of people, we should spend some time evaluating whether the
default class resolution/download/lookup approach is the generic norm and
potential replacements.
Simplistically, delaying downloading is as simple as returning a
MarshalledInstance on which one can then call .get as and when one
desires.....
Now, I haven't had my coffee yet and I've got a pile of operational worries
to attend to this morning which means I'm maybe a little shout'y,
nevertheless I for one am not convinced of the value of this and less
convinced we have the right solution which feels complex, exceptional and
clunky.
Gregg Wonderly
>
> On Jan 30, 2011, at 2:23 PM, Peter Firmstone wrote:
>
> > Gut feel, tells me the following class is not right, it's intent is to
> provide an api for implementation of delayed unmarshalling and provisioning
> of codebases, for services implementing a lookup service or
> ServiceRegistrar, whilst retaining backward compatibility.
> >
> > In other words, the lookup service proxy would implement it.
> >
> > Thoughts I had were to declare IOException's on methods, and to return a
> String annotation, rather than a URI.
> >
> > What are your thoughts?
> >
> > Cheers,
> >
> > Peter.
> >
> > /*
> > * 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.river.api.lookup;
> >
> > import java.net.URI;
> > import java.security.CodeSource;
> > import net.jini.core.entry.Entry;
> > import net.jini.core.lookup.ServiceID;
> > import net.jini.core.lookup.ServiceItem;
> >
> > /**
> > * MarshalledServiceItem extends ServiceItem and can be used anywhere a
> > * ServiceItem can. A MarshalledServiceItem implementation instance
> > * contains the marshalled form of a Service and it's Entry's,
> > * the corresponding superclass ServiceItem however contains null values
> > * for the service and can exclude any Entry's, however where Entry
> > * classes already exist at the client, that they be unmarshalled.
> > *
> > * The ServiceID shall be in unmarshalled form always in the ServiceItem
> super class.
> > *
> > * Since the ServiceItem.service is null, use of this class in existing
> software
> > * will not return the service, however it will not break that software as
> > * ServiceItem's contract is to set service or Entry's to null when they
> cannot
> > * be unmarshalled.
> > *
> > * ServiceItem's toString() method will return a different result for
> > * MarshalledServiceItem instances.
> > *
> > * If required, a new ServiceItem that is fully unmarshalled
> > * can be constructed from this class's methods and ServiceID.
> > *
> > * @author Peter Firmstone.
> > */
> > public abstract class MarshalledServiceItem extends ServiceItem{
> > private static final long SerialVersionUID = 1L;
> > protected MarshalledServiceItem(ServiceID id, Entry[]
> unmarshalledEntries){
> > super(id, (Object) null, unmarshalledEntries);
> > }
> > /**
> > * Unmarshall the service proxy.
> > * @param load service with local or existing CodeSource or null for
> > * default.
> > * @return the service proxy, null if class not found.
> > */
> > public abstract Object getService(CodeSource[] code);
> > /**
> > * Unmarshall the Entry's
> > * @return array of Entry's, null entry in array for any class not
> found.
> > */
> > public abstract Entry[] getEntries();
> > public abstract URI[] getAnnotations();
> > }
> >
>
>