All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.bridge.service.search.ServiceQuery Maven / Gradle / Ivy

Go to download

Jadex bridge is a base package for kernels and platforms, i.e., it is used by both and provides commonly used interfaces and classes for active components and their management.

There is a newer version: 4.0.267
Show newest version
package jadex.bridge.service.search;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jadex.bridge.ClassInfo;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.sensor.service.TagProperty;
import jadex.bridge.service.IServiceIdentifier;
import jadex.bridge.service.RequiredServiceBinding;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.ServiceScope;
import jadex.bridge.service.component.BasicServiceInvocationHandler;
import jadex.bridge.service.search.ServiceQuery.Multiplicity;
import jadex.commons.SUtil;
import jadex.commons.Tuple3;

/**
 *  Service query definition. T is the return type for search methods.
 */
public class ServiceQuery
{	
	/** The raw proxy type (i.e. no proxy). */
	public static final String	PROXYTYPE_RAW	= BasicServiceInvocationHandler.PROXYTYPE_RAW;
	
	/** The direct proxy type (supports custom interceptors, but uses caller thread). */
	public static final String	PROXYTYPE_DIRECT	= BasicServiceInvocationHandler.PROXYTYPE_DIRECT;
	
	/** The (default) decoupled proxy type (decouples from component thread to caller thread). */
	public static final String	PROXYTYPE_DECOUPLED	= BasicServiceInvocationHandler.PROXYTYPE_DECOUPLED;
	
	
	//-------- constants --------
	
	/** Marker for networks not set. */
	//Hack!!! should not be public??? 
	public static final String[]	NETWORKS_NOT_SET	= new String[]{"__NETWORKS_NOT_SET__"};	// TODO: new String[0] for better performance, but unable to check remotely after marshalling!
	
	/** Default matching modes set the elements with OR semantics. */
	public static final Map DEFAULT_MATCHINGMODES = SUtil.createHashMap(
		new String[]{ServiceKeyExtractor.KEY_TYPE_TAGS, ServiceKeyExtractor.KEY_TYPE_NETWORKS}, 
		new Boolean[]{Boolean.FALSE, Boolean.FALSE});
	
	//-------- attributes --------
	
	/** The service type. */
	protected ClassInfo servicetype;
	
	/** Tags of the service. */
	protected String[] servicetags;
	
	/** The service provider. (rename serviceowner?) */
	//protected IComponentIdentifier provider;
	
	/** Starting point for the search scoping. */
	protected IComponentIdentifier searchstart;
	
	/** The service platform. (Find a service from another known platform, e.g. cms) */
	protected IComponentIdentifier platform;
	
	/** The service ID of the target service. Fast lookup of a service by id. */
	protected IServiceIdentifier serviceidentifier;
	
	/** The network names. */
	protected String[] networknames;
	
	/** Should the service be unrestricted. */
	protected Boolean unrestricted;
	
	/** The search scope. */
	protected ServiceScope scope;
	
	/** The query owner. (rename queryowner?) */
	protected IComponentIdentifier owner;
	
	//-------- influence the result --------
	
	/** Flag, if service by the query owner should be excluded, i.e. do not return my own service. */
	protected boolean excludeowner;
	
	/** The multiple flag. Search for multiple services */
	protected Multiplicity	multiplicity;
	
	/** Flag if event mode is enabled on the query. */
	protected boolean eventmode;
	
	/** The matching mode for multivalued terms. True is and and false is or. */
	protected Map matchingmodes;
	
	/** Required service proxy type. */
	protected String requiredproxytype = PROXYTYPE_DECOUPLED;
	
	//-------- identification of a query --------
	
	/** The query id. Id is used for hashcode and equals and the same is used by servicequeryinfo class.
	    Allows for hashing queryies and use a queryinfo object for lookup. */
	protected String id;
	
//	/** Is the query prepared? Prepared means that the query is ready to be processed by the registry. */ 
//	protected boolean prepared;
	
	/**
	 *  Create a new service query.
	 */
	protected ServiceQuery()
	{
		// Not public to not encourage user to use it.
		// Here it does NOT set the networknames automatically because used for serialization.
	}
	
//	/**
//	 *  Create a new service query.
//	 */
//	public ServiceQuery(ClassInfo servicetype, String scope, IComponentIdentifier owner)
//	{
//		this(servicetype, scope, (IFilter) null, null, owner);
//	}
//	
//	/**
//	 *  Create a new service query.
//	 */
//	public ServiceQuery(ClassInfo servicetype, String scope, IComponentIdentifier provider, IComponentIdentifier owner)
//	{
//		this(servicetype, scope, (IFilter) null, provider, owner);
//	}
//	
	/**
	 *  Create a new service query.
	 */
	public ServiceQuery(Class servicetype)
	{
		this(servicetype, null);
	}
	
	/**
	 *  Create a new service query.
	 */
	public ServiceQuery(Class servicetype, ServiceScope scope)
	{
		this(servicetype == null ?(ClassInfo) null : new ClassInfo(servicetype), scope, null);
	}
	
//	
//	/**
//	 *  Create a new service query.
//	 */
//	public ServiceQuery(Class servicetype, String scope, IFilter filter, IComponentIdentifier provider, IComponentIdentifier owner)
//	{
////		this(new ClassInfo(servicetype), scope, filter, provider, owner);this.returntype = servicetype;
//		this.servicetype = new ClassInfo(servicetype);
//		this.returntype = this.servicetype;
//		// todo: what is the best place for this?
//		this.scope = scope==null && ServiceIdentifier.isSystemService(servicetype)? ServiceScope.PLATFORM: scope;
//		this.filter = filter;
//		this.provider = provider;
//		this.owner = owner;
//		
//	}
//	
//	/**
//	 *  Create a new service query.
//	 */
//	public ServiceQuery(ClassInfo servicetype, String scope, IFilter filter, IComponentIdentifier provider, IComponentIdentifier owner)
//	{
//		this.returntype = servicetype;
//		this.servicetype = servicetype;
//		this.scope = scope;
//		this.filter = filter;
//		this.provider = provider;
//		this.owner = owner;
//	}
//	
//	/**
//	 *  Create a new service query.
//	 */
//	public ServiceQuery(Class returntype, Class servicetype, String scope, IAsyncFilter filter, IComponentIdentifier provider, IComponentIdentifier owner)
//	{
//		this(new ClassInfo(returntype), new ClassInfo(servicetype), scope, filter, provider, owner);
//	}
	
//	/**
//	 *  Create a new service query.
//	 */
//	public ServiceQuery(ClassInfo returntype, ClassInfo servicetype, String scope, IAsyncFilter filter, IComponentIdentifier provider, IComponentIdentifier owner)
//	{
//		this.returntype = returntype;
//		this.servicetype = servicetype;
//		this.scope = scope;
//		this.filter = filter;
//		this.provider = provider;
//		this.owner = owner;
//	}
//	
//	/**
//	 *  Create a new service query.
//	 */
//	public ServiceQuery(ClassInfo servicetype, String scope, IAsyncFilter filter, IComponentIdentifier provider, IComponentIdentifier owner)
//	{
//		this(servicetype, servicetype, scope, filter, provider, owner);
////		this.returntype = servicetype;
////		this.servicetype = servicetype;
////		this.scope = scope;
////		this.filter = filter;
////		this.provider = provider;
////		this.owner = owner;
//	}
	
	/**
	 *  Create a new service query.
	 *  owner = startpoint
	 */
//	public ServiceQuery(Class servicetype, String scope, IComponentIdentifier provider, IComponentIdentifier owner)
//	{
//		this(servicetype, scope, provider, owner, null);
//	}
	
	/**
	 *  Create a new service query.
	 */
	public ServiceQuery(Class servicetype, ServiceScope scope, IComponentIdentifier owner)
	{
		this(servicetype == null ? (ClassInfo) null : new ClassInfo(servicetype), scope, owner);
	}
	
	/**
	 *  Create a new service query.
	 */
	public ServiceQuery(ClassInfo servicetype)
	{
		this(servicetype, null, null);
	}
	
	/**
	 *  Create a new service query.
	 */
	public ServiceQuery(ClassInfo servicetype, ServiceScope scope, IComponentIdentifier owner)
	{
//		if(owner==null)
//			throw new IllegalArgumentException("Owner must not null");
		
		this.servicetype = servicetype;
		this.owner = owner;
		
		this.id = SUtil.createUniqueId();
		this.networknames = NETWORKS_NOT_SET;
		
		setScope(scope);
	}
	
	/**
	 *  Shallow copy constructor.
	 *  @param original Original query.
	 */
	public ServiceQuery(ServiceQuery original)
	{
		this.servicetype = original.servicetype;
		this.scope = original.scope;
		this.servicetags = original.servicetags;
		this.owner = original.owner;
		this.id = original.id;
		this.networknames = original.networknames;
		this.matchingmodes = original.matchingmodes;
		this.platform	= original.platform;
		this.searchstart	= original.searchstart;
		this.unrestricted = original.unrestricted;
		this.requiredproxytype = original.requiredproxytype;
	}

	/**
	 *  Get the service type.
	 *  @return The service type
	 */
	public ClassInfo getServiceType()
	{
		return servicetype;
	}

	/**
	 *  Set the service type.
	 *  @param type The service type to set
	 */
	public ServiceQuery setServiceType(ClassInfo servicetype)
	{
		this.servicetype = servicetype;
		return this;
	}
	
	/**
	 *  Changes the query to event mode.
	 *  
	 *  @param eventmode the event mode state.
	 *  @deprecated For bean purposes only, use setEventMode().
	 */
	@Deprecated
	public void setEventMode(boolean eventmode)
	{
		this.eventmode = eventmode;
	}
	
	/**
	 *  Changes the query to event mode.
	 *  
	 *  @return The new query.
	 */
	@SuppressWarnings("unchecked")
	public ServiceQuery> setEventMode()
	{
		this.eventmode = true;
		return (ServiceQuery>)this;
	}
	
	/**
	 *  Checks if query is in event mode.
	 *  @return True, if in event mode
	 */
	public boolean isEventMode()
	{
		return eventmode;
	}
	
	/**
	 *  Get the scope.
	 *  @return The scope
	 */
	public ServiceScope getScope()
	{
		return scope;
	}

	/**
	 *  Set the scope.
	 *  @param scope The scope to set
	 */
	public ServiceQuery setScope(ServiceScope scope)
	{
		if(ServiceScope.EXPRESSION.equals(scope))
			throw new IllegalArgumentException("Cannot use scope 'expression' directly.");

		this.scope = scope!=null?scope:ServiceScope.DEFAULT;
		return this;
	}
	
	/**
	 *  Gets the service tags.
	 *  
	 *  @return The service tags. 
	 */
	public String[] getServiceTags()
	{
		return servicetags;
	}
	
	/**
	 *  Sets the service tags.
	 *  @param servicetags The service tags. 
	 */
	public ServiceQuery setServiceTags(String... servicetags)
	{
		TagProperty.checkReservedTags(servicetags);
		this.servicetags = servicetags;
		return this;
	}
	
	/**
	 *  Sets the service tags.
	 *  @param servicetags The service tags.
	 *  
	 *  todo: move or refactor to hide complexity!?
	 */
	public ServiceQuery setServiceTags(String[] servicetags, IExternalAccess component)
	{
		this.servicetags = TagProperty.createRuntimeTags(servicetags, component).toArray(new String[servicetags!=null ? servicetags.length : 0]);
		return this;
	}

	/**
	 *  Set the provider.
	 *  @param provider The provider to set
	 */
	public ServiceQuery setProvider(IComponentIdentifier provider)
	{
		this.searchstart = provider;
		this.scope = ServiceScope.COMPONENT_ONLY;
		return this;
	}
	
	/**
	 *  Get the provider.
	 *  @return The provider
	 */
	public IComponentIdentifier getSearchStart()
	{
		return searchstart;
	}

	/**
	 *  Set the provider.
	 *  @param provider The provider to set
	 */
	public ServiceQuery setSearchStart(IComponentIdentifier searchstart)
	{
		this.searchstart = searchstart;
		return this;
	}
	
	/**
	 *  Get the platform.
	 *  @return The platform
	 */
	public IComponentIdentifier getPlatform()
	{
		return platform;
	}
	
	/**
	 *  Set the platform.
	 *  @param platform The platform
	 */
	public ServiceQuery setPlatform(IComponentIdentifier platform)
	{
		this.platform = platform;
		return this;
	}
	
	/**
	 *  Gets the service identifier.
	 *
	 *  @return The service identifier.
	 */
	public IServiceIdentifier getServiceIdentifier()
	{
		return serviceidentifier;
	}

	/**
	 *  Sets the service identifier.
	 *  Also sets the corresponding provider when sid!=null.
	 *
	 *  @param serviceidentifier The service identifier.
	 */
	// TODO: looking up sid shouldn't be search/query?
	public ServiceQuery setServiceIdentifier(IServiceIdentifier serviceidentifier)
	{
		this.serviceidentifier = serviceidentifier;
		// When setting sid also set provider.
		if(serviceidentifier!=null)
			setProvider(serviceidentifier.getProviderId());
		return this;
	}

	/**
	 *  Get the owner.
	 *  @return The owner
	 */
	public IComponentIdentifier getOwner()
	{
		return owner;
	}

	/**
	 *  Set the owner.
	 *  @param owner The owner to set
	 */
	public ServiceQuery setOwner(IComponentIdentifier owner)
	{
		this.owner = owner;
		return this;
	}
	
	/**
	 *  Checks if service of the query owner should be excluded.
	 *  
	 *  @return True, if the services should be excluded.
	 */
	public boolean isExcludeOwner()
	{
		return excludeowner;
	}
	
	/**
	 *  Sets if service of the query owner should be excluded.
	 *  
	 *  @param excludeowner True, if the services should be excluded.
	 */
	public ServiceQuery setExcludeOwner(boolean excludeowner)
	{
		this.excludeowner = excludeowner;
		return this;
	}
	
	/**
	 *  Get the id.
	 *  @return the id
	 */
	public String getId()
	{
		return id;
	}

	/**
	 *  Set the id.
	 *  @param id The id to set
	 */
	public ServiceQuery setId(String id)
	{
		this.id = id;
		return this;
	}
	
	/**
	 *  Get the multiplicity.
	 *  @return the multiplicity
	 */
	public Multiplicity	getMultiplicity()
	{
		return multiplicity;
	}
	
	/**
	 *  Set the multiplicity.
	 *  @param multiplicity The minimum multiplicity to set
	 */
	public ServiceQuery setMultiplicity(int multiplicity)
	{
		return setMultiplicity(multiplicity, -1);
	}
	
	/**
	 *  Set the multiplicity.
	 *  @param multiplicitystart The minimum multiplicity to set
	 *  @param multiplicityend The max multiplicity to set
	 */
	public ServiceQuery setMultiplicity(int multiplicitystart, int multiplicityend)
	{
		return setMultiplicity(new Multiplicity(multiplicitystart, multiplicityend));
	}

	/**
	 *  Set the multiplicity.
	 *  @param multiplicity The multiplicity to set
	 */
	public ServiceQuery setMultiplicity(Multiplicity multiplicity)
	{
		this.multiplicity = multiplicity;
		return this;
	}

	/**
	 *  Gets the specification for the indexer.
	 *  Query needs to be enhanced before calling this method. See RequiredServiceFeature.enhanceQuery()
	 *  
	 *  @return The specification for the indexer.
	 */
	public List> getIndexerSearchSpec()
	{
		List> ret = new ArrayList>();
		
		// Problem with normal vs resticted vs. unrestricted queries
		// normal: - deliver all services (restr. and unrestr.). 
		//         - unrestricted services do not need networks that fit to those from query (they can always be accessed). Therefore key extractor return MATCH_ALWAYS. important for normal queries
		// restricted and unrestricted: use index to find only those. in case of unrestricted query the networks of the query will be omitted (they might have been automatically set)
		
		// normal is both, i.e. unrestricted = null
		if(unrestricted != null)
			ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_UNRESTRICTED, new String[]{unrestricted.toString()}, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_UNRESTRICTED)));
		
		if(platform != null)
			ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_PLATFORM, new String[]{platform.toString()}, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_PLATFORM)));
		
		if(ServiceScope.COMPONENT_ONLY.equals(scope))
		{
			if(searchstart != null)
				ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_PROVIDER, new String[]{searchstart.toString()}, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_PROVIDER)));
			else
				ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_PROVIDER, new String[]{owner.toString()}, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_PROVIDER)));
		}
		
		if(servicetype != null)
			ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_INTERFACE, new String[]{servicetype.getGenericTypeName()}, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_INTERFACE)));
		
		if(servicetags != null && servicetags.length > 0)
			ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_TAGS, servicetags, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_TAGS)));
		
		if(serviceidentifier != null)
			ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_SID, new String[]{serviceidentifier.toString()}, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_SID)));
		
		assert !Arrays.equals(networknames, NETWORKS_NOT_SET) : "Problem: query not enhanced before processing.";
	
		if((unrestricted==null || Boolean.FALSE.equals(unrestricted)) && networknames != null && networknames.length > 0)
			ret.add(new Tuple3(ServiceKeyExtractor.KEY_TYPE_NETWORKS, networknames, getMatchingMode(ServiceKeyExtractor.KEY_TYPE_NETWORKS)));
		
		return ret;
	}
	
	/**
	 *  Get the matching mode for a key.
	 *  @param key The key name.
	 *  @return True for and, false for or.
	 */
	public Boolean getMatchingMode(String key)
	{
		return matchingmodes==null? DEFAULT_MATCHINGMODES.get(key): matchingmodes.get(key);
	}
	
	/**
	 *  Set a matching mode.
	 *  @param key The key name.
	 *  @param and True for and.
	 */
	public ServiceQuery setMatchingMode(String key, Boolean and)
	{
		if(matchingmodes==null)
			matchingmodes = new HashMap(DEFAULT_MATCHINGMODES);
		matchingmodes.put(key, and);
		return this;
	}
	
	
	/**
	 *  Get the unrestricted mode.
	 *  @return The unrestricted mode.
	 */
	public Boolean isUnrestricted()
	{
		return unrestricted;
	}

	/**
	 *  Set the unrestricted mode.
	 *  @param unrestricted the unrestricted to set
	 */
	public ServiceQuery setUnrestricted(Boolean unrestricted)
	{
		this.unrestricted = unrestricted;
		return this;
	}

	/**
	 *  Tests if the query keys matches a service.
	 *  
	 *  @param service The service.
	 *  @return True, if the service matches the keys.
	 */
	protected boolean matchesKeys(IServiceIdentifier service)
	{
		if (servicetype != null && !service.getServiceType().getGenericTypeName().equals(servicetype))
			return false;
		
		if (servicetags != null)
		{
			Set tagsset = ServiceKeyExtractor.getKeysStatic(ServiceKeyExtractor.KEY_TYPE_TAGS, service);
			if (tagsset == null)
				return false;
			
			for (String tag : servicetags)
			{
				if (!tagsset.contains(tag))
				{
					return false;
				}
			}
		}
		
		if (ServiceScope.COMPONENT_ONLY.equals(scope) &&
			!((searchstart != null && service.getProviderId().equals(searchstart)) ||
			service.getProviderId().equals(owner)))
			return false;
		
//		if (provider != null && !provider.equals(service.getProviderId()))
//			return false;
		
		if (platform != null && !platform.equals(service.getProviderId().getRoot()))
			return false;
		
		return true;
	}
	
//	/**
//	 *  Get the prepared.
//	 *  @return the prepared
//	 */
//	public boolean isPrepared()
//	{
//		return prepared;
//	}
//
//	/**
//	 *  Set the prepared.
//	 *  @param prepared The prepared to set
//	 */
//	public void setPrepared(boolean prepared)
//	{
//		this.prepared = prepared;
//	}
	
//	/**
//	 *  Prepare the query.
//	 */
//	public void prepare(IComponentIdentifier cid)
//	{
//		if(!prepared)
//		{
//			networknames = getNetworkNames(cid);
//			prepared = true;
//		}
//	}
	
	
	/**
	 *  Get the networknames.
	 *  @return the networknames
	 */
	public String[] getNetworkNames()
	{
		return networknames;
	}

	/**
	 *  Set the networknames.
	 *  @param networknames The networknames to set
	 */
	public ServiceQuery setNetworkNames(String... networknames)
	{
		this.networknames = networknames;
		return this;
	}
	
	/**
	 *  Returns the requested required service proxy type.
	 *  @return The requested required service proxy type.
	 */
	public String getRequiredProxyType()
	{
		return requiredproxytype;
	}
	
	/**
	 *  Sets the requested required service proxy type.
	 *  @param requiredproxytype The requested required service proxy type.
	 */
	public ServiceQuery setRequiredProxyType(String requiredproxytype)
	{
		this.requiredproxytype = requiredproxytype;
		return this;
	}

	/**
	 *  Get the hashcode.
	 */
	public int hashCode()
	{
		return id.hashCode()*13;
	}

	/**
	 *  Test if other object equals this one.
	 */
	public boolean equals(Object obj)
	{
		boolean ret = false;
		if(obj instanceof ServiceQuery)
		{
			ServiceQuery other = (ServiceQuery)obj;
			ret = SUtil.equals(getId(), other.getId());
		}
		return ret;
	}
	
	/**
	 *  Get the target platform if specified (using platform and provider).
	 *  @return The target platform.
	 */
	public IComponentIdentifier getTargetPlatform()
	{
		if (getPlatform()!=null)
			return getPlatform().getRoot();
		
		if (ServiceScope.COMPONENT_ONLY.equals(scope))
			return searchstart != null ? searchstart.getRoot() : owner.getRoot();
			
		return null;
	}
	
	/**
	 * When searching for declared service -> map required service declaration to service query.
	 */
	public static  ServiceQuery getServiceQuery(IInternalAccess ia, RequiredServiceInfo info)
	{
		// TODO??? : no, but hardconstraints should be added, NFR props are not for search
//		info.getNFRProperties();

		// todo:
//		info.getDefaultBinding().getComponentName();
//		info.getDefaultBinding().getComponentType();
		
		ServiceQuery ret = new ServiceQuery(info.getType(), info.getDefaultBinding().getScope(), ia.getId());
		//ret.setMultiplicity(info.isMultiple() ? Multiplicity.ZERO_MANY : Multiplicity.ONE);
		
		Multiplicity m = new Multiplicity();
		if(info.getMin()!=RequiredServiceInfo.UNDEFINED)
			m.setFrom(info.getMin());
		if(info.getMax()!=RequiredServiceInfo.UNDEFINED)
			m.setTo(info.getMax());
		
		if(info.getTags()!=null)
			ret.setServiceTags(info.getTags().toArray(new String[info.getTags().size()]), ia.getExternalAccess());
		
		return ret;
	}
	
	/**
	 *  When searching with query -> create required service info from service query.
	 */
	public static  RequiredServiceInfo createServiceInfo(ServiceQuery query)
	{
		// TODO: multiplicity required here for info? should not be needed for proxy creation
		RequiredServiceBinding binding = new RequiredServiceBinding(SUtil.createUniqueId(), query.getScope());
		binding.setProxytype(query.getRequiredProxyType());
		Multiplicity m = query.getMultiplicity();
		return new RequiredServiceInfo(null, query.getServiceType(), m==null? RequiredServiceInfo.UNDEFINED: m.getFrom(), 
			m==null? RequiredServiceInfo.UNDEFINED: m.getTo() , binding, null, query.getServiceTags()==null ? null : Arrays.asList(query.getServiceTags()));
	}

	/**
	 *  Get the string representation.
	 */
	public String toString()
	{
		StringBuffer	ret	= new StringBuffer("ServiceQuery(");
		if(servicetype!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("servicetype=");
			ret.append(servicetype);
		}
		
		if(serviceidentifier!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("serviceidentifier=");
			ret.append(serviceidentifier);
		}
		
		if(multiplicity!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("multiplicity=");
			ret.append(multiplicity);
		}
		
		if(servicetags!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("servicetags=");
			ret.append(Arrays.toString(servicetags));
		}
		if(searchstart!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("searchstart=");
			ret.append(searchstart);
		}
		if(platform!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("platform=");
			ret.append(platform);
		}
		if(networknames!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("networknames=");
			ret.append(Arrays.toString(networknames));
		}

		if(unrestricted!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("unrestricted=");
			ret.append(unrestricted);
		}

		if(scope!=null && !ServiceScope.DEFAULT.equals(scope))
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("scope=");
			ret.append(scope);
		}

		if(owner!=null)
		{
			ret.append(ret.length()==13?"":", ");
			ret.append("owner=");
			ret.append(owner);
		}
			
		ret.append(")");
		return ret.toString();
	}
	
	//-------- query multiplicity --------
	
	/**
	 *  Define cases for multiplicity.
	 */
	public static class	Multiplicity
	{
		//-------- constants --------
		
		/** '0..1' multiplicity for single optional service. */
		public static Multiplicity	ZERO_ONE	= new Multiplicity(0, 1);
		
		/** '1' multiplicity for required service (default for searchService methods). */
		public static Multiplicity	ONE			= new Multiplicity(1, 1);
		
		/** '0..*' multiplicity for optional multi service (default for searchServices methods). */
		public static Multiplicity	ZERO_MANY	= new Multiplicity(0, -1);

		/** '1..*' multiplicity for required service (default for searchService methods). */
		public static Multiplicity	ONE_MANY	= new Multiplicity(1, -1);
		
		//-------- attributes --------
		
		/** The minimal number of services required. Otherwise search ends with ServiceNotFoundException. */
		private int	from;
		
		/** The maximal number of services returned. Afterwards search/query will terminate. */
		private int to;
		
		//-------- constructors --------

		/**
		 *  Bean constructor.
		 *  Not meant for direct use.
		 *  Defaults to invalid multiplicity ('0..0')!
		 */
		public Multiplicity()
		{
			this.from = -2; // = UNDEFINED
			this.to = -2;
		}
		
		/**
		 *  Create a multiplicity.
		 *  @param from The minimal number of services for the search/query being considered successful (positive integer or 0).
		 *  @param to The maximal number of services returned by the search/query (positive integer or -1 for unlimited).
		 */
		public Multiplicity(int from, int to)
		{
			setFrom(from);
			setTo(to);
		}
		
		//-------- methods --------
		
		/**
		 *  Get the 'from' value, i.e. the minimal number of services required.
		 *  Otherwise search ends with ServiceNotFoundException. 
		 */
		public int getFrom()
		{
			return from;
		}
		
		/**
		 *  Set the 'from' value, i.e. the minimal number of services required.
		 *  Otherwise search ends with ServiceNotFoundException. 
		 *  @param from Positive integer or 0
		 */
		public void setFrom(int from)
		{
			if(from<0)
				throw new IllegalArgumentException("'from' must be a positive value or 0.");
				
			this.from = from;
		}
		
		/**
		 *  Get the 'to' value, i.e. The maximal number of services returned.
		 *  Afterwards search/query will terminate.
		 */
		public int getTo()
		{
			return to;
		}
		
		/**
		 *  Get the 'to' value, i.e. The maximal number of services returned.
		 *  Afterwards search/query will terminate.
		 *  @param to	Positive integer or -1 for unlimited.
		 */
		public void setTo(int to)
		{
			if(to!=-1 && to<1)
				throw new IllegalArgumentException("'to' must be a positive value or -1.");
			
			this.to = to;
		}
		
		/**
		 *  Get a string representation of the multiplicity.		
		 */
		@Override
		public String toString()
		{
			return from==to ? Integer.toString(from) : from + ".." + (to==-1 ? "*" : Integer.toString(to));
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy