You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by rj...@apache.org on 2009/06/09 14:00:32 UTC

svn commit: r782968 [6/7] - in /directory/sandbox/slp: ./ src/main/java/org/apache/directory/slp/ src/main/java/org/apache/directory/slp/codec/ src/main/java/org/apache/directory/slp/extensions/ src/main/java/org/apache/directory/slp/impl/ src/main/jav...

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ThreadedReplyFuture.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ThreadedReplyFuture.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ThreadedReplyFuture.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ThreadedReplyFuture.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,301 @@
+/* 
+ *   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.directory.slp.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.slp.ReplyFuture;
+import org.apache.directory.slp.messages.AbstractSLPReplyMessage;
+
+/**
+ * The future returned when performing SLP lookups. It can be accessed while results still come in using next(),
+ * or after all results have arrived using getResult().
+ * 
+ * @author Lorenz Breu
+ *
+ */
+public class ThreadedReplyFuture implements ReplyFuture {
+
+	// used to wait for done status
+	protected final Object donelock = new Object();
+	
+	//List of responses (i.e. message results)
+	protected final List<String> responses = new ArrayList<String>();
+	
+	// List of responders, used to build initial list of previous responders for multicast convergence
+	protected final List<String> responders = new ArrayList<String>();
+	
+	// point when reply future is closed automatically
+	protected long timeout;
+	
+	// set to true when all operations producing results have completed
+	protected boolean done = false;
+	
+	// the next position to be returned using the next() method.
+	// currently a future object is read by only one consumer.
+	private int nextPosition = 0;
+	
+	// the list of scopes this future has to cover, used to control correct closure.
+	private List<String> unhandledScopes = new ArrayList<String>();
+	
+	// used to close the future when lifetime expires
+	private Thread timeoutThread;
+	
+	/**
+	 * Basic constructor, sets a default timeout value and uses all scopes definied in CONFIG
+	 */
+	public ThreadedReplyFuture(){
+		//TODO: which wait time should we use here? has to be larger than the time it takes to start and end the multicast convergence
+		this(SLPCore.CONFIG.getWaitTime()*5);
+	}
+	
+	
+	
+	
+	/**
+	 * Constructor with a specific lifetime. The future expects to handle all scopes defined in CONFIG
+	 * 
+	 * @param lifetime
+	 * 				Number of milliseconds this future should remain open to receive results.
+	 */
+	public ThreadedReplyFuture(long lifetime){
+		unhandledScopes = SLPUtils.stringToList(SLPCore.CONFIG.getScopes().toLowerCase(), ",");
+		timeout = System.currentTimeMillis()+lifetime;
+		timeoutThread = new TimeoutThread();
+	}
+	
+	
+	/**
+	 * Detailed constructor.
+	 * 
+	 * @param lifetime
+	 * 			Number of milliseconds this future should remain open to receive results.
+	 * @param scopes
+	 * 			List of scopes to be handled.
+	 */
+	public ThreadedReplyFuture(long lifetime,List<String> scopes){
+		for (String s : scopes){
+			unhandledScopes.add(s.toLowerCase());
+		}
+		timeout = System.currentTimeMillis()+lifetime;
+		timeoutThread = new TimeoutThread();
+	}
+	
+	
+	
+	/**
+	 * Adds the result of an SLP reply message to the list of responses and the sender of the 
+	 * reply to the list of responders, if the error code is 0. 
+	 * 
+	 * @param reply
+	 * 			An AbstractSLPReplyMessage obtained through unicast or multicast
+	 */
+	public void add(AbstractSLPReplyMessage reply){
+
+		if (reply==null || reply.getErrorCode()!=0){
+			return;
+		}
+		if (done){
+			// this reply is coming in too late...
+			return;
+		}
+		
+		synchronized (responders){
+			if (!responders.contains(reply.getSource())) {
+				responders.add(reply.getSource());
+			} else {
+				return;
+			}
+		}
+		
+		synchronized(responses){
+			List<String> res = reply.getResultAsList();
+			if (res!=null && res.size()>0){
+				List<String> resp = reply.getResultAsList();
+				for (String s: resp){
+					if (!responses.contains(s)){
+						responses.add(s);
+					}
+				}
+				responses.notifyAll();
+			}
+		}
+		
+	}
+	
+	/**
+	 * Close the future.
+	 * If the override flag is set, the future will be closed directly.
+	 * If override is false, then the defined scopes will be removed from the list of unhandled scopes
+	 * and the future will be closed only if no scopes remain unhandled. Else it will remain open.
+	 * 
+	 * @param scopes
+	 * 			The scopes to mark as done.
+	 * @param override
+	 * 			Set to true if the future should be closed even if scopes remain unhandled (e.g. timeout)
+	 */
+	public synchronized void setDone(String[] scopes, boolean override){
+		synchronized (unhandledScopes){
+			for (String s: scopes){
+				unhandledScopes.remove(s.toLowerCase());
+			}
+		}
+		
+		if (!unhandledScopes.isEmpty() && !override){
+			//oops, not all scopes that were expected to be handled actually were handled, so keep waiting
+			return;
+		}
+		if (!done){
+			done=true;
+			synchronized(donelock){
+				donelock.notifyAll();
+			}
+			synchronized(responses){
+				responses.notifyAll();
+			}
+		}
+		try {
+			timeoutThread.interrupt();
+		} catch (Exception e){
+			System.out.println("oops");
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceLocationEnumeration#next()
+	 */
+	public String next(){
+		// NOTE: a future is currently only read by one consumer (i.e. LocatorImpl) and therefor a single
+		// position marker is sufficient. Also the data containers holding responses must add new elements to the end.
+		synchronized(responses){
+			while (!done){
+				if (responses.size()>nextPosition){
+					return responses.get(nextPosition++);
+				}
+				try{
+					responses.wait(timeout-System.currentTimeMillis()+1000);
+				} catch (InterruptedException e){
+					
+				}
+			}
+			if (responses.size()>nextPosition){
+				return responses.get(nextPosition++);
+			}
+			return null;
+		}
+	}
+	
+	
+	/**
+	 * Returns the status of the future.
+	 * 
+	 * @return
+	 * 		True if done, false if results can still be added.
+	 */
+	public synchronized boolean isDone(){
+		return done;
+	}
+	
+	
+	/**
+	 * Blocking call that waits until the future is marked as "done" before returning all available responses.
+	 * 
+	 * @return
+	 * 		A list of all results obtained during the unicast or multicast SLP operation in the form of Strings.
+	 */
+	public List<String> getResult(){
+		while (!done){
+			synchronized (donelock){
+				try {
+					donelock.wait();
+				} catch (InterruptedException ie){
+					
+				}
+			}
+		}
+		return responses;
+	}
+	
+	
+	/**
+	 * Returns the sources of all reply messages with error code 0 passed on to this future. 
+	 * 
+	 * @return
+	 * 		Array of IP addresses as Strings in dot notation of the sources of reply messages.
+	 */
+	public synchronized String[] getResponders(){
+		return SLPUtils.listToStringArray(responders);
+	}
+	
+	/* (non-Javadoc)
+	 * @see java.util.Enumeration#hasMoreElements()
+	 */
+	public synchronized boolean hasMoreElements() {
+		return (responses.size()>nextPosition);
+	}
+
+	/* (non-Javadoc)
+	 * @see java.util.Enumeration#nextElement()
+	 */
+	public String nextElement() {
+		return next();
+	}
+	
+	
+	
+	/**
+	 * setup a new thread to close this future when it times out.
+	 * 
+	 */
+	private class TimeoutThread extends Thread {
+
+		public TimeoutThread() {
+			this.start();
+		}
+
+		public void run() {
+
+			long remain;
+
+			// while lifetime is not expired
+			while (((remain=timeout-System.currentTimeMillis())>0) && !isDone()){
+				try {
+					Thread.sleep(remain);
+				} catch (InterruptedException ie){
+					continue;
+				}
+			}
+			// close the future, even if scopes remain unhandled
+			setDone(new String[]{},true);
+		}
+	}
+
+
+}
+
+	
+	
+	
+	
+	
+	
+	
+

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ThreadedReplyFuture.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemon.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemon.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemon.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemon.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,173 @@
+/* 
+ *   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.directory.slp.impl.da;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.slp.Service;
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.ServiceStore;
+import org.apache.directory.slp.messages.AbstractSLPMessage;
+import org.apache.directory.slp.messages.AbstractSLPReplyMessage;
+import org.apache.directory.slp.messages.DAAdvertisementMessage;
+import org.apache.directory.slp.messages.ServiceDeregistrationMessage;
+import org.apache.directory.slp.messages.ServiceRegistrationMessage;
+
+
+/**
+ * Internal interface of the jSLP Directory Agent. This interface is to the "daemon" that does message handling
+ * and reads services from and writes them to the store. This should only be used by the jSLP machinery, not fro the outside.
+ * To access the DA from a client application, or to start a standalone DA, use the DirectoryAgent interface.
+ * 
+ * @author Lorenz Breu
+ */
+public interface DirectoryAgentDaemon {
+
+	/**
+	 * This does the actual message handling and controlling. Called by the SLPHandler if it receives a message
+	 * of interest.
+	 * 
+	 * @param msg
+	 * 		The received AbstractSLPMessage
+	 * @return
+	 * 		The reply if the received message triggers such, null else.
+	 * @throws ServiceLocationException
+	 */
+	public AbstractSLPReplyMessage handleMessage(AbstractSLPMessage msg) throws ServiceLocationException;
+	
+	/**
+	 * Checks if the DA is set to handle requests in this specific scope.
+	 * 
+	 * @param scope
+	 * 		The scope to be checked
+	 * @return
+	 * 		True if the DA supports that scope, false otherwise
+	 */
+	public boolean isInScope(String scope);
+	
+	/**
+	 * Builds the DAAdvertisementMessage.
+	 * 
+	 * @return
+	 * 		A DAAdvertisementMessage
+	 * @throws ServiceLocationException
+	 */
+	public DAAdvertisementMessage buildAdvert() throws ServiceLocationException;
+	
+	/**
+	 * Gets the statelessBootTimestamp of the DA
+	 * 
+	 * @return
+	 * 		statelessBootTimestamp
+	 * 		
+	 */
+	public int getStatelessBootTimestamp();
+	
+	/**
+	 * Sets the store that contains the registered services
+	 * 
+	 * @param store
+	 * 		An object that implements the ServiceStore interface
+	 */
+	public void setStore(ServiceStore store);
+	
+	/**
+	 * Checks if a service with the given url has been registered with this DA
+	 * 
+	 * @param service
+	 * 		The service to be checked
+	 * @return
+	 * 		True if a service with that url has been found in the store
+	 */
+	public boolean isKnownService(Service service);
+	
+	/**
+	 * Updates a registered service entry with new attributes.
+	 * 
+	 * @param reg
+	 * 			A ServiceRegistrationMessage which doesn't have the FRESH flag set.
+	 * @throws ServiceLocationException
+	 */
+	public void updateServiceEntry(ServiceRegistrationMessage reg) throws ServiceLocationException;
+	
+	/**
+	 * Register the service (if all checks pass) with the DA.
+	 * 
+	 * @param reg
+	 * 			A FRESH service registration message
+	 * @throws ServiceLocationException
+	 */
+	public void registerService(ServiceRegistrationMessage reg) throws ServiceLocationException;
+	
+	/**
+	 * Register the service (if all checks pass) with the DA. This method does not have to perform any
+	 * checks, it just registers the service.
+	 * @param reg
+	 * 			The service to be registered
+	 * @throws ServiceLocationException
+	 */
+	public void registerService(Service service) throws ServiceLocationException;
+	
+	/**
+	 * Deregisters a service from the DA.
+	 * 
+	 * @param dereg
+	 * 			The ServiceDeregistrationMessage asking for the deregistration.
+	 * @throws ServiceLocationException
+	 */
+	public void deregisterService(ServiceDeregistrationMessage dereg) throws ServiceLocationException;
+	
+	/**
+	 * Deregisters a service from the DA.
+	 * 
+	 * @param dereg
+	 * 			The Service to be deregistered.
+	 * @throws ServiceLocationException
+	 */
+	public void deregisterService(Service service) throws ServiceLocationException;
+	
+	/**
+	 * Lists all services currently registered with the DA.
+	 * 
+	 * @return
+	 * 		A List of the service urls of all registered services.
+	 */
+	public List<Service> listServices();
+	
+	/**
+	 * Shuts the DA down and sends a DAAdvert informing other SLP agents of this fact.
+	 * All registered services are lost on shutdown.
+	 */
+	public void shutdown();
+	
+	
+	/**
+	 * Returns the mappings of attributes of specific abstract SLP service types to their type (string, integer, boolean, opaquevalue or array thereof)
+	 * The method returns a copy of the actual type registry, changes made to the returned object are not
+	 * reflected in the actual type registry
+	 * 
+	 * @return
+	 * 		A copy of the attribute type registry
+	 * @throws ServiceLocationException
+	 * 		If not implemented
+	 */
+	public Map<String, Integer> getAttributeTypes() throws ServiceLocationException;
+}

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemon.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemonImpl.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemonImpl.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemonImpl.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemonImpl.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,1065 @@
+/* 
+ *   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.directory.slp.impl.da;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.directory.slp.Service;
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.ServiceStore;
+import org.apache.directory.slp.ServiceType;
+import org.apache.directory.slp.ServiceURL;
+import org.apache.directory.slp.extensions.AbstractExtension;
+import org.apache.directory.slp.extensions.AttributeListExtension;
+import org.apache.directory.slp.impl.AuthenticationBlock;
+import org.apache.directory.slp.impl.SLPCore;
+import org.apache.directory.slp.impl.SLPUtils;
+import org.apache.directory.slp.messages.AbstractSLPMessage;
+import org.apache.directory.slp.messages.AbstractSLPReplyMessage;
+import org.apache.directory.slp.messages.AbstractSLPRequestMessage;
+import org.apache.directory.slp.messages.AttributeReplyMessage;
+import org.apache.directory.slp.messages.AttributeRequestMessage;
+import org.apache.directory.slp.messages.DAAdvertisementMessage;
+import org.apache.directory.slp.messages.ServiceAcknowledgementMessage;
+import org.apache.directory.slp.messages.ServiceDeregistrationMessage;
+import org.apache.directory.slp.messages.ServiceRegistrationMessage;
+import org.apache.directory.slp.messages.ServiceReplyMessage;
+import org.apache.directory.slp.messages.ServiceRequestMessage;
+import org.apache.directory.slp.messages.ServiceTypeReplyMessage;
+import org.apache.directory.slp.messages.ServiceTypeRequestMessage;
+
+
+/**
+ * 
+ * @author Lorenz Breu
+ */
+public class DirectoryAgentDaemonImpl extends SLPCore implements DirectoryAgentDaemon{
+	
+	private static int statelessBootTimestamp;
+		
+	//The storage mechanism holding the information on registered services
+	private ServiceStore store;
+	
+	private boolean running = false;
+	
+	// The scopes supported by this DA
+	private List<String> myScopes = new ArrayList<String>();
+	
+	/**
+	 * Sorted set for disposal of services which lifetimes have expired:
+	 * 
+	 * Long expirationTimestamp -> String service.
+	 */
+	private SortedMap<Long,String> serviceDisposalQueue = new TreeMap<Long,String>();
+	
+	// The attributes of the DA as specified in the configuration
+	private String[] attributes = new String[]{};
+	
+	public DirectoryAgentDaemonImpl() throws Exception{
+		statelessBootTimestamp = (int) System.currentTimeMillis();
+		attributes = SLPUtils.stringToStringArray(SLPCore.CONFIG.getConfigDAAttributes(), ",");
+		// load the scopes this DA is responsible for
+        myScopes = SLPUtils.stringToList(SLPCore.CONFIG.getScopes().toLowerCase(), ",");
+        running=true;
+               
+        new UnsolicitedAdvertisementThread();
+		new ServiceDisposalThread();
+		SLPCore.platform.logDebug("jSLP directory agent starting...");
+		
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#listServices()
+	 */
+	public List<Service> listServices(){
+		try {
+			return store.listServices();
+		} catch (ServiceLocationException sle){
+			return new ArrayList<Service>();
+		}
+	}
+
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#isInScope(java.lang.String)
+	 */
+	public boolean isInScope(String scope){
+		for (String s: myScopes){
+			if (s.toLowerCase().equals(scope.toLowerCase())){
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#isKnownService(ch.ethz.iks.slp.impl.Service)
+	 */
+	public boolean isKnownService(Service service){
+		return (store.containsService(service.getURL().toString()));
+	}
+
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#handleMessage(ch.ethz.iks.slp.messages.AbstractSLPMessage)
+	 */
+	public AbstractSLPReplyMessage handleMessage(AbstractSLPMessage message) throws ServiceLocationException{
+		if (message == null || !(message instanceof AbstractSLPMessage)) {
+			return null;
+		}
+		AbstractSLPMessage msg = (AbstractSLPMessage) message;
+		boolean scopeOverlap = stripUnsupportedScopes(msg);
+		switch (msg.getFuncID()) {
+		case AbstractSLPMessage.DAADVERT:
+			// for now drop message as the handler does the necessary things for UA/SA
+				
+			//TODO: keep a list of other DAs for coordination, replication, etc...
+			
+			return null;
+	
+			// reply messages not care about, we do...
+		case AbstractSLPMessage.ATTRRPLY:
+		case AbstractSLPMessage.SRVRPLY:
+		case AbstractSLPMessage.SRVTYPERPLY:
+			
+			return null;
+			// request messages
+		case AbstractSLPMessage.SRVRQST:
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				ServiceReplyMessage servreply = new ServiceReplyMessage();
+				servreply.setXid(msg.getXid());
+				servreply.setLocale(msg.getLocale());
+				servreply.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD);
+				return servreply;
+			}
+			
+			ServiceRequestMessage srvReq = (ServiceRequestMessage) msg;
+			if (!scopeOverlap){
+				return null;
+			}
+			if (srvReq.getServiceType().toString().equals("service:directory-agent")){
+				for (String s:srvReq.getScopes()){
+					if (isInScope(s)){
+						try {
+							DAAdvertisementMessage advert = buildAdvert();
+							advert.setXid(srvReq.getXid());
+							if (SLPCore.CONFIG.getSecurityEnabled()){
+								List<String> mySpis = SLPUtils.stringToList(SLPCore.CONFIG.getSPI(), ",");
+								boolean knownSpi = false;
+								for (String spi : srvReq.getSPIs()){
+									if (mySpis.contains(spi)){
+										knownSpi = true;
+										break;
+									}
+								}
+								if (knownSpi){
+									advert.setSPIs(SLPUtils.stringToStringArray(SLPCore.CONFIG.getSPI(), ","));
+									advert.sign(SLPCore.CONFIG.getSPI());
+									return advert;
+								}
+								// spi not supported
+								advert.setErrorCode(ServiceLocationException.AUTHENTICATION_UNKNOWN);
+								
+								
+							}
+							return advert;
+						} catch (ServiceLocationException sle){
+							// something went wrong internally, can't reply :(
+							return null;
+						}
+					}
+				}
+				// scopes not supported, drop silently
+				return null;
+			}// end of directory-agent lookup reply
+			
+			
+			ServiceReplyMessage servreply = new ServiceReplyMessage();
+			servreply.setXid(srvReq.getXid());
+			servreply.setLocale(srvReq.getLocale());
+			
+			if (SLPCore.CONFIG.getSecurityEnabled()) {
+				boolean knownSpi = false;
+				List<String> knownSpis = SLPUtils.stringToList(SLPCore.CONFIG.getSPI(), ",");
+				for (String s : srvReq.getSPIs()){
+					if (knownSpis.contains(s)){
+						knownSpi = true;
+						break;
+					}
+				}
+				if (!knownSpi){
+					servreply.setErrorCode(ServiceLocationException.AUTHENTICATION_UNKNOWN);
+					return servreply;
+				}
+			}
+			List<String> overlap = new ArrayList<String>();
+			for (String scope : srvReq.getScopes()){
+				if (isInScope(scope)){
+					overlap.add(scope);
+				}
+			}
+			List<ServiceURL> results = new ArrayList<ServiceURL>();
+			List<AbstractExtension> extensions = new ArrayList<AbstractExtension>();
+			List<Service> services = store.getServices(srvReq.getServiceType().toString(),srvReq.getPredicate(),overlap.toArray(new String[]{}));
+			for (Service s : services){
+				if (!results.contains(s.getURL())){
+					results.add(s.getURL());
+					if (srvReq.hasExtensionType(AbstractExtension.ATTRIBUTE_LIST_EXTENSION)){
+						AttributeListExtension ale = new AttributeListExtension(s.getURL().toString(),SLPUtils.dictToString(s.getAttributesAsStringDict()));
+						extensions.add(ale);
+					}
+				}
+			}
+			
+			/*
+			 * if there is no result, don't send a reply. This causes the SA to
+			 * get the same message at least two more times but the RFC strictly
+			 * demands this for multicast requests
+			 */
+			if (results.size() == 0 && srvReq.isMulticast()) {
+				return null;
+			}
+			
+			servreply.setErrorCode((short) 0);
+			servreply.setServiceURLs(results.toArray(new ServiceURL[]{}));
+			servreply.setExtensions(extensions.toArray(new AbstractExtension[]{}));
+			
+			if (SLPCore.CONFIG.getSecurityEnabled()) {
+				servreply.sign(SLPUtils.arrayToString(srvReq.getSPIs(),","));
+			}
+			
+			return servreply;
+			
+		case AbstractSLPMessage.ATTRRQST:
+			
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				AttributeReplyMessage attreply = new AttributeReplyMessage();
+				attreply.setXid(msg.getXid());
+				attreply.setLocale(msg.getLocale());
+				attreply.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD);
+				return attreply;
+			}
+			
+			AttributeRequestMessage attreq = (AttributeRequestMessage) msg;
+			if (!scopeOverlap){
+				return null;
+			}
+			//moved this out of the for loop for performance
+//			 the request can either be for a ServiceURL or a ServiceType
+			Object reqService;
+			boolean fullurl = false;
+			if ((attreq.getServiceUrl().getURL().indexOf("//") == -1) || (attreq.getServiceUrl().getHost().equals("nullnull"))) {
+				reqService = attreq.getServiceUrl().getServiceType();
+			} else {
+				fullurl = true;
+				reqService = new ServiceURL(attreq.getServiceUrl().getURL(), 0);
+			}
+			String[] attResult = store.getAttributes(reqService.toString(),attreq.getTags(), attreq.getScopes());
+			if (!fullurl){
+				attResult=SLPUtils.mergeAttributes(attResult);
+			}
+			AttributeReplyMessage attrep = new AttributeReplyMessage();
+			attrep.setAttributes(SLPUtils.mergeAttributes(attResult));
+			attrep.setLocale(attreq.getLocale());
+			attrep.setXid(attreq.getXid());
+			attrep.setAuthBlocks(new AuthenticationBlock[0]);
+			attrep.setErrorCode((short)0);
+			if (attreq.getSPIs().length>0 && !fullurl){
+				attrep.setAttributes(new String[]{});
+				attrep.setErrorCode(ServiceLocationException.AUTHENTICATION_FAILED);
+			}
+			
+	
+
+			if (SLPCore.CONFIG.getSecurityEnabled()) {
+				attrep.sign(SLPUtils.arrayToString(attreq.getSPIs(),","));
+			}
+			return attrep;
+		case AbstractSLPMessage.SRVTYPERQST:
+			
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				ServiceTypeReplyMessage streply = new ServiceTypeReplyMessage();
+				streply.setXid(msg.getXid());
+				streply.setLocale(msg.getLocale());
+				streply.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD);
+				return streply;
+			}
+			
+			ServiceTypeRequestMessage streq = (ServiceTypeRequestMessage) msg;
+			if (!scopeOverlap){
+				return null;
+			}
+			ServiceType[] result = store.getServiceTypes(streq.getScopes(),streq.getNamingAuthority());
+			
+			
+			ServiceTypeReplyMessage streply = new ServiceTypeReplyMessage();
+			streply.setXid(streq.getXid());
+			streply.setLocale(streq.getLocale());
+			streply.setErrorCode((short)0);
+			streply.setServiceTypes(result);
+			return streply;
+			
+			// registration and deregistration
+		case AbstractSLPMessage.SRVREG:
+			// process the message and check if everything is ok.
+			// then cache the service.
+			
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				ServiceAcknowledgementMessage ack = new ServiceAcknowledgementMessage();
+				ack.setXid(msg.getXid());
+				ack.setLocale(msg.getLocale());
+				ack.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD);
+				return ack;
+			}
+			
+			ServiceRegistrationMessage reg = (ServiceRegistrationMessage) msg;
+			
+			ServiceAcknowledgementMessage ack = new ServiceAcknowledgementMessage();
+			ack.setXid(reg.getXid());
+			ack.setErrorCode((short) 0);
+			
+			if (!reg.checkAttributeListValidity()){
+				ack.setErrorCode(ServiceLocationException.INVALID_REGISTRATION);
+				return ack;
+			}
+			
+			Service service = new Service(reg);
+			boolean found = false;
+			for (int i=0;i<reg.getScopes().length;i++) {
+				String scope = reg.getScopes()[i];
+				scope = scope.toLowerCase().trim();
+				
+				// is the DA configured for this scope?
+				if (myScopes.contains(scope)){
+					found = true;
+					break;
+				}
+				
+			}
+			
+			if (!found){
+				// reply with an error if not:
+				ack.setErrorCode(ServiceLocationException.SCOPE_NOT_SUPPORTED);
+				return ack;
+			}
+				
+			try {
+				// is this a fresh registration, or an incremental one?
+				boolean exists = isKnownService(service);
+				if (exists){
+					updateServiceEntry(reg);
+				} else {
+					registerService(reg);
+				}
+			} catch (ServiceLocationException sle){
+				ack.setErrorCode(sle.getErrorCode());
+			}
+			
+			return ack;
+	
+				
+		
+		
+	
+		case AbstractSLPMessage.SRVDEREG:
+//			 process the message and check if everything is ok.
+			// then cache the service.
+			
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				ack = new ServiceAcknowledgementMessage();
+				ack.setXid(msg.getXid());
+				ack.setLocale(msg.getLocale());
+				ack.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD);
+				return ack;
+			}
+			
+			ServiceDeregistrationMessage dereg = (ServiceDeregistrationMessage) msg;
+			
+			ack = new ServiceAcknowledgementMessage();
+			ack.setXid(dereg.getXid());
+			ack.setErrorCode((short) 0);
+						
+			found = false;
+			for (int i=0;i<dereg.getScopes().length;i++) {
+				String scope = dereg.getScopes()[i];
+				scope = scope.toLowerCase().trim();
+				
+				// is the DA configured for this scope?
+				if (myScopes.contains(scope)){
+					found = true;
+					break;
+				}
+				
+			}
+			
+			if (!found){
+				// reply with an error if not:
+				ack.setErrorCode(ServiceLocationException.SCOPE_NOT_SUPPORTED);
+				return ack;
+			}
+				
+			try {
+				deregisterService(dereg);
+			} catch (ServiceLocationException sle){
+				ack.setErrorCode(sle.getErrorCode());
+			}
+			
+			return ack;
+			
+		case AbstractSLPMessage.SRVACK:
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				return null;
+			}
+			final AbstractSLPReplyMessage rep = (AbstractSLPReplyMessage) msg;
+			if (rep.getErrorCode() != 0) {
+				SLPCore.platform.logWarning(msg.getSource()
+							+ " replied with error code " + rep.getErrorCode()
+							+ " (" + rep + ")");
+			}
+			SLPCore.addReply(msg, new InetSocketAddress(msg.getSource(),msg.getPort()));
+			return null;	
+			
+		default:
+			
+			return null;
+		}
+	}
+
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#setStore(ch.ethz.iks.slp.impl.da.ServiceStore)
+	 */
+	public void setStore(ServiceStore store){
+		// TODO: should dynamic switchover be allowed? in this case service must be extracted from the
+		// old store and injected into the new one...
+		this.store = store;
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#registerService(ch.ethz.iks.slp.messages.ServiceRegistrationMessage)
+	 */
+	public void registerService(ServiceRegistrationMessage reg) throws ServiceLocationException{
+		// test for incremental registration has been done
+		if (SLPCore.CONFIG.getSecurityEnabled()){
+			// message has been authenticated
+			// dump all auth blocks that are not understood
+			List<AuthenticationBlock> auth = new ArrayList<AuthenticationBlock>();
+			List<String> mySpis = SLPUtils.stringToList(SLPCore.CONFIG.getSPI(),",");
+			for (AuthenticationBlock b : reg.getAuthBlocks()){
+				if (mySpis.contains(b.getSpi())){
+					auth.add(b);
+				}
+			}
+			reg.setAuthBlocks(auth.toArray(new AuthenticationBlock[]{}));
+		}
+		
+		
+		
+		// first check if FRESH is NOT set but no service has been registered to update...
+		if (!reg.isFresh()){
+			throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE,"Tried to register a new service without the FRESH flag set");
+		}
+		
+		
+		Service service = new Service(reg);
+		
+		
+		store.storeService(service);
+		
+		if (reg.getServiceURL().getLifetime() > ServiceURL.LIFETIME_PERMANENT) {
+			synchronized (serviceDisposalQueue) {
+				long next = System.currentTimeMillis()
+				+ (reg.getServiceURL().getLifetime() * 1000);
+				ArrayList<Long> keys = new ArrayList<Long>(serviceDisposalQueue
+						.keySet());
+				for (Iterator iter = keys.iterator(); iter.hasNext();) {
+					Object key = iter.next();
+					if (serviceDisposalQueue.get(key).equals(reg.getServiceURL().toString())) {
+						serviceDisposalQueue.remove(key);
+					}
+				}
+				serviceDisposalQueue.put(new Long(next), reg.getServiceURL().toString());
+				serviceDisposalQueue.notifyAll();
+			}
+		}
+
+		SLPCore.platform.logTraceReg("REGISTERED " + reg.getServiceURL());
+
+		// TODO: pass on registration to fellow DAs	???
+
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#registerService(ch.ethz.iks.slp.impl.Service)
+	 */
+	public void registerService(Service service) throws ServiceLocationException{
+		// this call should only be made through the DirectoryAgent interface
+		// no checks are made
+		
+		store.storeService(service);
+		
+		if (service.getURL().getLifetime() > ServiceURL.LIFETIME_PERMANENT) {
+			synchronized (serviceDisposalQueue) {
+				long next = System.currentTimeMillis()
+				+ (service.getURL().getLifetime() * 1000);
+				ArrayList<Long> keys = new ArrayList<Long>(serviceDisposalQueue
+						.keySet());
+				for (Iterator iter = keys.iterator(); iter.hasNext();) {
+					Object key = iter.next();
+					if (serviceDisposalQueue.get(key).equals(service.getURL().toString())) {
+						serviceDisposalQueue.remove(key);
+					}
+				}
+				serviceDisposalQueue.put(new Long(next), service.getURL().toString());
+				serviceDisposalQueue.notifyAll();
+			}
+		}
+
+		SLPCore.platform.logTraceReg("REGISTERED " + service.getURL());
+
+		// TODO: pass on registration to fellow DAs	???
+
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#deregisterService(ch.ethz.iks.slp.messages.ServiceDeregistrationMessage)
+	 */
+	public void deregisterService(ServiceDeregistrationMessage dereg) throws ServiceLocationException{
+		
+		Service registeredService = store.getService(dereg.getServiceURL().toString());
+		
+		if (registeredService==null){
+			// no specs for this case given in RFC2608...
+			throw new ServiceLocationException(ServiceLocationException.INVALID_REGISTRATION,"No such Service registered");
+		}
+		
+		//check if the <scope-list> matches the one used in previous registration
+		List<String> previousScopes = registeredService.getScopes();
+		if (previousScopes.size()!=dereg.getScopes().length){
+			throw new ServiceLocationException(ServiceLocationException.SCOPE_NOT_SUPPORTED, "Tried to deregister an existing entry registered with a different scope-list");
+		}
+		for (String scope: dereg.getScopes()){
+			if (!previousScopes.contains(scope.toLowerCase().trim())){
+				throw new ServiceLocationException(ServiceLocationException.SCOPE_NOT_SUPPORTED, "Tried to deregister an existing entry registered with a different scope-list");
+			}
+		}
+		
+		// check if tag-list is non-zero, in which case only the attributes in the tag list are deleted
+		if (dereg.getTags().length>0){
+			if (registeredService.getAuthBlocks().length>0){
+				throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_FAILED, "Tried to deregister attributes of an existing entry registered with authentication blocks");
+			}
+			
+			Dictionary<String,String> attributes = registeredService.getAttributesAsStringDict();
+			// find all matching attributes in the services attribute dictionary...
+			List<String> matches = SLPUtils.findMatches(SLPUtils.arrayToList(dereg.getTags()), attributes);
+			// and extract the attribute types...
+			for (String s : matches){
+				// s is of form "(ATTRIBUTE)" or "(ATTRIBUTE=VALUE)"
+				int end = s.length()-1;
+				if (s.indexOf("=")>-1){
+					end = s.indexOf("=");
+				}
+				String q = s.substring(1,end);
+				registeredService.getAttributes().remove(q);
+			}
+			
+			
+			
+			store.deleteService(dereg.getServiceURL().toString());
+			store.storeService(registeredService);
+			SLPCore.platform.logTraceReg("DEREGISTERED ATTRIBUTES ["+dereg.getTags()+"] from " + dereg.getServiceURL());
+			return;
+		}
+		
+		
+		if (registeredService.getURL().getAuthBlocks().length>0){
+			// unsure about what RFC 2608 means in the part concerning this...
+			
+			// fetch all spis for this reg message
+			AuthenticationBlock[] authBlocks = dereg.getServiceURL().getAuthBlocks();
+			String[] spis = new String[authBlocks.length];
+			for (int i = 0; i< authBlocks.length; i++){
+				spis[i] = authBlocks[i].getSpi();
+			}
+			// now get the spis of the stored service
+			AuthenticationBlock[] registeredAuthBlocks = registeredService.getURL().getAuthBlocks();
+			String[] registeredSpis = new String[registeredAuthBlocks.length];
+			for (int i = 0; i< registeredAuthBlocks.length; i++){
+				registeredSpis[i] = registeredAuthBlocks[i].getSpi();
+			}
+			if (registeredSpis.length!=spis.length){
+				throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_FAILED,"SPIs did not match existing entry");
+			}
+			for (int i = 0;i<spis.length;i++){
+				boolean found = false;
+				// yes, this runs in O(n²), may be fixed later if possible
+				for (int j=0;j<registeredSpis.length;j++){
+					if (spis[i].equals(registeredSpis[j])){
+						found=true;
+					}
+				}
+				if (!found){
+					throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_FAILED,"SPIs did not match existing entry");
+				}
+			}
+			
+		} // end of security enabled block
+				
+		store.deleteService(dereg.getServiceURL().toString());
+		
+		serviceDisposalQueue.values().remove(dereg.getServiceURL().toString());
+	
+
+		SLPCore.platform.logTraceReg("DEREGISTERED " + dereg.getServiceURL());
+
+		// TODO: pass on deregistration to fellow DAs	???
+	}
+	
+	
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#deregisterService(ch.ethz.iks.slp.impl.Service)
+	 */
+	public void deregisterService(Service service) throws ServiceLocationException{
+		
+		store.deleteService(service.getURL().toString());
+			
+		serviceDisposalQueue.values().remove(service.getURL().toString());
+	
+		SLPCore.platform.logTraceReg("DEREGISTERED " + service.getURL());
+
+		// TODO: pass on deregistration to fellow DAs	???
+	}
+	
+	
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#updateServiceEntry(ch.ethz.iks.slp.messages.ServiceRegistrationMessage)
+	 */
+	public void updateServiceEntry(ServiceRegistrationMessage reg) throws ServiceLocationException{
+		// this is an update, so let's first fetch the existing service
+		Service registeredService = store.getService(reg.getServiceURL().toString());
+		
+		// if the resh flag is set, overwrite the existing entry
+		if (reg.isFresh()){
+			try {
+//				 check if the <scope-list> matches the one used in previous registration
+				List<String> previousScopes = registeredService.getScopes();
+				if (previousScopes.size()!=reg.getScopes().length){
+					throw new ServiceLocationException(ServiceLocationException.SCOPE_NOT_SUPPORTED, "Tried to update an existing entry registered with a different scope-list");
+				}
+				for (String scope: reg.getScopes()){
+					if (!previousScopes.contains(scope.toLowerCase().trim())){
+						throw new ServiceLocationException(ServiceLocationException.SCOPE_NOT_SUPPORTED, "Tried to update an existing entry registered with a different scope-list");
+					}
+				}
+				//	check if the slp spis are identical to the ones previously used
+				if (SLPCore.CONFIG.getSecurityEnabled()){
+					// fetch all spis for this reg message
+					AuthenticationBlock[] authBlocks = reg.getAuthBlocks();
+					String[] spis = new String[authBlocks.length];
+					for (int i = 0; i< authBlocks.length; i++){
+						spis[i] = authBlocks[i].getSpi();
+					}
+					// now get the spis of the stored service
+					AuthenticationBlock[] registeredAuthBlocks = registeredService.getAuthBlocks();
+					String[] registeredSpis = new String[registeredAuthBlocks.length];
+					for (int i = 0; i< registeredAuthBlocks.length; i++){
+						registeredSpis[i] = registeredAuthBlocks[i].getSpi();
+					}
+					if (registeredSpis.length!=spis.length){
+						throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE,"SPIs did not match existing entry");
+					}
+					for (int i = 0;i<spis.length;i++){
+						boolean found = false;
+						// yes, this runs in O(n²), may be fixed later if possible
+						for (int j=0;j<registeredSpis.length;j++){
+							if (spis[i].equals(registeredSpis[j])){
+								found=true;
+							}
+						}
+						if (!found){
+							throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_ABSENT,"SPIs did not match existing entry");
+						}
+					}
+					
+				}
+				
+				// scope checks out, security checks out, replace it
+				
+				store.deleteService(reg.getServiceURL().toString());
+				store.storeService(new Service(reg));
+				SLPCore.platform.logTraceReg("REREGISTERED " + reg.getServiceURL());
+				return;
+			} catch (ServiceLocationException sle){
+				throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"Problems updating service "+reg.getServiceURL());
+			}
+		} else {
+			// incremental update required
+			
+			// first: check if there even exists a previous entry
+			if (registeredService==null){
+				throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE, "Tried to update a non-existing entry");
+			}
+			
+			// second: check if the service was previously registered with auth blocks
+			if (registeredService.getAuthBlocks().length > 0){
+				throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_FAILED, "Tried to update an existing entry registered with AuthBlocks");
+			}
+			
+			// third: check if the <scope-list> matches the one used in previous registration
+			List<String> previousScopes = registeredService.getScopes();
+			if (previousScopes.size()!=reg.getScopes().length){
+				throw new ServiceLocationException(ServiceLocationException.SCOPE_NOT_SUPPORTED, "Tried to update an existing entry registered with a different scope-list");
+			}
+			for (String scope: reg.getScopes()){
+				if (!previousScopes.contains(scope.toLowerCase().trim())){
+					throw new ServiceLocationException(ServiceLocationException.SCOPE_NOT_SUPPORTED, "Tried to update an existing entry registered with a different scope-list");
+				}
+			}
+			
+			// fourth: check if the service-type is the same as previously registered
+			if (!registeredService.getURL().getServiceType().equals(reg.getServiceType())){
+				throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE, "Tried to update an existing entry registered with a different service type");
+			}
+			
+			// finally, check if the slp spis are identical to the ones previously used
+			if (SLPCore.CONFIG.getSecurityEnabled()){
+				// fetch all spis for this reg message
+				AuthenticationBlock[] authBlocks = reg.getAuthBlocks();
+				String[] spis = new String[authBlocks.length];
+				for (int i = 0; i< authBlocks.length; i++){
+					spis[i] = authBlocks[i].getSpi();
+				}
+				// now get the spis of the stored service
+				AuthenticationBlock[] registeredAuthBlocks = registeredService.getAuthBlocks();
+				String[] registeredSpis = new String[registeredAuthBlocks.length];
+				for (int i = 0; i< registeredAuthBlocks.length; i++){
+					registeredSpis[i] = registeredAuthBlocks[i].getSpi();
+				}
+				if (registeredSpis.length!=spis.length){
+					throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE,"SPIs did not match existing entry");
+				}
+				for (int i = 0;i<spis.length;i++){
+					boolean found = false;
+					// yes, this runs in O(n²), may be fixed later if possible
+					for (int j=0;j<registeredSpis.length;j++){
+						if (spis[i].equals(registeredSpis[j])){
+							found=true;
+						}
+					}
+					if (!found){
+						throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_ABSENT,"SPIs did not match existing entry");
+					}
+				}
+				
+			} // end of security enabled block
+							
+
+			
+			Dictionary<String,Object> registeredAttributes = registeredService.getAttributes();
+			Dictionary<String,Object> newAttributes = SLPUtils.stringArrayToDict(reg.getAttrList());
+			Enumeration<String> keys = newAttributes.keys();
+			while (keys.hasMoreElements()){
+				String key = keys.nextElement();
+				registeredAttributes.remove(key);
+				registeredAttributes.put(key, newAttributes.get(key));
+			}
+			registeredService.setAttributes(registeredAttributes);
+		} // end of incremental update
+		
+		//		process the new lifetime
+		if (reg.getServiceURL().getLifetime() > ServiceURL.LIFETIME_PERMANENT) {
+			synchronized (serviceDisposalQueue) {
+				long next = System.currentTimeMillis()
+						+ (reg.getServiceURL().getLifetime() * 1000);
+				ArrayList<Long> disposalKeys = new ArrayList<Long>(serviceDisposalQueue.keySet());
+				for (Long k:disposalKeys) {
+					if (serviceDisposalQueue.get(k).equals(reg.getServiceURL().toString())) {
+						serviceDisposalQueue.remove(k);
+					}
+				}
+				serviceDisposalQueue.put(new Long(next), reg.getServiceURL().toString());
+				serviceDisposalQueue.notifyAll();
+			}
+		}
+		store.deleteService(reg.getServiceURL().toString());
+		store.storeService(registeredService);
+		SLPCore.platform.logTraceReg("REGISTERED INCREMENTALLY " + reg.getServiceURL());
+		return;
+	}
+
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#buildAdvert()
+	 */
+	public DAAdvertisementMessage buildAdvert() throws ServiceLocationException{
+		DAAdvertisementMessage advert = new DAAdvertisementMessage();
+		// always return 0... what errors have to be handled here?
+		advert.setErrorCode((short) 0);
+		advert.setXid((short) 0);
+		advert.setStatelessBootTimestamp(statelessBootTimestamp);
+		advert.setAttributes(attributes);
+		//TODO: add min-refresh-interval here
+		ServiceURL myService = new ServiceURL("service:directory-agent://"+SLPCore.getMyIP().getHostAddress(),0);
+		advert.setServiceURL(myService);
+		advert.setOrigURL("service:directory-agent://"+SLPCore.getMyIP().getHostAddress());
+		advert.setScopes(SLPUtils.stringToStringArray(SLPCore.CONFIG.getScopes(), ","));
+		
+		return advert;
+		
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#getStatelessBootTimestamp()
+	 */
+	public int getStatelessBootTimestamp(){
+		return statelessBootTimestamp;
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#shutdown()
+	 */
+	public void shutdown(){
+		try {
+			if (running){
+				running = false;
+				SLPCore.platform.logDebug("jSLP Directory Agent shutting down...");
+				DAAdvertisementMessage advert = buildAdvert();
+				advert.setStatelessBootTimestamp(0);
+				SLPCore.sendUnicastMessage(advert, new InetSocketAddress(SLPCore.MCAST_ADDRESS,SLP_PORT), false);
+				SLPCore.shutdownDirectoryAgent();
+				//store.clear();
+			}
+			
+		} catch (ServiceLocationException sle){
+			SLPCore.platform.logError("Error while closing down DA", sle);
+		}
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.impl.da.DirectoryAgentDaemon#getAttributeTypes()
+	 */
+	public Map<String, Integer> getAttributeTypes() throws ServiceLocationException{
+		return store.getAttributeTypes();
+	}
+	
+	
+	/**
+	 * This removes all unsupported scopes from the list of scopes in a message. After processing a message
+	 * the scopelist in the message includes only those scopes the DA also supports.
+	 * 
+	 * @param msg
+	 * 			An AbstractSLPMessage, such as a ServiceRegistrationMessage
+	 * @return
+	 * 			True if the list of supported scopes still contains an entry, false if none of the scopes
+	 * 			listed in the message are supported by the DA.
+	 */
+	private boolean stripUnsupportedScopes(AbstractSLPMessage msg){
+		if (msg instanceof ServiceRegistrationMessage){
+			ServiceRegistrationMessage reg = (ServiceRegistrationMessage) msg;
+			List<String> supportedScopes = new ArrayList<String>();
+			for (String s: reg.getScopes()){
+				if (myScopes.contains(s.toLowerCase().trim())){
+					supportedScopes.add(s.toLowerCase().trim());
+				}
+			}
+			reg.setScopes(SLPUtils.listToStringArray(supportedScopes));
+			return (supportedScopes.size()>0);
+		}
+		if (msg instanceof ServiceDeregistrationMessage){
+			ServiceDeregistrationMessage reg = (ServiceDeregistrationMessage) msg;
+			List<String> supportedScopes = new ArrayList<String>();
+			for (String s: reg.getScopes()){
+				if (myScopes.contains(s.toLowerCase().trim())){
+					supportedScopes.add(s.toLowerCase().trim());
+				}
+			}
+			reg.setScopes(SLPUtils.listToStringArray(supportedScopes));
+			return (supportedScopes.size()>0);
+		}
+		
+		if (msg instanceof AbstractSLPRequestMessage){
+			AbstractSLPRequestMessage req = (AbstractSLPRequestMessage) msg;
+			List<String> supportedScopes = new ArrayList<String>();
+			for (String s: req.getScopes()){
+				if (myScopes.contains(s.toLowerCase().trim())){
+					supportedScopes.add(s.toLowerCase().trim());
+				}
+			}
+			req.setScopes(SLPUtils.listToStringArray(supportedScopes));
+			return (supportedScopes.size()>0);
+		}
+		return true;
+	}
+
+	
+	
+	
+	/**
+	 * service disposal thread. Removes services from the local registry when
+	 * their lifetime has expired.
+	 */
+	private final class ServiceDisposalThread extends Thread {
+
+		/**
+		 * create and start a new instance of this thread.
+		 * 
+		 */
+		private ServiceDisposalThread() {
+			super("ServiceDisposalThread");
+			start();
+		}
+
+		/**
+		 * thread's main loop.
+		 */
+		public void run() {
+			try {
+				while (running) {
+					synchronized (serviceDisposalQueue) {
+						if (serviceDisposalQueue.isEmpty()) {
+							// nothing to do, sleep until something arrives
+							SLPCore.platform
+										.logDebug("ServiceDisposalThread sleeping ...");
+							serviceDisposalQueue.wait();
+						} else {
+							// we have work, do everything that is due
+							Long nextActivity;
+							while (!serviceDisposalQueue.isEmpty()
+									&& (nextActivity = ((Long) serviceDisposalQueue
+											.firstKey())).longValue() <= System
+											.currentTimeMillis()) {
+							
+								String service =  serviceDisposalQueue
+										.get(nextActivity);
+								
+								try {
+									store.deleteService(service);
+								} catch (ServiceLocationException sle) {
+									SLPCore.platform.logError(sle
+												.getMessage(), sle
+												.fillInStackTrace());
+								}
+								SLPCore.platform
+											.logTraceReg("disposed service "
+													+ service);
+								serviceDisposalQueue.remove(nextActivity);
+							}
+							if (!serviceDisposalQueue.isEmpty()) {
+								/*
+								 * there are some activities in the future,
+								 * sleep until the first activity becomes due
+								 */
+								nextActivity = ((Long) serviceDisposalQueue
+										.firstKey());
+								long waitTime = nextActivity.longValue()
+										- System.currentTimeMillis();
+								if (waitTime > 0) {
+									SLPCore.platform
+												.logDebug("sleeping for "
+														+ waitTime / 1000
+														+ " seconds.");
+									serviceDisposalQueue.wait(waitTime);
+								}
+							}
+						}
+					}
+				}
+			} catch (InterruptedException ie) {
+				// let the thread stop.
+			}
+		}
+	}
+	
+	
+	/**
+	 * thread for unsolicited DAAdverts. This thread periodically sends out DAAdvertisements
+	 */
+	private final class UnsolicitedAdvertisementThread extends Thread {
+
+		private long lastUnsolicitedAdvertisement = 0;
+		
+		/**
+		 * create and start a new instance of this thread.
+		 * 
+		 */
+		private UnsolicitedAdvertisementThread() {
+			super("UnsolicitedAdvertisementThread");
+			start();
+		}
+
+		/**
+		 * thread's main loop.
+		 */
+		public void run() {
+			long remaining;
+			while (running){
+				try {
+					if ((remaining=SLPCore.CONFIG.getConfigDABeat()-System.currentTimeMillis()+lastUnsolicitedAdvertisement)<0){
+						DAAdvertisementMessage advert = buildAdvert();
+						if (SLPCore.CONFIG.getSecurityEnabled()){
+							advert.setSPIs(SLPUtils.stringToStringArray(SLPCore.CONFIG.getSPI(),","));
+							advert.sign(SLPCore.CONFIG.getSPI());
+							if (advert.getSize()>CONFIG.getMTU()){
+								//crap, too big, have to send a bunch of individual small ones...
+								String[] spis = SLPUtils.stringToStringArray(SLPCore.CONFIG.getSPI(), ",");
+								for (String spi : spis){
+									advert.setSPIs(new String[]{spi});
+									advert.sign(spi);
+									InetSocketAddress addr = new InetSocketAddress(SLP_MCAST_ADDRESS,SLP_PORT);
+									SLPCore.sendUnicastMessage(advert, addr, false);
+								}
+								lastUnsolicitedAdvertisement = System.currentTimeMillis();
+								continue;
+							}
+						}
+						InetSocketAddress addr = new InetSocketAddress(SLP_MCAST_ADDRESS,SLP_PORT);
+						SLPCore.sendUnicastMessage(advert, addr, false);
+						lastUnsolicitedAdvertisement = System.currentTimeMillis();
+					} else {
+						Thread.sleep(remaining);
+					}
+				}catch (Exception e){
+					continue;
+				}
+			}
+		}
+	}
+	
+	
+	
+}

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentDaemonImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentImpl.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentImpl.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentImpl.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentImpl.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,233 @@
+/* 
+ *   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.directory.slp.impl.da;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.slp.DirectoryAgent;
+import org.apache.directory.slp.Service;
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.ServiceStore;
+import org.apache.directory.slp.ServiceURL;
+import org.apache.directory.slp.impl.SLPCore;
+import org.apache.directory.slp.impl.SLPUtils;
+import org.apache.directory.slp.messages.ServiceDeregistrationMessage;
+import org.apache.directory.slp.messages.ServiceRegistrationMessage;
+
+
+/**
+ * 
+ * @author Lorenz Breu
+ */
+public class DirectoryAgentImpl implements DirectoryAgent{
+
+	public DirectoryAgentImpl(){
+		
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#listServices()
+	 */
+	public List<Service> listServices() {
+		return SLPCore.daDaemon.listServices();
+	}
+
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#shutdown()
+	 */
+	public void shutdown() {
+		SLPCore.getDirectoryAgentDaemon().shutdown();
+		
+	}
+
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#registerService(ch.ethz.iks.slp.messages.ServiceRegistrationMessage)
+	 */
+	public void registerService(ServiceRegistrationMessage reg) throws ServiceLocationException{
+		SLPCore.getDirectoryAgentDaemon().registerService(reg);
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#registerService(ch.ethz.iks.slp.Service)
+	 */
+	public void registerService(Service service) throws ServiceLocationException {
+		SLPCore.getDirectoryAgentDaemon().registerService(service);
+	}
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#deregisterService(ch.ethz.iks.slp.messages.ServiceDeregistrationMessage)
+	 */
+	public void deregisterService(ServiceDeregistrationMessage dereg) throws ServiceLocationException{
+		SLPCore.getDirectoryAgentDaemon().deregisterService(dereg);
+		
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#deregisterService(ch.ethz.iks.slp.Service)
+	 */
+	public void deregisterService(Service service) throws ServiceLocationException{
+		SLPCore.getDirectoryAgentDaemon().deregisterService(service);
+	}
+	
+	
+//	#comment
+//	;comment
+//	service-url,language-tag,lifetime,[service-type]<newline>
+//	"scopes="[scope-list]<newline>
+//	[attrid]"="val1<newline>
+//	[attrid]"="val1,val2,val3<newline>
+//	<newline>
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#registerServicesFromFile(java.io.File)
+	 */
+	public void registerServicesFromFile(File file){
+		try {
+			BufferedReader input =  new BufferedReader(new FileReader(file));
+			String line = null;
+			boolean parsingService = false;
+			Service service = null;
+			List<String> attributes = new ArrayList<String>();
+			while ((line = input.readLine()) != null){
+				if (line.startsWith("#") || line.startsWith(";")){
+					// just a comment
+					continue;
+				}
+				if (!parsingService){
+					String[] fields = line.split(",");
+					String url = fields[0];
+					//TODO: implement correct localization
+					//String lang = fields[1];
+					int lifetime = Integer.parseInt(fields[2]);
+					if (fields.length==4){
+						String type = fields[3];
+						service = new Service(new ServiceURL(type, lifetime));
+					} else {
+						service = new Service(new ServiceURL(url,lifetime));
+					}
+					parsingService = true;
+					continue;
+				}
+				if (line.equals("")){
+					service.setAttributes(SLPUtils.stringArrayToDict(SLPUtils.listToStringArray(attributes)));
+					SLPCore.getDirectoryAgentDaemon().registerService(service);
+					service = null;
+					attributes = new ArrayList<String>();
+					parsingService = false;
+					continue;
+				}
+				if (line.startsWith("scopes=") && parsingService){
+					String[] scopes = line.substring(7).split(",");
+					service.setScopes(SLPUtils.arrayToList(scopes));
+					continue;
+				}
+				if (parsingService){
+					attributes.add("("+line+")");
+				}
+				
+			}
+			 		 
+			 
+		} catch (Exception e){
+			SLPCore.getPlatform().logError("Unable to parse registration file");
+			System.out.println("Unable to parse registration file "+file);
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#exportServicesToFile(java.lang.String, boolean)
+	 */
+	public void exportServicesToFile(String path, boolean append){
+		File file = null;
+		BufferedWriter out = null;
+		try {
+			file = new File(path);
+			out = new BufferedWriter(new FileWriter(file,append));
+		} catch (Exception e){
+			SLPCore.getPlatform().logError("Unable to open registration file for writing");
+			System.out.println("Unable to open registration file "+path+" for writing");
+		}
+		
+		try{
+			List<Service> allServices = listServices();
+			for (Service service : allServices){
+				//TODO: iplement correct localization
+				out.write(service.getURL().toString()+","+SLPCore.DEFAULT_LOCALE+","+service.getURL().getLifetime());
+				out.newLine();
+				out.write("scopes="+SLPUtils.listToString(service.getScopes(),","));
+				out.newLine();
+				Enumeration<String> keys = service.getAttributesAsStringDict().keys();
+				while (keys.hasMoreElements()){
+					String key = keys.nextElement();
+					out.write(key+"="+service.getAttributesAsStringDict().get(key));
+					out.newLine();
+				}
+				out.newLine();
+				out.close();
+				
+			}
+		} catch (Exception e){
+			SLPCore.getPlatform().logError("Unable to export to file");
+			System.out.println("Unable to export to file "+path);
+		}
+		
+	}
+
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#setServiceStore(ch.ethz.iks.slp.ServiceStore, boolean)
+	 */
+	public void setServiceStore(ServiceStore store, boolean flush) throws ServiceLocationException {
+		List<Service> services = new ArrayList<Service>();
+		if (!flush){
+			services = SLPCore.daDaemon.listServices();
+		}
+		SLPCore.daDaemon.setStore(store);
+		if (!flush){
+			for (Service s:services){
+				registerService(s);
+			}
+		}
+		
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.DirectoryAgent#getAttributeTypes()
+	 */
+	public Map<String, Integer> getAttributeTypes() throws ServiceLocationException{
+		return SLPCore.getDirectoryAgentDaemon().getAttributeTypes();
+	}
+	
+	
+}

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/DirectoryAgentImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/SimpleServiceStore.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/SimpleServiceStore.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/SimpleServiceStore.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/SimpleServiceStore.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,323 @@
+/* 
+ *   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.directory.slp.impl.da;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.slp.OpaqueValue;
+import org.apache.directory.slp.Service;
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.ServiceStore;
+import org.apache.directory.slp.ServiceType;
+import org.apache.directory.slp.ServiceURL;
+import org.apache.directory.slp.impl.SLPCore;
+import org.apache.directory.slp.impl.SLPUtils;
+import org.apache.directory.slp.impl.filter.Filter;
+
+
+/**
+ * A simple HashMap based ServiceStore for the DirectoryAgentDaemon to store registrations in.
+ * 
+ * @author Lorenz Breu
+ */
+public class SimpleServiceStore implements ServiceStore{
+	
+	
+	// The services registered
+	private Map<String,Service> registeredServices = new HashMap<String,Service>();
+	
+	// the type registry
+	private Map<String,Integer> attributeTypes = new HashMap<String, Integer>(); 
+	
+	
+	
+	public SimpleServiceStore(){
+		
+	}
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#deleteService(java.lang.String)
+	 */
+	public synchronized void deleteService(String serviceurl) throws ServiceLocationException {
+		try {
+			registeredServices.remove(serviceurl);
+		} catch (Exception e){
+			throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"Service not registered before.");
+		}
+		
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#getAttributes(java.lang.String, java.lang.String[], java.lang.String[])
+	 */
+	public String[] getAttributes(String service, String[] tagList, String[] scopeList){
+		try {
+			List<Service> allServiceMatches = getServices(service, "",scopeList);
+			
+			
+			List<String> attResult = new ArrayList<String>();
+				
+			for (Service matchedService: allServiceMatches) {
+				List<String> completeListwithDuplicates = SLPUtils.findMatches(SLPUtils.arrayToList(tagList), matchedService.getAttributesAsStringDict());
+				
+				for (String s: completeListwithDuplicates){
+					if (!attResult.contains(s)){
+						attResult.add(s);
+					}
+				}
+						
+			}
+			
+			
+			
+			return attResult.toArray(new String[]{});
+		} catch (ServiceLocationException sle){
+			SLPCore.getPlatform().logError("error finding attributes", sle);
+			return new String[]{""};
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#getServiceTypes(java.lang.String[], java.lang.String)
+	 */
+	public ServiceType[] getServiceTypes(String[] scopes, String namingAuthority){
+		try {
+			List<Service> allServiceMatches = listServices();
+			List<Service> scopeMatchedServices = new ArrayList<Service>();
+			for (Service serv: allServiceMatches){
+				for (String scope : scopes){
+					if (serv.getScopes().contains(scope.toLowerCase().trim())){
+						scopeMatchedServices.add(serv);
+						break;
+					}
+				}
+	
+			}
+	
+			ArrayList<ServiceType> result = new ArrayList<ServiceType>();
+	
+			for (Service service : scopeMatchedServices) {
+				ServiceType type = service.getURL().getServiceType();
+				if (namingAuthority.equals("*")
+						|| namingAuthority.equals("")
+						|| type.getNamingAuthority().equals(
+								namingAuthority)) {
+					if (!result.contains(type)) {
+						result.add(type);
+					}
+				}
+			}
+	
+			return result.toArray(new ServiceType[]{});
+		} catch (ServiceLocationException sle){
+			SLPCore.getPlatform().logError("Error while retrieving service types", sle);
+			return new ServiceType[]{};
+		}
+
+	}
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#getServices(java.lang.String, java.lang.String)
+	 */
+	public List<Service> getServices(String serviceType,String attributeFilter) throws ServiceLocationException {
+		try {
+			return getServices(serviceType, attributeFilter, SLPUtils.stringToStringArray(SLPCore.CONFIG.getScopes(),","));
+		} catch (Exception e){
+			throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"Error while retrieveing Services");
+		}
+			
+	}
+	
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#getServices(java.lang.String, java.lang.String, java.lang.String[])
+	 */
+	public List<Service> getServices(String serviceType,String attributeFilter, String[] scopes) throws ServiceLocationException {
+		try {
+			List<String> scopeList = new ArrayList<String>();
+			for (String s: scopes){
+				scopeList.add(s.toLowerCase().trim());
+			}
+			
+			Object st;
+			try{
+				st = new ServiceURL(serviceType,0);
+			} catch (Exception e){
+				st = new ServiceType(serviceType);
+			}
+			List<Service> results = new ArrayList<Service>();
+				synchronized(registeredServices){
+				for (String key : registeredServices.keySet()) {
+					Service service = registeredServices.get(key);
+					
+					if (service.getURL().matches(st) && scopeMatch(service.getScopes(),scopeList)) {
+						if (attributeFilter == null || attributeFilter.equals("")) {
+	
+							results.add(service);
+							continue;
+						}
+						Filter filter = SLPCore.getPlatform().createFilter(attributeFilter);
+						if (filter.match(service.getAttributes())  && scopeMatch(service.getScopes(),scopeList)) {
+							results.add(service);
+						}
+					}
+				}
+			}
+			
+			
+			return results;
+			
+		} catch (Exception e){
+			throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"Error while retrieveing Services");
+		}
+		
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#getService(java.lang.String)
+	 */
+	public synchronized Service getService(String serviceUrl) throws ServiceLocationException{
+		try {
+			return registeredServices.get(serviceUrl);
+		} catch (Exception e){
+			throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"Failed to find specified service");
+		}
+	}
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#storeService(ch.ethz.iks.slp.Service)
+	 */
+	public synchronized void storeService(Service service) throws ServiceLocationException {
+		if (registeredServices.get(service.getURL().toString())!=null){
+			throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"Service already exists");
+		}
+		String abstracttype = service.getURL().getServiceType().getAbstractTypeName();
+		if (abstracttype.equals("")){
+			abstracttype=service.getURL().toString();
+			abstracttype = abstracttype.substring(0,abstracttype.indexOf("://"));
+			ServiceType st = new ServiceType(abstracttype);
+			abstracttype=st.getAbstractTypeName();
+		}
+		if (abstracttype.startsWith("service:")){
+			abstracttype = abstracttype.substring("service:".length());
+		}
+		try {
+			if (service.getAttributes()!=null){
+				Enumeration<String> atts = service.getAttributes().keys();
+				while (atts.hasMoreElements()){
+					String k = atts.nextElement();
+					int type;
+					if ((service.getAttributes().get(k) instanceof Boolean) || service.getAttributes().get(k) instanceof Boolean[]){
+						type = BOOLEAN_AT;
+					} else if ((service.getAttributes().get(k) instanceof Number) || service.getAttributes().get(k) instanceof Number[]){
+						type = INTEGER_AT;
+					} else if ((service.getAttributes().get(k) instanceof OpaqueValue) || service.getAttributes().get(k) instanceof OpaqueValue[]){
+						type = OPAQUE_AT;
+					} else {
+						type=STRING_AT;
+					}
+					Integer at = attributeTypes.get(abstracttype+"."+k);
+					if (at!=null && at!=type){
+						throw new ServiceLocationException(ServiceLocationException.INVALID_REGISTRATION,"inconsistent attribute type");
+					}
+					attributeTypes.put(abstracttype+"."+k, type);
+					
+				}
+			}
+			registeredServices.put(service.getURL().toString(),service);
+			
+			
+		} catch (Exception e){
+			if (e instanceof ServiceLocationException){
+				throw (ServiceLocationException) e;
+			}
+			throw new ServiceLocationException(ServiceLocationException.INTERNAL_SYSTEM_ERROR,"Problems while registering service");
+		}
+		
+	}
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#containsService(java.lang.String)
+	 */
+	public synchronized boolean containsService(String service) {
+		return registeredServices.containsKey(service);
+	}
+
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#listServices()
+	 */
+	public synchronized List<Service> listServices() throws ServiceLocationException {
+		List<Service> result = new ArrayList<Service>();
+		for (Service service : registeredServices.values()){
+			result.add(service);
+		}
+		return result;
+	}
+
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#clear()
+	 */
+	public synchronized void clear(){
+		registeredServices = new HashMap<String,Service>();
+		attributeTypes = new HashMap<String, Integer>();
+	}
+	
+	/**
+	 * Checks if there is a scope in both lists. Returns true if one of the two is null....
+	 * 
+	 * @param scopes1
+	 * 			A List of scopes strings
+	 * @param scopes2
+	 * 			A List of scopes strings
+	 * @return
+	 * 			True if either list is null or both lists contain at least one identical scope
+	 * 			False if both lists contain unique scopes
+	 */
+	private boolean scopeMatch(List<String> scopes1, List<String> scopes2){
+		if ((scopes1==null) || (scopes2==null)){
+			return true;
+		}
+		for (String s: scopes1){
+			if (scopes2.contains(s)){
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#shutdown()
+	 */
+	public void shutdown(){
+		// nothing to do
+	}
+	
+	/* (non-Javadoc)
+	 * @see ch.ethz.iks.slp.ServiceStore#getAttributeTypes()
+	 */
+	public Map<String, Integer> getAttributeTypes() throws ServiceLocationException{
+		return new HashMap<String, Integer>(attributeTypes);
+	}
+}

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/da/SimpleServiceStore.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/filter/Filter.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/filter/Filter.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/filter/Filter.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/filter/Filter.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,41 @@
+/* 
+ *   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.directory.slp.impl.filter;
+
+import java.util.Dictionary;
+
+/**
+ * a generic LDAP filter.
+ * @author Jan S. Rellermeyer
+ */
+public interface Filter {
+    /**
+     * try to match a <code>Dictionary</code> of attributes.
+     * @param values a <code>Dictionary</code> of attributes.
+     * @return true if the filter evaluated to true;
+     */
+    boolean match(Dictionary values);
+
+    /**
+     * get a String representation of the filter.
+     * @return the String representation.
+     */
+    String toString();
+}

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/filter/Filter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPMessage.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPMessage.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPMessage.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPMessage.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,337 @@
+/* 
+ *   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.directory.slp.messages;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.extensions.AbstractExtension;
+import org.apache.directory.slp.extensions.UnsupportedExtension;
+import org.apache.directory.slp.impl.SLPUtils;
+
+
+
+/**
+ * abstract base class for all SLP messages.
+ * 
+ * @author Jan S. Rellermeyer
+ */
+public abstract class AbstractSLPMessage {
+
+	protected static final String[] EMPTY = new String[0];
+
+	protected final byte funcID;
+
+	protected short xid;
+	
+	protected String source;
+	protected int port;
+
+	protected boolean multicast;
+	protected boolean fresh = true;;
+
+	protected boolean tcp;
+	
+	protected AbstractExtension[] extensions = new AbstractExtension[]{};
+	
+	/**
+	 * the message funcID values according to RFC 2608, Service Request = 1.
+	 */
+	public static final byte SRVRQST = 1;
+
+	/**
+	 * the message funcID values according to RFC 2608, Service Reply = 2.
+	 */
+	public static final byte SRVRPLY = 2;
+
+	/**
+	 * the message funcID values according to RFC 2608, Service Registration =
+	 * 3.
+	 */
+	public static final byte SRVREG = 3;
+
+	/**
+	 * the message funcID values according to RFC 2608, Service Deregistration =
+	 * 4.
+	 */
+	public static final byte SRVDEREG = 4;
+
+	/**
+	 * the message funcID values according to RFC 2608, Service Acknowledgement =
+	 * 5.
+	 */
+	public static final byte SRVACK = 5;
+
+	/**
+	 * the message funcID values according to RFC 2608, Attribute Request = 6.
+	 */
+	public static final byte ATTRRQST = 6;
+
+	/**
+	 * the message funcID values according to RFC 2608, Attribute Reply = 7.
+	 */
+	public static final byte ATTRRPLY = 7;
+
+	/**
+	 * the message funcID values according to RFC 2608, DA Advertisement = 8.
+	 */
+	public static final byte DAADVERT = 8;
+
+	/**
+	 * the message funcID values according to RFC 2608, Service Type Request =
+	 * 9.
+	 */
+	public static final byte SRVTYPERQST = 9;
+
+	/**
+	 * the message funcID values according to RFC 2608, Service Type Reply = 10.
+	 */
+	public static final byte SRVTYPERPLY = 10;
+
+	/**
+	 * the message funcID values according to RFC 2608, SA Advertisement = 11.
+	 */
+	public static final byte SAADVERT = 11;
+
+	/**
+	 * used for reverse lookup of funcID values to have nicer debug messages.
+	 */
+	private static final String[] TYPES = { "NULL", "SRVRQST", "SRVPLY",
+			"SRVREG", "SRVDEREG", "SRVACK", "ATTRRQST", "ATTRRPLY", "DAADVERT",
+			"SRVTYPERQST", "SRVTYPERPLY", "SAADVERT" };
+
+	// TODO: take the default locale here...
+	protected Locale locale = new Locale("en");
+
+	AbstractSLPMessage(final byte funcID) {
+		this.funcID = funcID;
+	}
+
+	public final byte getFuncID() {
+		return funcID;
+	}
+
+	public final short getXid() {
+		return xid;
+	}
+
+	public final void setXid(final short xid) {
+		this.xid = xid;
+	}
+
+	public final boolean isMulticast() {
+		return multicast;
+	}
+
+	public final void setMulticast(final boolean multicast) {
+		this.multicast = multicast;
+	}
+	
+		
+	public boolean isFresh(){
+		return fresh;
+	}
+	
+	public void setFresh(boolean freshness){
+		fresh = freshness;
+	}
+
+	public final boolean isTcp() {
+		return tcp;
+	}
+
+	public final void setTcp(final boolean tcp) {
+		this.tcp = tcp;
+	}
+
+	public final Locale getLocale() {
+		return locale;
+	}
+
+	public final void setLocale(final Locale locale) {
+		if (locale != null) {
+			this.locale = locale;
+		} else {
+			// TODO: set default
+		}
+	}
+
+	public String getHeaderString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("xid=" + xid);
+		buffer.append(", locale=" + locale);
+		return buffer.toString();
+	}
+
+	public abstract String toString();
+	
+	/**
+	 * 
+	 * @return
+	 */
+	public abstract int getSize();
+	
+	int getHeaderSize() {
+		return 14 + locale.getLanguage().length();
+	}
+	
+	
+	protected static String arrayToString(final String[] arr, final String delim) {
+		return SLPUtils.arrayToString(arr, delim);
+	}
+
+	protected static List<String> stringToList(final String str, final String delim) {
+		return SLPUtils.stringToList(str, delim);
+	}
+	
+	protected static List<String> arrayToList(final String[] arr){
+		return SLPUtils.arrayToList(arr);
+	}
+	
+	
+	
+	
+	
+	
+	/**
+	 * get the bytes from a SLPMessage. Processes the header and then calls the
+	 * getBody() method of the implementing subclass.
+	 * 
+	 * @return an array of bytes encoding the SLPMessage.
+	 * @throws IOException
+	 * @throws ServiceLocationException
+	 *             in case of IOExceptions.
+	 */
+	protected void writeHeader(final DataOutputStream out, int msgSize, int mtu)
+			throws IOException {
+		byte flags = 0;
+		if (funcID == SRVREG) {
+			flags |= 0x40;
+		}
+		if (multicast) {
+			flags |= 0x20;
+		}
+		if (!tcp && msgSize > mtu) {
+			flags |= 0x80;
+		}
+		out.write(2);
+		out.write(funcID);
+		out.write((byte) ((msgSize) >> 16));
+		out.write((byte) (((msgSize) >> 8) & 0xFF));
+		out.write((byte) ((msgSize) & 0xFF));
+		out.write(flags);
+		out.write(0);
+		out.write(0);
+		out.write(0);
+		out.write(0);
+		out.writeShort(xid);
+		out.writeUTF(locale.getLanguage());
+	}
+	
+	public abstract void writeTo(final DataOutputStream out, final int mtu) throws IOException;
+	
+	public String getSource(){
+		return source;
+	}
+	
+	public void setSource(String s){
+		source=s;
+	}
+	
+	public int getPort(){
+		return port;
+	}
+	
+	public void setPort(int p){
+		port=p;
+	}
+	
+	
+	
+	/**
+	 * Return the String corresponding to the FuncID
+	 * 
+	 * @param funcID the message type as int
+	 * @return The String representation of that type
+	 */
+	public static String getType(int funcID){
+		return TYPES[funcID];
+	}
+	
+	
+	public AbstractExtension[] getExtensions(){
+		return extensions;
+	}
+	
+	public void setExtensions(AbstractExtension[] extensions){
+		this.extensions = extensions;
+	}
+	
+	public void addExtension(AbstractExtension extension){
+		AbstractExtension[] newExt = new AbstractExtension[extensions.length+1];
+		int i = 0;
+		for (AbstractExtension ae : extensions){
+			newExt[i++]=ae;
+		}
+		newExt[i] = extension;
+		extensions = newExt;
+	}
+	
+	public boolean hasExtensions(){
+		if (extensions == null){
+			return false;
+		}
+		return (extensions.length>0);
+	}
+	
+	public boolean hasExtensionType(short id){
+		for (AbstractExtension ae : extensions){
+			if (ae.getId()==id){
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	public boolean hasUnsupportedExtensions(){
+		for (AbstractExtension ae : extensions){
+			if (ae instanceof UnsupportedExtension){
+				 return true;
+			}
+		}
+		return false;
+	}
+	
+	public boolean hasUnsupportedMandatoryExtensions(){
+		for (AbstractExtension ae : extensions){
+			if (ae instanceof UnsupportedExtension){
+				 if (ae.isMandatory()){
+					 return true;
+				 }
+			}
+		}
+		return false;
+	}
+	
+}
+

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPMessage.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPReplyMessage.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPReplyMessage.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPReplyMessage.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPReplyMessage.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,75 @@
+/* 
+ *   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.directory.slp.messages;
+
+import java.util.List;
+
+/**
+ * abstract base class for all ReplyMessages.
+ * 
+ * @author Jan S. Rellermeyer
+ */
+public abstract class AbstractSLPReplyMessage extends AbstractSLPMessage {
+
+	/**
+	 * the error code that is returned.
+	 */
+	private short errorCode;
+
+	AbstractSLPReplyMessage(byte funcID) {
+		super(funcID);
+	}
+
+	public void setErrorCode(final short errorCode) {
+		this.errorCode = errorCode;
+	}
+
+	public short getErrorCode() {
+		return errorCode;
+	}
+
+	public final String getHeaderString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append(super.getHeaderString());
+		buffer.append(", errorCode=");
+		buffer.append(errorCode);
+		return buffer.toString();
+	}
+	
+	
+	/**
+	 * get the results.
+	 * 
+	 * @return the Array of results.
+	 */
+	public abstract String[] getResult();
+	
+	/**
+	 * get the results.
+	 * 
+	 * @return the List of results.
+	 */
+	public abstract List<String> getResultAsList();
+	
+	
+	
+	
+
+}

Propchange: directory/sandbox/slp/src/main/java/org/apache/directory/slp/messages/AbstractSLPReplyMessage.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain