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 [5/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/SLPDaemonImpl.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPDaemonImpl.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,1108 @@
+/* 
+ *   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.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+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.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.filter.Filter;
+import org.apache.directory.slp.messages.AbstractSLPMessage;
+import org.apache.directory.slp.messages.AbstractSLPReplyMessage;
+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;
+
+/**
+ * the jSLP daemon class. This class is only required, if the peer is configured
+ * as a SA and no other SLP daemon is running on the machine. UA-only
+ * configurations or distributions that are intended to run on a machine with
+ * OpenSLP <i>slpd</i> can be packaged without this class.
+ * 
+ * @author Jan S. Rellermeyer
+ */
+public final class SLPDaemonImpl implements SLPDaemon {
+
+	/**
+	 * thread loop variable.
+	 */
+	private boolean running = true;
+
+	/**
+	 * Map of registered services:
+	 * 
+	 * String scope -> List of ServiceURLs services. //?? Service, not URLS...
+	 */
+	private Map<String,List<Service>> registeredServices = new HashMap<String,List<Service>>();
+
+	/**
+	 * Sorted set for disposal of services which lifetimes have expired:
+	 * 
+	 * Long expirationTimestamp -> ServiceURL service.
+	 */
+	private SortedMap<Long,ServiceURL> serviceDisposalQueue = new TreeMap<Long,ServiceURL>();
+
+
+
+
+	/**
+	 * create a new SLPDaemon instance.
+	 * 
+	 * @throws Exception
+	 *             if something goes wrong.
+	 */
+	public SLPDaemonImpl() throws Exception {
+		new ServiceDisposalThread();
+		SLPCore.platform.logDebug("jSLP daemon starting ...");
+		running=true;
+	}
+
+	/**
+	 * register a service with the SLP framework. For the scopes, where DAs are
+	 * known, the service will be registered with all DAs.
+	 * 
+	 * @param reg
+	 *            the ServiceRegistration.
+	 */
+	private void registerService(final ServiceRegistrationMessage reg) {
+		// prevent registrations from being sent to the same DA multiple times when in multiple scopes
+		List<String> handledDAs = new ArrayList<String>();
+
+		Service service = new Service(reg);
+		String[] scopes = reg.getScopes();
+		for (int i=0;i<scopes.length;i++) {
+			String scope = reg.getScopes()[i];
+			scope = scope.toLowerCase().trim();
+			synchronized (registeredServices) {
+				SLPUtils.removeValue(registeredServices, scope, service);
+				SLPUtils.addValue(registeredServices, scope, 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())) {
+							serviceDisposalQueue.remove(key);
+						}
+					}
+					serviceDisposalQueue.put(new Long(next), reg.getServiceURL());
+					serviceDisposalQueue.notifyAll();
+				}
+			}
+
+			SLPCore.platform.logTraceReg("REGISTERED " + reg.getServiceURL());
+
+			// register the service with all known DAs in the scopes
+			List<String> daList = (List<String>) SLPCore.dAs.get(scope);
+
+			// no DA for the scope known ?
+			// try to find one
+			//could this lead to unnecessary timeouts???
+			if ((daList == null || daList.isEmpty()) && !SLPCore.noDiscovery) {
+				try {
+					SLPCore.daLookup(new String[] { (String) scope });
+
+					// wait a short time for incoming replies
+					synchronized (SLPCore.dAs) {
+						try {
+							SLPCore.dAs.wait(SLPCore.CONFIG.getWaitTime());
+						} catch (InterruptedException e) {
+						}
+					}
+					daList = SLPCore.dAs.get(scope);
+				} catch (ServiceLocationException sle) {
+					SLPCore.platform.logError(sle.getMessage(), sle
+							.fillInStackTrace());
+				}
+			}
+
+
+
+
+			if (daList != null && !daList.isEmpty()) {
+				final String[] dAs = (String[]) daList
+				.toArray(new String[daList.size()]);
+				for (int j = 0; j < dAs.length; j++) {
+					try{
+						if (handledDAs.contains(dAs[j])){
+							continue;
+						}
+						handledDAs.add(dAs[j]);
+						// if the ip is within the framework, i.e. DA and SA are running at the same time, then pass the reg on internally
+						if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dAs[j])){
+							if (SLPCore.getDirectoryAgentDaemon()!=null){
+								if (SLPCore.getDirectoryAgentDaemon().isKnownService(service)){
+									SLPCore.getDirectoryAgentDaemon().updateServiceEntry(reg);
+								} else {
+									SLPCore.getDirectoryAgentDaemon().registerService(reg);
+								}
+							} else {
+								// what? no daDaemon running?? must remove the ip from the list
+								SLPUtils.removeValueFromAll(SLPCore.dAs, (reg).getServiceURL().toString());
+								SLPCore.dASPIs.remove((reg).getServiceURL().toString());
+
+							}
+						} else {
+							announceService(dAs[j], reg);
+						}
+
+					} catch (ServiceLocationException e) {
+						if (e.getErrorCode()==ServiceLocationException.INVALID_REGISTRATION){
+							return;
+						}
+						
+						// remove DA from list
+						SLPUtils.removeValueFromAll(SLPCore.dAs, dAs[i]);
+						SLPCore.dASPIs.remove(dAs[i]);
+						SLPCore.platform.logError(e.getMessage(), e
+								.fillInStackTrace());
+					}
+				}
+			}
+		}
+
+	}
+
+	private void updateService(final ServiceRegistrationMessage reg) throws ServiceLocationException{
+
+		// fresh flag is set and the message comes from the framework, considered safe for now...
+		Service registeredService = null;
+		Service newService = new Service(reg);
+		boolean found = false;
+		for (int i=0;i<reg.getScopes().length&&!found; i++) {
+			List<Service> services = registeredServices.get(reg.getScopes()[i].toLowerCase().trim());
+			if (services == null) {
+				continue;
+			}
+
+			for (Iterator<Service> srvs = services.iterator(); srvs.hasNext();) {
+				Service service = srvs.next();
+				if (service.getURL().toString().equals(reg.getServiceURL().toString())){
+					registeredService = service;
+					found = true;
+					break;
+				}
+			}
+		}
+
+		if (registeredService==null){
+			throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE,"No service to update...");
+		}
+
+		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));
+		}
+		newService.setAttributes(registeredAttributes);
+
+		final String[] scopes = (String[]) registeredServices.keySet().toArray(
+				new String[registeredServices.size()]);
+		for (int i = 0; i < scopes.length; i++) {
+			final List<Service> tmp = registeredServices.get(scopes[i].toLowerCase());
+			final Service[] services = tmp.toArray(new Service[tmp
+			                                                   .size()]);
+
+			for (int j = 0; j < services.length; j++) {
+				if (reg.getServiceURL().matches(services[j].getURL())) {
+					List<String> daList = SLPCore.dAs.get(scopes[i].toLowerCase());
+					if (daList != null) {
+						for (String dA : daList) {
+
+							// if there is a local DA in the same framework, deregister the service directly from there
+							if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dA)){
+								if (SLPCore.getDirectoryAgentDaemon()!=null){
+									SLPCore.getDirectoryAgentDaemon().updateServiceEntry(reg);
+								}  else {
+									// what? no daDaemon running?? must remove the ip from the list
+									SLPUtils.removeValueFromAll(SLPCore.dAs, dA);
+									SLPCore.dASPIs.remove(dA);
+
+								}
+								return;
+							}
+
+							// update all known remote DAs
+
+
+							if (SLPCore.CONFIG.getSecurityEnabled()) {
+								List spiList = (List) SLPCore.dASPIs
+								.get(dA);
+								reg.sign(SLPUtils.listToStringArray(spiList));
+							}
+
+							announceUpdatedService(dA, reg, newService);
+
+
+						} 
+					}
+
+					synchronized (registeredServices) {
+						SLPUtils.removeValue(registeredServices, scopes[i],
+								services[j]);
+						SLPUtils.addValue(registeredServices, scopes[i], newService);
+					}
+					break;
+				}
+			}
+		}
+	}
+
+
+
+	/**
+	 * deregister a service from the SLP framework. Deregisters from all DAs
+	 * within the scopes and from the local service cache.
+	 * 
+	 * @param dereg
+	 *            the service deregistration.
+	 * @throws ServiceLocationException
+	 */
+	private void deregisterService(final ServiceDeregistrationMessage dereg)
+	throws ServiceLocationException {
+
+		final String[] scopes = (String[]) registeredServices.keySet().toArray(
+				new String[registeredServices.size()]);
+		List<String> handledDAs = new ArrayList<String>();
+		for (int i = 0; i < scopes.length; i++) {
+			final List<Service> tmp = registeredServices.get(scopes[i].toLowerCase());
+			final Service[] services = tmp.toArray(new Service[tmp
+			                                                   .size()]);
+
+			for (int j = 0; j < services.length; j++) {
+				if (dereg.getServiceURL().matches(services[j].getURL())) {
+					List<String> daList = SLPCore.dAs.get(scopes[i].toLowerCase());
+					if (daList != null) {
+						for (String dA : daList) {
+							if (handledDAs.contains(dA)){
+								continue;
+							}
+							handledDAs.add(dA);
+							try {
+								// if there is a local DA in the same framework, deregister the service directly from there
+								if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dA)){
+									if (SLPCore.getDirectoryAgentDaemon()!=null){
+										SLPCore.getDirectoryAgentDaemon().deregisterService(dereg);
+									}  else {
+										// what? no daDaemon running?? must remove the ip from the list
+										SLPUtils.removeValueFromAll(SLPCore.dAs, (dereg).getServiceURL().toString());
+										SLPCore.dASPIs.remove((dereg).getServiceURL().toString());
+
+									}
+									return;
+								}
+
+								// deregister from all known remote DAs
+
+								ServiceDeregistrationMessage dadereg = new ServiceDeregistrationMessage();
+								dadereg.setLocale(dereg.getLocale());
+								dadereg.setMulticast(false);
+								dadereg.setScopes(dereg.getScopes());
+								dadereg.setServiceURL(dereg.getServiceURL());
+								dadereg.setTags(dereg.getTags());
+
+								InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(dA),SLPCore.SLP_PORT);
+								dadereg.setXid(SLPCore.nextXid());
+								if (SLPCore.CONFIG.getSecurityEnabled()) {
+									List spiList = (List) SLPCore.dASPIs
+									.get(dA);
+									dadereg.sign(spiList);
+								}
+								AbstractSLPReplyMessage reply = new ServiceReplyMessage();
+								new AnnouncerThread(address,dadereg,reply);
+
+							} catch (UnknownHostException uhe) {
+								throw new ServiceLocationException(
+										ServiceLocationException.NETWORK_ERROR,
+										uhe.getMessage());
+							} 
+						}
+					}
+					synchronized (registeredServices) {
+						SLPUtils.removeValue(registeredServices, scopes[i],
+								services[j]);
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * all incoming messages are handled here.
+	 * 
+	 * @param msg
+	 *            the message to be processed.
+	 * @return the reply if the handled message came in via TCP. Otherwise null
+	 *         will be returned.
+	 * @throws ServiceLocationException
+	 *             for various reasons like authentication failures etc.
+	 */
+	public AbstractSLPReplyMessage handleMessage(final AbstractSLPMessage msg)
+	throws ServiceLocationException {
+		short zero=0;
+		if (msg == null) {
+			return null;
+		}
+
+		String via = msg.isTcp() ? " (tcp)" : " (udp)";
+
+		SLPCore.platform.logTraceMessage("RECEIVED (" + msg.getSource() + ":"
+				+ msg.getPort() + ") " + msg.toString() + via);
+
+		AbstractSLPReplyMessage reply = null;
+
+		switch (msg.getFuncID()) {
+		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 req = (ServiceRequestMessage) msg;
+
+			List<ServiceURL> results = new ArrayList<ServiceURL>();
+			List<AbstractExtension> extensions = new ArrayList<AbstractExtension>();
+			for (int i=0;i<req.getScopes().length; i++) {
+				List<Service> services = registeredServices.get(req.getScopes()[i].toLowerCase());
+				if (services == null) {
+					continue;
+				}
+
+				for (Service service : services) {
+					if (service.getURL().getServiceType().matches(req.getServiceType())) {
+						if (req.getPredicate() == null || req.getPredicate().equals("")) {
+							results.add(service.getURL());
+							if (req.hasExtensionType(AbstractExtension.ATTRIBUTE_LIST_EXTENSION)){
+								AttributeListExtension ale = new AttributeListExtension(service.getURL().toString(),SLPUtils.dictToString(service.getAttributesAsStringDict()));
+								extensions.add(ale);
+							}
+							continue;
+						}
+						Filter filter = SLPCore.platform.createFilter(req.getPredicate());
+						if (filter.match(service.getAttributes())) {
+							results.add(service.getURL());
+							if (req.hasExtensionType(AbstractExtension.ATTRIBUTE_LIST_EXTENSION)){
+								AttributeListExtension ale = new AttributeListExtension(service.getURL().toString(),SLPUtils.dictToString(service.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 && req.isMulticast()) {
+				return null;
+			}
+			
+			reply = new ServiceReplyMessage();
+			ServiceReplyMessage servreply = (ServiceReplyMessage) reply;
+			servreply.setXid(req.getXid());
+			servreply.setLocale(req.getLocale());
+			servreply.setErrorCode(zero);
+			servreply.setServiceURLs((ServiceURL[]) results.toArray(new ServiceURL[]{}));
+			
+			servreply.setExtensions(extensions.toArray(new AbstractExtension[]{}));
+			
+			if (SLPCore.CONFIG.getSecurityEnabled()) {
+				servreply.sign(SLPUtils.arrayToString(req.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;
+
+			// 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);
+			}
+
+			List<String> attResult = new ArrayList<String>();
+			for (int i=0;i<attreq.getScopes().length;i++) {
+				List<Service> services = registeredServices.get(attreq.getScopes()[i].toLowerCase());
+				if (services == null) {
+					continue;
+				}
+
+
+				// if spi is sent, the request must be for a full url and
+				// the tag list has to be empty
+				if (attreq.getSPIs().length==0
+						|| (fullurl && attreq.getTags().length==0)) {
+					for (Service service:services) {
+						if (service.getURL().matches(reqService)) {
+							attResult.addAll(SLPUtils.findMatches(
+									SLPUtils.arrayToList(attreq.getTags()), service.getAttributesAsStringDict()));
+						}
+					}
+				}
+			}
+			
+			String[] finalAtts = SLPUtils.listToStringArray(attResult);
+			if (!fullurl){
+				finalAtts = SLPUtils.mergeAttributes(attResult);
+			}
+				
+			reply = new AttributeReplyMessage();
+			AttributeReplyMessage attrep = (AttributeReplyMessage) reply;
+			attrep.setAttributes(finalAtts);
+			attrep.setLocale(attreq.getLocale());
+			attrep.setXid(attreq.getXid());
+			attrep.setAuthBlocks(new AuthenticationBlock[0]);
+			attrep.setErrorCode(zero);
+			if (attreq.getSPIs().length>0 && !fullurl){
+				attrep.setErrorCode(ServiceLocationException.AUTHENTICATION_FAILED);
+			}
+
+
+
+			if (SLPCore.CONFIG.getSecurityEnabled()) {
+				attrep.sign(SLPUtils.arrayToString(attreq.getSPIs(),","));
+			}
+			return reply;
+		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;
+
+			ArrayList<ServiceType> result = new ArrayList<ServiceType>();
+
+			// iterate over scopes
+			for (int i=0;i<streq.getScopes().length;i++) {
+
+				// iterate over the registered services
+				List services = ((List) registeredServices
+						.get(streq.getScopes()[i]));
+				if (services == null) {
+					continue;
+				}
+				for (Iterator iter = services.iterator(); iter.hasNext();) {
+					Service service = (Service) iter.next();
+					ServiceType type = service.getURL().getServiceType();
+					if (streq.getNamingAuthority().equals("*")
+							|| streq.getNamingAuthority().equals("")
+							|| type.getNamingAuthority().equals(
+									streq.getNamingAuthority())) {
+						if (!result.contains(type)) {
+							result.add(type);
+						}
+					}
+				}
+			}
+			zero = 0;
+			reply = new ServiceTypeReplyMessage();
+			ServiceTypeReplyMessage streply = (ServiceTypeReplyMessage) reply;
+			streply.setXid(streq.getXid());
+			streply.setLocale(streq.getLocale());
+			streply.setErrorCode(zero);
+			streply.setServiceTypes(ServiceTypeReplyMessage.listToServiceTypeArray(result));
+
+			return streply;
+
+		case AbstractSLPMessage.SRVREG:
+			
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				ServiceAcknowledgementMessage ack = new ServiceAcknowledgementMessage();
+				ack.setXid(msg.getXid());
+				ack.setLocale(msg.getLocale());
+				ack.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD);
+				return ack;
+			}
+			
+			
+			if (!((ServiceRegistrationMessage)msg).checkAttributeListValidity()){
+				ServiceAcknowledgementMessage srvreply = new ServiceAcknowledgementMessage();
+				srvreply.setXid(msg.getXid());
+				srvreply.setErrorCode(ServiceLocationException.INVALID_REGISTRATION);
+				srvreply.setLocale(msg.getLocale());
+				srvreply.setSource(msg.getSource());
+				srvreply.setPort(msg.getPort());
+				return srvreply;
+			}
+			reply = new ServiceAcknowledgementMessage();
+			ServiceAcknowledgementMessage srvreply = (ServiceAcknowledgementMessage) reply;
+			srvreply.setXid(msg.getXid());
+			srvreply.setErrorCode(zero);
+			srvreply.setLocale(msg.getLocale());
+			srvreply.setSource(msg.getSource());
+			srvreply.setPort(msg.getPort());
+			if (!((ServiceRegistrationMessage)msg).isFresh()){
+				try {
+					updateService((ServiceRegistrationMessage) msg);
+				} catch (ServiceLocationException sle){
+					srvreply.setErrorCode(sle.getErrorCode());
+				}
+			} else {
+				registerService((ServiceRegistrationMessage) msg);
+			}
+
+			return srvreply;
+
+		case AbstractSLPMessage.SRVDEREG:
+			
+			if (msg.hasUnsupportedMandatoryExtensions()){
+				ServiceAcknowledgementMessage ack = new ServiceAcknowledgementMessage();
+				ack.setXid(msg.getXid());
+				ack.setLocale(msg.getLocale());
+				ack.setErrorCode(ServiceLocationException.OPTION_NOT_UNDERSTOOD);
+				return ack;
+			}
+			
+			ServiceDeregistrationMessage dereg = (ServiceDeregistrationMessage) msg;
+//			check if tags have been set to delete attributes only...
+			if (dereg.getTags().length>0){
+				deleteAttributes(dereg);
+			} else {
+				deregisterService(dereg);
+			}
+
+			reply = new ServiceAcknowledgementMessage();
+			srvreply = (ServiceAcknowledgementMessage) reply;
+			srvreply.setXid(msg.getXid());
+			srvreply.setErrorCode(zero);
+			srvreply.setLocale(msg.getLocale());
+			return srvreply;
+
+		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:
+			// this should never happen, message should already cause an
+			// exception during parsing
+			throw new ServiceLocationException(
+					ServiceLocationException.NOT_IMPLEMENTED,
+					"The message type " + AbstractSLPMessage.getType(msg.getFuncID())
+					+ " is not implemented");
+		}
+
+	}
+
+	/**
+	 * get informed about a new discovered DA. Registers all services in the
+	 * scopes of the new DA.
+	 * 
+	 * @param advert
+	 *            the DA advertisement.
+	 */
+	public void newDaDiscovered(final DAAdvertisementMessage advert) {
+		// so find all services within the scopes of the new DA:
+		for (int i=0;i<advert.getScopes().length;i++) {
+			String scope = advert.getScopes()[i].toLowerCase();
+			List services = (List) registeredServices.get(scope);
+			if (services != null) {
+				for (Iterator serviceIter = services.iterator(); serviceIter
+				.hasNext();) {
+					// and try to register it with the new DA
+					try {
+						Service service = (Service) serviceIter.next();
+						ServiceRegistrationMessage reg = new ServiceRegistrationMessage();
+						reg.setServiceURL(service.getURL());
+						reg.setServiceType(service.getURL().getServiceType());
+						reg.setScopes(new String[]{scope});
+						reg.setAttrList(SLPUtils.listToStringArray(SLPUtils.dictToAttrList(service.getAttributes())));
+						reg.setLocale(SLPCore.DEFAULT_LOCALE);
+
+						SLPCore.platform.logDebug("Registering "
+								+ service.getURL() + " with new DA "
+								+ advert.getServiceURL());
+						// added by Lorenz to ensure adherence to RFC2608 section 12.2.1
+						long rand = Math.round(Math.random()*SLPCore.CONFIG.getConfigRegActive());
+						Thread.sleep(rand);
+
+						announceService(advert.getServiceURL().getHost(), reg);
+					} catch (ServiceLocationException e) {
+						SLPCore.platform.logError(e.getMessage(), e
+								.fillInStackTrace());
+					} catch (InterruptedException ie){
+						// what has to happen here? announce again?
+					}
+				}
+			}
+		}
+		//update the timestamp:
+		SLPUtils.addValue(SLPCore.statelessBootTimestamps, advert.getServiceURL().getHost(), advert.getStatelessBootTimestamp());
+	}
+
+	/**
+	 * Provides direct access to the registered services.
+	 * 
+	 * @return
+	 * 		The cache of registered services
+	 */
+	public Map<String,List<Service>> getRegisteredServices(){
+		return registeredServices;
+	}
+
+	
+
+	/**
+	 * Delete attributes from an existing regstration
+	 * 
+	 * @param dereg
+	 * 		The Deregistration Message asking for this to happen
+	 * @throws ServiceLocationException
+	 */
+	private void deleteAttributes(ServiceDeregistrationMessage dereg) throws ServiceLocationException{
+		// check for security has been done by the handler!
+		// message comes from the framework, considered safe for now...
+		Service registeredService = null;
+		boolean found = false;
+		for (int i=0;i<dereg.getScopes().length&&!found; i++) {
+			List<Service> services = registeredServices.get(dereg.getScopes()[i].toLowerCase().trim());
+			if (services == null) {
+				continue;
+			}
+
+			for (Iterator<Service> srvs = services.iterator(); srvs.hasNext();) {
+				Service service = srvs.next();
+				if (service.getURL().toString().equals(dereg.getServiceURL().toString())){
+					registeredService = service;
+					found = true;
+					break;
+				}
+			}
+		}
+
+		if (registeredService==null){
+			throw new ServiceLocationException(ServiceLocationException.INVALID_UPDATE,"No service to update...");
+		}
+
+		Dictionary<String,Object> registeredAttributes = registeredService.getAttributes();
+		for (String t: dereg.getTags()){
+			registeredAttributes.remove(t);
+		}
+
+		// now propagate to DAs
+
+		final String[] scopes = (String[]) registeredServices.keySet().toArray(
+				new String[registeredServices.size()]);
+		for (int i = 0; i < scopes.length; i++) {
+			final List<Service> tmp = registeredServices.get(scopes[i].toLowerCase());
+			final Service[] services = tmp.toArray(new Service[tmp
+			                                                   .size()]);
+
+			for (int j = 0; j < services.length; j++) {
+				if (dereg.getServiceURL().matches(services[j].getURL())) {
+					List<String> daList = SLPCore.dAs.get(scopes[i].toLowerCase());
+					if (daList != null) {
+						for (String dA : daList) {
+
+							// if there is a local DA in the same framework, delete the attribute directly from there
+							if (SLPUtils.arrayToList(SLPCore.myIPs).contains(dA)){
+								if (SLPCore.getDirectoryAgentDaemon()!=null){
+									SLPCore.getDirectoryAgentDaemon().deregisterService(dereg);
+								}  else {
+									// what? no daDaemon running?? must remove the ip from the list
+									SLPUtils.removeValueFromAll(SLPCore.dAs, dA);
+									SLPCore.dASPIs.remove(dA);
+
+								}
+								return;
+							}
+
+//							deregister from all known remote DAs
+
+							ServiceDeregistrationMessage dadereg = new ServiceDeregistrationMessage();
+							dadereg.setLocale(dereg.getLocale());
+							dadereg.setMulticast(false);
+							dadereg.setScopes(dereg.getScopes());
+							dadereg.setServiceURL(dereg.getServiceURL());
+							dadereg.setTags(dereg.getTags());
+
+							try {
+								InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(dA),SLPCore.SLP_PORT);
+								dadereg.setXid(SLPCore.nextXid());
+								AbstractSLPReplyMessage reply = new ServiceReplyMessage();
+								new AnnouncerThread(address,dadereg,reply);
+							}  catch (UnknownHostException uhe) {
+								throw new ServiceLocationException(
+										ServiceLocationException.NETWORK_ERROR,
+										uhe.getMessage());
+							} 
+
+
+
+
+
+						} 
+					}
+
+					// now that we have found a service that matches the one in dereg, we can move on to the next scope
+					break;
+				}
+			}
+		}
+	}
+
+
+
+
+
+
+	/**
+	 * register a service with a DA.
+	 * 
+	 * @param dAAddress
+	 *            the IP address of the DA as <code>String</code>
+	 * @param reg
+	 *            the <code>ServiceRegistration</code> message.
+	 * @throws ServiceLocationException
+	 *             in case of network errors.
+	 */
+	private void announceService(final String dAAddress,
+			final ServiceRegistrationMessage reg) throws ServiceLocationException {
+		try {
+			InetSocketAddress addr = new InetSocketAddress(InetAddress.getByName(dAAddress),SLPCore.SLP_PORT);
+			ServiceRegistrationMessage dareg = new ServiceRegistrationMessage();
+			dareg.setAttrList(reg.getAttrList());
+			dareg.setAuthBlocks(reg.getAuthBlocks());
+			dareg.setLocale(reg.getLocale());
+			dareg.setMulticast(false);
+			dareg.setScopes(reg.getScopes());
+			dareg.setServiceType(reg.getServiceType());
+			dareg.setServiceURL(reg.getServiceURL());
+			dareg.setXid(SLPCore.nextXid());
+			dareg.setFresh(reg.isFresh());
+			if (SLPCore.CONFIG.getSecurityEnabled()) {
+				List<String> spiList = SLPCore.dASPIs.get(dAAddress);
+				dareg.sign((String[]) spiList.toArray(new String[]{}));
+			}
+			new AnnouncerThread(addr,dareg,null);
+
+		} catch (UnknownHostException e) {
+			SLPCore.platform.logError("Service announcement to "
+					+ dAAddress + " failed. ", e.fillInStackTrace());
+		}
+	}
+
+
+	/**
+	 * updatea service with a DA.
+	 * 
+	 * @param dAAddress
+	 *            the IP address of the DA as <code>String</code>
+	 * @param reg
+	 *            the <code>ServiceRegistration</code> message.
+	 * @throws ServiceLocationException
+	 *             in case of network errors.
+	 */
+	private void announceUpdatedService(final String dAAddress,
+			final ServiceRegistrationMessage reg, final Service service) throws ServiceLocationException {
+		try {
+			InetSocketAddress addr = new InetSocketAddress(InetAddress.getByName(dAAddress),SLPCore.SLP_PORT);
+			ServiceRegistrationMessage dareg = new ServiceRegistrationMessage();
+			dareg.setAttrList(reg.getAttrList());
+			dareg.setAuthBlocks(reg.getAuthBlocks());
+			dareg.setLocale(reg.getLocale());
+			dareg.setMulticast(false);
+			dareg.setScopes(reg.getScopes());
+			dareg.setServiceType(reg.getServiceType());
+			dareg.setServiceURL(reg.getServiceURL());
+			dareg.setXid(SLPCore.nextXid());
+			dareg.setFresh(reg.isFresh());
+			if (SLPCore.CONFIG.getSecurityEnabled()) {
+				List<String> spiList = SLPCore.dASPIs.get(dAAddress);
+				dareg.sign((String[]) spiList.toArray(new String[]{}));
+			}
+			new UpdaterThread(addr,dareg,service);
+
+		} catch (UnknownHostException e) {
+			SLPCore.platform.logError("Service announcement to "
+					+ dAAddress + " failed. ", e.fillInStackTrace());
+		}
+	}
+	
+	
+
+	
+	
+	
+
+
+	/**
+	 * 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() {
+			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()) {
+
+								ServiceURL service = (ServiceURL) serviceDisposalQueue
+								.get(nextActivity);
+
+								ServiceDeregistrationMessage dereg = new ServiceDeregistrationMessage();
+								dereg.setServiceURL(service);
+								dereg.setLocale(SLPCore.DEFAULT_LOCALE);
+
+								try {
+									deregisterService(dereg);
+								} 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.
+			}
+		}
+	}
+
+
+
+	/**
+	 * service anouncer thread.
+	 */
+	private final class AnnouncerThread extends Thread {
+
+
+		private InetSocketAddress addr;
+		private AbstractSLPMessage msg;
+		private AbstractSLPReplyMessage replyMsg;
+
+		private AnnouncerThread(InetSocketAddress sock,final AbstractSLPMessage message, AbstractSLPReplyMessage reply) {
+			addr=sock;
+			msg=message;
+			if (reply!=null){
+				replyMsg=reply;
+			} else {
+				replyMsg = new ServiceReplyMessage();
+			}
+			start();
+		}
+
+		/**
+		 * thread's main loop.
+		 */
+		public void run() {
+			try{
+				AbstractSLPReplyMessage rm = SLPCore.sendReliableUnicastMessage(msg, addr, true);
+				if (rm!=null){
+					replyMsg.setErrorCode(rm.getErrorCode());
+				} else {
+
+					//remove DA from list
+					SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress());
+					SLPCore.dASPIs.remove( addr.getAddress().getHostAddress());
+				}
+
+				if (msg instanceof ServiceRegistrationMessage){
+					SLPCore.platform.logTraceReg("ANNOUNCED "
+							+ ((ServiceRegistrationMessage)msg).getServiceURL() + " to " + addr.getAddress().getHostAddress());
+				} else if (msg instanceof ServiceDeregistrationMessage){
+					SLPCore.platform.logTraceReg("DEREGISTERED "
+							+ ((ServiceDeregistrationMessage)msg).getServiceURL() + " from " + addr.getAddress().getHostAddress());
+				} 
+
+			} catch (ServiceLocationException sle){
+				if (msg instanceof ServiceRegistrationMessage){
+					// remove DA from list
+					SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress());
+					SLPCore.dASPIs.remove( addr.getAddress().getHostAddress());
+					SLPCore.platform.logError(sle.getMessage(), sle.fillInStackTrace());
+				} 
+			}
+		}
+	}
+
+
+	/**
+	 * service anouncer thread.
+	 */
+	private final class UpdaterThread extends Thread {
+
+
+		private InetSocketAddress addr;
+		private ServiceRegistrationMessage msg;
+		private Service srv;
+
+		private UpdaterThread(InetSocketAddress sock, ServiceRegistrationMessage message,final Service service) {
+			addr=sock;
+			msg=message;
+			srv=service;
+			start();
+		}
+
+		/**
+		 * thread's main loop.
+		 */
+		public void run() {
+			try{
+				AbstractSLPReplyMessage rm = SLPCore.sendReliableUnicastMessage(msg, addr, true);
+				if (rm!=null){
+					if (rm.getErrorCode()!=0){
+						//DA may not udnerstand updates...
+						msg.setAttrList(SLPUtils.listToStringArray(SLPUtils.dictToAttrList(srv.getAttributes())));
+						msg.setAuthBlocks(srv.getAuthBlocks());
+						msg.setXid(SLPCore.nextXid());
+						msg.setFresh(true);
+						if (SLPCore.CONFIG.getSecurityEnabled()) {
+							List<String> spiList = SLPCore.dASPIs.get(addr);
+							msg.sign((String[]) spiList.toArray(new String[]{}));
+						}
+						rm = SLPCore.sendReliableUnicastMessage(msg, addr, true);
+						if (rm==null){
+//							remove DA from list
+							SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress());
+							SLPCore.dASPIs.remove( addr.getAddress().getHostAddress());
+						}
+					}
+				} else {
+
+					//remove DA from list
+					SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress());
+					SLPCore.dASPIs.remove( addr.getAddress().getHostAddress());
+				}
+
+				SLPCore.platform.logTraceReg("ANNOUNCED "
+						+ ((ServiceRegistrationMessage)msg).getServiceURL() + " to " + addr.getAddress().getHostAddress());
+
+
+			} catch (ServiceLocationException sle){
+
+				// remove DA from list
+				SLPUtils.removeValueFromAll(SLPCore.dAs, addr.getAddress().getHostAddress());
+				SLPCore.dASPIs.remove( addr.getAddress().getHostAddress());
+				SLPCore.platform.logError(sle.getMessage(), sle.fillInStackTrace());
+
+			}
+		}
+	}
+}

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

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPHandler.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,432 @@
+/* 
+ *   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.net.InetSocketAddress;
+
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.messages.AbstractSLPMessage;
+import org.apache.directory.slp.messages.AbstractSLPRequestMessage;
+import org.apache.directory.slp.messages.AttributeReplyMessage;
+import org.apache.directory.slp.messages.DAAdvertisementMessage;
+import org.apache.directory.slp.messages.ServiceAcknowledgementMessage;
+import org.apache.directory.slp.messages.ServiceRegistrationMessage;
+import org.apache.directory.slp.messages.ServiceReplyMessage;
+import org.apache.mina.core.service.IoHandlerAdapter;
+import org.apache.mina.core.session.IdleStatus;
+import org.apache.mina.core.session.IoSession;
+
+
+/**
+ * The IoHandler processing incoming SLP messages and dispatching them to the correct agent for processing
+ * 
+ * @author Lorenz Breu
+ *
+ */
+public class SLPHandler extends IoHandlerAdapter{
+	
+	
+	public SLPHandler(){
+
+	}
+	
+	@Override
+    public void exceptionCaught(IoSession session, Throwable cause)
+            throws Exception {
+        cause.printStackTrace();
+        session.close(false);
+    }
+
+    @Override
+    public void messageReceived(IoSession session, Object message) throws ServiceLocationException {
+    
+	if (message == null || !(message instanceof AbstractSLPMessage)) {
+		return;
+	}
+	AbstractSLPMessage msg = (AbstractSLPMessage) message;
+	
+	
+	
+	InetSocketAddress address = (InetSocketAddress) session.getRemoteAddress();
+	SLPCore.platform.logDebug("RECEIVED (" + msg.getSource() + ":"
+			+ msg.getPort() + ") " + msg.toString());
+
+	switch (msg.getFuncID()) {
+	case AbstractSLPMessage.DAADVERT:
+		// drop message, if noDADiscovery is set
+		if (SLPCore.noDiscovery) {
+			if (SLPCore.discoveryException.equals(address.getAddress().getHostAddress())){
+				SLPCore.addReply(msg, address);
+			} else {
+				SLPCore.platform.logTraceDrop("DROPPED (" + address.getAddress() + ":"
+							+ address.getPort() + ") " + msg.toString()
+							+ "(reason: noDADiscovery is set");
+			}
+			session.close(false);
+			return;
+		}
+
+		DAAdvertisementMessage advert = (DAAdvertisementMessage) message;
+
+		if (advert.getErrorCode() != 0) {
+			SLPCore.platform.logTraceDrop("DROPPED DAADvertisement (" + address.getAddress() + ":"
+					+ address.getPort() + ") " + advert.toString()
+					+ "(reason: " + advert.getErrorCode() + " != 0");
+			session.close(false);
+			return;
+		}
+		// this should also prevent reverse-lookup each time a DA is contacted
+		if (advert.getServiceURL().getHost() != address.getAddress().getHostAddress()) {
+			advert.getServiceURL().setHost(address.getAddress().getHostAddress());
+		}
+
+		// statelessBootTimestamp = 0 means DA is going down
+		if (advert.getStatelessBootTimestamp() == 0) {
+			for (int i=0;i<advert.getScopes().length;i++){
+				String scope = advert.getScopes()[i].toLowerCase().trim();
+				SLPUtils.removeValue(SLPCore.dAs,scope.toLowerCase(), advert.getServiceURL());
+			}
+		} else {
+			for (int i=0;i<advert.getScopes().length;i++){
+				String scope = advert.getScopes()[i].toLowerCase().trim();
+			
+				// If OpenSLP would strictly follow RFC 2608,
+				// it should only send a new statelessBootTimestamp
+				// if it was really rebooted or has lost
+				// registrations for other reasons.
+				// But it looks like OpenSLP sends a new sBT whenever
+				// it sends a DAADVERT so we will just reregister
+				// all of our services if we receive a new DAADVERT
+				// from OpenSLP.
+				
+				
+				SLPUtils.addValue(SLPCore.dAs, scope, advert.getServiceURL().getHost());
+				
+				if (SLPCore.CONFIG.getSecurityEnabled()) {
+					if (!advert.verify()){
+						session.close(false);
+						return;
+					}
+					SLPCore.dASPIs.put(advert.getServiceURL().getHost(), SLPUtils.arrayToList(
+							advert.getSPIs()));
+				}
+
+			}
+
+			synchronized (SLPCore.dAs) {
+				SLPCore.dAs.notifyAll();
+			}
+
+			// if there is a daemon instance, inform it about the discovered
+			// DA
+			if (SLPCore.getDaemon() != null) {
+				if (SLPCore.statelessBootTimestamps.get(advert.getServiceURL().getHost())==null){
+					SLPCore.getDaemon().newDaDiscovered(advert);
+				} else if (SLPCore.statelessBootTimestamps.get(advert.getServiceURL().getHost())<=advert.getStatelessBootTimestamp()){
+					SLPCore.getDaemon().newDaDiscovered(advert);
+				}
+			}
+
+		}
+		SLPCore.platform.logDebug("NEW DA LIST: " + SLPCore.dAs);
+		SLPCore.addReply(advert, new InetSocketAddress(advert.getSource(),advert.getPort()));
+		session.close(false);
+		return;
+
+		// reply messages
+	case AbstractSLPMessage.ATTRRPLY:
+		if (msg.hasUnsupportedMandatoryExtensions()){
+			return;
+		}
+		//if the message comes from a different host and security is enabled, verify the message.
+		// if verification fails, drop the message and throw an exception
+		if (!msg.getSource().equals("127.0.0.1") && SLPCore.CONFIG.getSecurityEnabled()){
+			if (!((AttributeReplyMessage)msg).verify()){
+				throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_FAILED,"Failed to verify AttributeReply");
+			}
+		}
+		SLPCore.addReply(msg, address);
+		session.close(false);
+		return;
+	case AbstractSLPMessage.SRVRPLY:
+		if (msg.hasUnsupportedMandatoryExtensions()){
+			return;
+		}
+		// if the message comes from a different host and security is enabled, verify the message.
+		// if verification fails, drop the message and throw an exception
+		if (!msg.getSource().equals("127.0.0.1") && SLPCore.CONFIG.getSecurityEnabled()){
+			if (!((ServiceReplyMessage)msg).verify()){
+				throw new ServiceLocationException(ServiceLocationException.AUTHENTICATION_FAILED,"Failed to verify ServiceReply");
+			}
+		}
+		SLPCore.addReply(msg, address);
+		session.close(false);
+		return;
+	case AbstractSLPMessage.SRVTYPERPLY:
+		if (msg.hasUnsupportedMandatoryExtensions()){
+			return;
+		}
+		// add the reply to the queue if it has been verified...
+		SLPCore.addReply(msg, address);
+		session.close(false);
+		return;
+		// request messages
+	case AbstractSLPMessage.SRVRQST:
+	case AbstractSLPMessage.ATTRRQST:
+	case AbstractSLPMessage.SRVTYPERQST:
+		// silently drop messages where this peer is in the previous
+		// responder list
+		for (int i = 0; i < SLPCore.myIPs.length; i++) {
+			if (((AbstractSLPRequestMessage) message).knowsResponder(SLPCore.myIPs[i])) {
+				SLPCore.platform.logTraceDrop("DROPPED (" + address.getAddress() + ":"
+							+ address.getPort() + ") " + msg.toString()
+							+ "(udp multicast)");
+				session.close(false);
+				return;
+			}
+		}
+		
+		// if a DA is running, all requests should be passed to it
+		if (SLPCore.getDirectoryAgentDaemon() != null) {
+			AbstractSLPMessage reply = SLPCore.getDirectoryAgentDaemon().handleMessage(msg);
+			if (reply!=null){
+				if (msg.isMulticast()){
+					SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+				} else {
+					if (reply.getSize()>SLPCore.CONFIG.getMTU()){
+						SLPCore.sendMessageTCP(reply, new InetSocketAddress(msg.getSource(),SLPCore.SLP_PORT), false);
+						session.close(false);
+						return;
+					}
+					session.write(reply);
+					SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+							+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+							+ ")");
+				}
+			}
+			session.close(false);
+			return;
+		} 
+		
+
+		// else if we have a daemon instance, delegate the
+		// message to the daemon.
+		if (SLPCore.getDaemon() != null) {
+			AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg);
+			if (reply!=null){
+				if (msg.isMulticast()){
+					SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+				} else {
+					if (reply.getSize()>SLPCore.CONFIG.getMTU()){
+						SLPCore.sendMessageTCP(reply, new InetSocketAddress(msg.getSource(),SLPCore.SLP_PORT), false);
+						session.close(false);
+						return;
+					}
+					session.write(reply);
+					SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+							+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+							+ ")");
+				}
+			}
+			
+			session.close(false);
+			return;
+		} else {
+			SLPCore.platform.logDebug("Request recieved ("
+					+ address.getAddress().getHostAddress() + ":" + address.getPort() + ") "
+					+ msg.toString()
+					+ " but no SLPDaemon to handle the message present");
+			session.close(false);
+			return;
+		}
+	
+	case AbstractSLPMessage.SRVREG:
+		
+		if (SLPCore.CONFIG.getSecurityEnabled()){
+			if (!((ServiceRegistrationMessage)msg).verify()){
+				ServiceAcknowledgementMessage ack = new ServiceAcknowledgementMessage();
+				ack.setXid(msg.getXid());
+				ack.setErrorCode(ServiceLocationException.AUTHENTICATION_FAILED);
+				if (msg.isMulticast()){
+					SLPCore.sendUnicastMessage(ack, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+				} else {
+					session.write(ack);
+					SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+							+ ack + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+							+ ")");
+				}
+			}
+		}
+		
+		// if the reg comes from within the framework, pass it to the SA part...
+		if (SLPUtils.arrayToList(SLPCore.myIPs).contains(msg.getSource())){
+			if (SLPCore.getDaemon()!=null){
+				AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg);
+				if (reply!=null){
+					if (msg.isMulticast()){
+						SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+					} else {
+						session.write(reply);
+						SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+								+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+								+ ")");
+					}
+				}
+				session.close(false);
+				return;
+			}
+		}
+		// this reg comes from outside
+		if (SLPCore.getDirectoryAgentDaemon() != null) {
+			AbstractSLPMessage reply = SLPCore.getDirectoryAgentDaemon().handleMessage(msg);
+			if (reply!=null){
+				if (msg.isMulticast()){
+					SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+				} else {
+					session.write(reply);
+					SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+							+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+							+ ")");
+				}
+			}
+			session.close(false);
+			return;
+		}
+		
+	case AbstractSLPMessage.SRVDEREG:
+		// if the reg comes from within the framework, pass it to the SA part...
+		if (SLPUtils.arrayToList(SLPCore.myIPs).contains(msg.getSource())){
+			if (SLPCore.getDaemon()!=null){
+				AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg);
+				if (reply!=null){
+					if (msg.isMulticast()){
+						SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+					} else {
+						session.write(reply);
+						SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+								+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+								+ ")");
+					}
+				}
+				session.close(false);
+				return;
+			}
+		}
+		// this reg comes from outside
+		if (SLPCore.getDirectoryAgentDaemon() != null) {
+			AbstractSLPMessage reply = SLPCore.getDirectoryAgentDaemon().handleMessage(msg);
+			if (reply!=null){
+				if (msg.isMulticast()){
+					SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+				} else {
+					session.write(reply);
+					SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+							+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+							+ ")");
+				}
+			}
+			session.close(false);
+			return;
+		}
+		
+	case AbstractSLPMessage.SRVACK:
+		if (msg.hasUnsupportedMandatoryExtensions()){
+			return;
+		}
+		
+		SLPCore.addReply(msg, new InetSocketAddress(msg.getSource(),msg.getPort()));
+		return;	
+		
+		
+	default:
+		// if we have a DA running, pass messages (in this case reg and dereg) to it.
+		// the da will relegate reg and deregs coming from the framework on to the SA if present
+		if (SLPCore.getDirectoryAgentDaemon() != null) {
+			AbstractSLPMessage reply = SLPCore.getDirectoryAgentDaemon().handleMessage(msg);
+			if (reply!=null){
+				if (msg.isMulticast()){
+					SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+				} else {
+					session.write(reply);
+					SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+							+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+							+ ")");
+				}
+			}
+			session.close(false);
+			return;
+		} 
+		
+		
+		// if we have a daemon instance but no DA, delegate all other
+		// messages to the daemon.
+		if (SLPCore.getDaemon() != null) {
+			AbstractSLPMessage reply = SLPCore.getDaemon().handleMessage(msg);
+			if (reply!=null){
+				if (msg.isMulticast()){
+					SLPCore.sendUnicastMessage(reply, new InetSocketAddress(msg.getSource(),msg.getPort()), false);
+				} else {
+					session.write(reply);
+					SLPCore.platform.logTraceMessage("SENT (" + msg.getSource() + ":" + msg.getPort() + ") "
+							+ reply + " (via udp port " +((InetSocketAddress) session.getLocalAddress()).getPort()
+							+ ")");
+				}
+			}
+			
+			session.close(false);
+			return;
+		} else {
+			SLPCore.platform.logDebug("A message recieved ("
+					+ address.getAddress() + ":" + address.getPort() + ") "
+					+ msg.toString()
+					+ " but no SLPDaemon to handle the message present");
+			session.close(false);
+			return;
+		}
+	}
+
+}
+
+    @Override
+    public void sessionClosed(IoSession session) throws Exception {
+        
+    }
+
+    @Override
+    public void sessionCreated(IoSession session) throws Exception {
+
+        
+    }
+
+    @Override
+    public void sessionIdle(IoSession session, IdleStatus status)
+            throws Exception {
+        
+    }
+
+    @Override
+    public void sessionOpened(IoSession session) throws Exception {
+        
+    }
+}
+
+
+

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

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/SLPUtils.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,567 @@
+/* 
+ *   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.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.directory.slp.OpaqueValue;
+
+
+/**
+ * Utility class.
+ * 
+ * @author Jan S. Rellermeyer
+ */
+public final class SLPUtils {
+
+	public static final String KEYWORD_STRING = "jslpkeyword";
+	
+	
+	/**
+	 * hidden constructor.
+	 */
+	private  SLPUtils() {
+
+	}
+
+	/**
+	 * get a <code>List</code> of attribute/value pairs in String
+	 * representation from a <code>Dictionary</code>.
+	 * 
+	 * @param attributes
+	 *            the <code>Dictionary</code>
+	 * @return the <code>List</code>.
+	 */
+	public static List<String> dictToAttrList(final Dictionary attributes) {
+		List<String> attList = new ArrayList<String>();
+		if (attributes != null) {
+			for (Enumeration keys = attributes.keys(); keys.hasMoreElements();) {
+				Object key = keys.nextElement();
+				if (attributes.get(key).equals(KEYWORD_STRING)){
+					attList.add(key.toString());
+					continue;
+				}
+				StringBuffer buffer = new StringBuffer();
+				buffer.append("(");
+				buffer.append(key);
+				buffer.append("=");
+				buffer.append(attributes.get(key));
+				buffer.append(")");
+				attList.add(buffer.toString());
+			}
+		}
+		return attList;
+	}
+	
+	
+	public static String dictToString(final Dictionary<String,String> attributes){
+		return listToString(dictToAttrList(attributes), ",");
+	}
+
+	/**
+	 * get a <code>Dictionary</code> of attributes and their values from an
+	 * attribute <code>List</code>.
+	 * 
+	 * @since 0.6
+	 * @param attrList
+	 *            the attribute list.
+	 * @return the <code>Dictionary</code>.
+	 */
+	static Dictionary<String,Object> attrListToDict(final List<String> attrList) {
+		Dictionary<String,Object> dict = new Hashtable<String,Object>();
+
+		for (Iterator iter = attrList.iterator(); iter.hasNext();) {
+			String attrStr = (String) iter.next();
+			attrStr = attrStr.substring(1, attrStr.length() - 1);
+			int pos = attrStr.indexOf("=");
+			if (pos > -1) {
+				String key = attrStr.substring(0, pos).trim();
+				String value = attrStr.substring(pos + 1).trim();
+				dict.put(key, value);
+			}
+		}
+
+		return dict;
+	}
+
+	/**
+	 * This is the most important method of the class. It is used to parse the 
+	 * attribute lists from their string form as received in messages to their typed
+	 * form in the Service object.
+	 * 
+	 * @param arr
+	 * 		The attributes as an array of string representations
+	 * @return
+	 */
+	public static Dictionary<String,Object> stringArrayToDict(final String[] arr){
+		Dictionary<String,Object> dict = new Hashtable<String,Object>();
+		for (int i=0;i<arr.length;i++){
+			String attrStr = arr[i];
+			attrStr = attrStr.substring(1,attrStr.length()-1);
+			int pos = attrStr.indexOf("=");
+			if (pos>-1){
+				String key = attrStr.substring(0, pos).trim();
+				String value = attrStr.substring(pos+1).trim();
+				//added by Lorenz to support multivalued attributes
+				String valueRep = value.replace("\\,", "SLP_ESCAPED_COMMA");
+				String[] valuesRep = valueRep.split(",");
+				String[] valuesFixed = new String[valuesRep.length];
+				int k = 0;
+				for (String s: valuesRep){
+					valuesFixed[k++] = s.replace("SLP_ESCAPED_COMMA", "\\,").trim();
+				}
+				
+				if (valuesFixed.length==1){
+					if (value.toLowerCase().equals("true") || value.toLowerCase().equals("false")) {
+						dict.put(key, new Boolean(value) );
+					} else if (value.startsWith("\\FF")) {
+						dict.put(key, new OpaqueValue(value) );
+					} else {
+						try {
+							int v = Integer.parseInt(value);
+							dict.put(key, v);
+						} catch (NumberFormatException e){
+							dict.put(key, value);
+						} 
+					}
+
+					continue;
+				}
+				
+				Object[] values;
+				String type;
+				String value1 = valuesFixed[0];
+				if (value1.startsWith("\\FF")){
+					values = new OpaqueValue[valuesFixed.length];
+					values[0]=new OpaqueValue(value1);
+					type="opaque";
+				} else if (value1.toLowerCase().equals("true") || value1.toLowerCase().equals("false")){
+					values = new Boolean[valuesFixed.length];
+					values[0]= Boolean.valueOf(value1);
+					type="boolean";
+				} else {
+					try {
+						int v = Integer.parseInt(value1);
+						values = new Number[valuesFixed.length];
+						values[0] = v;
+						type="integer";
+					} catch (NumberFormatException e){
+						values = new String[valuesFixed.length];
+						values[0]=value1;
+						type="string";
+					}
+				}
+				for (int j=1;j<values.length;j++){
+					if (type.equals("opaque")){
+						values[j] = new OpaqueValue(valuesFixed[j]);
+					} else if (type.equals("string")){
+						values[j]=valuesFixed[j];
+					} else if (type.equals("boolean")){
+						values[j]=Boolean.valueOf(valuesFixed[j]);
+					} else {
+						values[j]=Integer.parseInt(valuesFixed[j]);
+					}
+
+				}
+				dict.put(key, values);
+			} else {
+				// this is a keyword attribute, Lorenz decided to handle it as a string
+				dict.put(attrStr,KEYWORD_STRING);
+			}
+		}
+		return dict;
+	}
+	
+	
+	/**
+	 * transforms a Java list to string list.
+	 * 
+	 * @param list
+	 *            the list
+	 * @param delim
+	 *            the delimiter
+	 * @return the String list.
+	 */
+	public static String listToString(final List list, final String delim) {
+		if (list == null || list.size() == 0) {
+			return "";
+		} else if (list.size() == 1) {
+			return list.get(0).toString();
+		} else {
+			final StringBuffer buffer = new StringBuffer();
+			final Object[] elements = list.toArray();
+			for (int i = 0; i < elements.length - 1; i++) {
+				buffer.append(elements[i]);
+				buffer.append(delim);
+			}
+			buffer.append(elements[elements.length - 1]);
+			return buffer.toString();
+		}
+	}
+	
+	/**
+	 * transforms a String-array to a string list.
+	 * 
+	 * @param arr
+	 *            the array
+	 * @param delim
+	 *            the delimiter
+	 * @return the String list.
+	 */
+	public static String arrayToString(final String[] arr, final String delim) {
+		if (arr == null || arr.length == 0) {
+			return "";
+		} else if (arr.length == 1) {
+			return arr[0];
+		} else {
+			final StringBuffer buffer = new StringBuffer();
+			for (int i = 0; i < arr.length - 1; i++) {
+				buffer.append(arr[i]);
+				buffer.append(delim);
+			}
+			buffer.append(arr[arr.length - 1]);
+			return buffer.toString();
+		}
+	}
+
+	/**
+	 * transforms a string list of items separated by delim to Java List.
+	 * 
+	 * @param str
+	 *            the String list
+	 * @param delim
+	 *            the delimiter
+	 * @return the List.
+	 */
+	public static List<String> stringToList(final String str, final String delim) {
+		List<String> result = new ArrayList<String>();
+		String strFixed = str.replace("\\"+delim, "SLP_ESCAPED_DELIM");
+		StringTokenizer tokenizer = new StringTokenizer(strFixed, delim);
+		while (tokenizer.hasMoreTokens()) {
+			result.add(tokenizer.nextToken().replace("SLP_ESCAPED_DELIM", "\\"+delim));
+		}
+		return result;
+	}
+	
+	public static List<String> arrayToList(final String[] arr){
+		List<String> result = new ArrayList<String>();
+		for (int i=0;i< arr.length;i++){
+			result.add(arr[i]);
+		}
+			
+		return result;
+	}
+	
+	public static String[] listToStringArray(final List list){
+		if (list==null){
+			return new String[]{};
+		}
+		if (list.isEmpty()){
+			return new String[]{};
+		}
+		String[] result = new String[list.size()];
+		for (int i = 0;i<result.length;i++){
+			result[i]=(String) list.get(i);
+		}
+		return result;
+	}
+	
+	
+	
+	
+	
+	public static String[] stringToStringArray(String string, String delim){
+		List<String> result = new ArrayList<String>();
+		String strFixed = string.replace("\\"+delim, "SLP_ESCAPED_DELIM");
+		StringTokenizer tokenizer = new StringTokenizer(strFixed, delim);
+		while (tokenizer.hasMoreTokens()) {
+			result.add(tokenizer.nextToken().replace("SLP_ESCAPED_DELIM","\\"+delim));
+		}
+		return result.toArray(new String[]{});
+	}
+	
+	
+
+
+	/**
+	 * add a value to a value list in a Map.
+	 * 
+	 * @param map
+	 *            the map.
+	 * @param key
+	 *            the key.
+	 * @param value
+	 *            the value to be added to the list.
+	 */
+	static void addValue(final Map map, final Object key, final Object value) {
+
+		List values;
+		if ((values = (List) map.get(key)) == null) {
+			values = new ArrayList<Object>();
+		}
+		if (values.contains(value)) {
+			return;
+		}
+		values.add(value);
+		map.put(key, values);
+	}
+
+	/**
+	 * remove a value from a value list in a Map.
+	 * 
+	 * @param map
+	 *            the map.
+	 * @param key
+	 *            the key.
+	 * @param value
+	 *            the value to be removed from the list.
+	 */
+	static void removeValue(final Map map, final Object key, final Object value) {
+		List values;
+		if ((values = (List) map.get(key)) == null) {
+			return;
+		}
+		values.remove(value);
+		if (!values.isEmpty()) {
+			map.put(key, values);
+		} else {
+			map.remove(key);
+		}
+	}
+
+	/**
+	 * remove a value from all keys where it occurs.
+	 * 
+	 * @param map
+	 *            the map.
+	 * @param value
+	 *            the value.
+	 */
+	static void removeValueFromAll(final Map map, final Object value) {
+		final Object[] keys = map.keySet().toArray();
+		for (int i = 0; i < keys.length; i++) {
+			List list = (List) map.get(keys[i]);
+			list.remove(value);
+			if (list.isEmpty()) {
+				map.remove(keys[i]);
+			}
+		}
+	}
+
+	/**
+	 * get the current timestamp as defined in RFC 2608.
+	 * 
+	 * @return the current timestamp.
+	 */
+	public static int getTimestamp() {
+		long systemTime = System.currentTimeMillis();
+		systemTime /= 1000;
+		return (int) systemTime;
+	}
+
+	/**
+	 * find case insensitive matching between a key List and a Dictionary of
+	 * attributes.
+	 * 
+	 * @param keyList
+	 *            the key List.
+	 * @param attributes
+	 *            the attribute Dictionary.
+	 * @return a List of matches.
+	 */
+	public static List<String> findMatches(final List keyList, final Dictionary<String,String> attributes) {
+		List<String> results = new ArrayList<String>();
+		Set<String> caseInsensitiveKeyList = new HashSet<String>();
+		List<String> wildcards = new ArrayList<String>();
+		if (!keyList.isEmpty()) {
+			for (Iterator keys = keyList.iterator(); keys.hasNext();) {
+				String key = (String) keys.next();
+				if (key.indexOf("*") == -1) {
+					caseInsensitiveKeyList.add(key.toLowerCase());
+				} else {
+					wildcards.add(key);
+				}
+			}
+		}
+
+		for (Enumeration keys = attributes.keys(); keys.hasMoreElements();) {
+			String key = (String) keys.nextElement();
+			if (keyList.isEmpty()
+					|| caseInsensitiveKeyList.contains(key.toLowerCase())) {
+				results.add("(" + key + "=" + attributes.get(key).toString()
+						+ ")");
+				continue;
+			}
+			for (Iterator iter = wildcards.iterator(); iter.hasNext();) {
+				String wildcard = (String) iter.next();
+				if (equalsWithWildcard(wildcard.toCharArray(), 0, key
+						.toCharArray(), 0)) {
+					results.add("(" + key + "="
+							+ attributes.get(key).toString() + ")");
+					continue;
+				}
+			}
+
+		}
+		return results;
+	}
+
+	/**
+	 * equality check with wildcards
+	 * 
+	 * @param val
+	 *            the value
+	 * @param valIndex
+	 *            the current position within the value
+	 * @param attr
+	 *            the attribute
+	 * @param attrIndex
+	 *            the current position within the attribute.
+	 * @return true if equals.
+	 */
+	private static boolean equalsWithWildcard(char[] val, int valIndex,
+			char[] attr, int attrIndex) {
+		if (val.length == valIndex) {
+			return attr.length == attrIndex;
+		}
+		if (val[valIndex] == '*') {
+			valIndex++;
+			do {
+				if (equalsWithWildcard(val, valIndex, attr, attrIndex)) {
+					return true;
+				}
+				attrIndex++;
+			} while (attr.length - attrIndex > -1);
+			return false;
+		} else {
+			return (attr.length == attrIndex || attr[attrIndex] != val[valIndex]) ? false
+					: equalsWithWildcard(val, ++valIndex, attr, ++attrIndex);
+		}
+	}
+
+
+	/**
+	 * Merges the SLP attribute-list by merging multiple attributes with the same name and type into one
+	 * 
+	 * @param atts
+	 * 			The atttribute list as a a list of SLP atribute strings (name=value)
+	 * @return
+	 * 			The merged attributes as an array
+	 */
+	public static String[] mergeAttributes(List<String> atts){
+		Map<String,List<String>> ad = new Hashtable<String, List<String>>();
+		List<String> keywords = new ArrayList<String>();
+		
+		for (String s : atts){
+			String[] fields = s.split("=");
+			String at_name = fields[0];
+			if (at_name.startsWith("(")){
+				at_name=at_name.substring(1);
+			}
+			if (at_name.endsWith(")")){
+				at_name=at_name.substring(0, at_name.length()-1);
+			}
+			if (fields.length==1 && !keywords.contains(at_name)){
+				keywords.add(at_name);
+				continue;
+			}
+			if (ad.keySet().contains(at_name)){
+				for (String s2:stringToList(fields[1].substring(0, fields[1].length()-1), ",")){
+					List<String> current = ad.get(at_name);
+					if (!current.contains(s2)){
+						current.add(s2);
+					}
+				}
+				continue;
+			}
+			ad.put(at_name, stringToList(fields[1].substring(0, fields[1].length()-1), ","));
+		}
+		
+		List<String> result = new ArrayList<String>();
+		Set<String> keys = ad.keySet();
+		for (String k:keys){
+			result.add("("+k+"="+listToString(ad.get(k), ",")+")");
+		}
+		for (String kw:keywords){
+			result.add(kw);
+		}
+		return listToStringArray(result);
+		
+	}
+	
+	/**
+	 * Merges the SLP attribute-list by merging multiple attributes with the same name and type into one
+	 * 
+	 * @param atts
+	 * 			The atttribute list as a an array of SLP atribute strings (name=value)
+	 * @return
+	 * 			The merged attributes as an array
+	 */
+	public static String[] mergeAttributes(String[] atts){
+		Map<String,List<String>> ad = new Hashtable<String, List<String>>();
+		List<String> keywords = new ArrayList<String>();
+		
+		for (String s : atts){
+			String[] fields = s.split("=");
+			String at_name = fields[0];
+			if (at_name.startsWith("(")){
+				at_name=at_name.substring(1);
+			}
+			if (at_name.endsWith(")")){
+				at_name=at_name.substring(0, at_name.length()-1);
+			}
+			if (fields.length==1 && !keywords.contains(at_name)){
+				keywords.add(at_name);
+				continue;
+			}
+			if (ad.keySet().contains(at_name)){
+				for (String s2:stringToList(fields[1].substring(0, fields[1].length()-1), ",")){
+					List<String> current = ad.get(at_name);
+					if (!current.contains(s2)){
+						current.add(s2);
+					}
+				}
+				continue;
+			}
+			ad.put(at_name, stringToList(fields[1].substring(0, fields[1].length()-1), ","));
+		}
+		
+		List<String> result = new ArrayList<String>();
+		Set<String> keys = ad.keySet();
+		for (String k:keys){
+			result.add("("+k+"="+listToString(ad.get(k), ",")+")");
+		}
+		for (String kw:keywords){
+			result.add(kw);
+		}
+		return listToStringArray(result);
+		
+	}
+
+}

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

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceLocationEnumerationImpl.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,97 @@
+/* 
+ *   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.Iterator;
+import java.util.List;
+
+import org.apache.directory.slp.ServiceLocationEnumeration;
+import org.apache.directory.slp.ServiceLocationException;
+
+
+/**
+ * the implementation of a ServiceLocationEnumeration.
+ * 
+ * @see org.apache.directory.slp.ServiceLocationEnumeration
+ * @author Jan S. Rellermeyer
+ */
+class ServiceLocationEnumerationImpl implements ServiceLocationEnumeration {
+	/**
+	 * a list of results.
+	 */
+	private List<String> list;
+
+	/**
+	 * internal Iterator over the elements of the list.
+	 */
+	private Iterator iterator;
+
+	/**
+	 * creates a new ServiceLocationEnumerationImpl.
+	 * 
+	 * @param resultList
+	 *            a list of results.
+	 */
+	ServiceLocationEnumerationImpl(final List<String> resultList) {
+		list = resultList != null ? resultList : new ArrayList<String>();
+		this.iterator = list.iterator();
+	}
+
+	/**
+	 * returns the next element of the Enumeration.
+	 * 
+	 * @return the next element.
+	 * @throws ServiceLocationException
+	 *             if there is no more element.
+	 * @see org.apache.directory.slp.ServiceLocationEnumeration#next()
+	 */
+	public synchronized Object next() throws ServiceLocationException {
+		try {
+			return iterator.next();
+		} catch (Exception e) {
+			throw new ServiceLocationException(
+					ServiceLocationException.INTERNAL_SYSTEM_ERROR, e
+							.getMessage());
+		}
+	}
+
+	/**
+	 * checks if the Enumeration has more elements.
+	 * 
+	 * @return true if there are more elements available.
+	 */
+	public synchronized boolean hasMoreElements() {
+		return iterator.hasNext();
+	}
+
+	/**
+	 * returns the next elenemt of the Enumeration.
+	 * 
+	 * @return the next element or null if there aren't any more.
+	 */
+	public synchronized Object nextElement() {
+		try {
+			return next();
+		} catch (ServiceLocationException sle) {
+			return null;
+		}
+	}
+}

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

Added: directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java
URL: http://svn.apache.org/viewvc/directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java?rev=782968&view=auto
==============================================================================
--- directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java (added)
+++ directory/sandbox/slp/src/main/java/org/apache/directory/slp/impl/ServiceReplyFutureImpl.java Tue Jun  9 12:00:29 2009
@@ -0,0 +1,208 @@
+/* 
+ *   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.Service;
+import org.apache.directory.slp.ServiceLocationException;
+import org.apache.directory.slp.ServiceReplyFuture;
+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.extensions.UnsupportedExtension;
+import org.apache.directory.slp.messages.AbstractSLPReplyMessage;
+import org.apache.directory.slp.messages.ServiceReplyMessage;
+
+/**
+ * 
+ * @author Lorenz Breu
+ */
+public class ServiceReplyFutureImpl extends NonThreadedReplyFuture implements
+		ServiceReplyFuture {
+
+	// List of responses (i.e. message results)
+	private final List<Service> services = new ArrayList<Service>();
+
+	// next service to return when next() is called
+	private int nextServicePosition = 0;
+
+	/**
+	 * Creates a new ServiceReplyFuture with a timeout of 5x the WaitTime in
+	 * SLPConfiguration
+	 */
+	public ServiceReplyFutureImpl() {
+		super(SLPCore.CONFIG.getWaitTime() * 5);
+	}
+
+	/**
+	 * Creates a new ServiceReplyFuture with the specified lifetime (in ms)
+	 * 
+	 * @param lifetime
+	 *            The time until the ReplyFuture is considered done in ms
+	 */
+	public ServiceReplyFutureImpl(long lifetime) {
+		super(lifetime);
+	}
+
+	/**
+	 * Creates a new AttributeReplyFuture with the specified lifetime (in ms)
+	 * expecting responses for the specified scopes.
+	 * 
+	 * @param lifetime
+	 *            The lifetime in ms
+	 * @param scopes
+	 *            The scopes for which replies are expected. used for completion
+	 *            checks
+	 */
+	public ServiceReplyFutureImpl(long lifetime, List<String> scopes) {
+		super(lifetime, scopes);
+	}
+
+	@Override
+	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;
+			}
+		}
+
+		if (reply instanceof ServiceReplyMessage) {
+			for (String s : reply.getResult()) {
+				try {
+					Service srv = new Service(new ServiceURL(s, 0));
+					synchronized (services) {
+						services.add(srv);
+					}
+
+				} catch (ServiceLocationException sle) {
+					continue;
+				}
+			}
+			processExtensions(reply);
+
+		}
+
+		// stick to the basic behaviour...
+		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();
+			}
+		}
+
+	}
+
+	/**
+	 * Process the extensions
+	 * 
+	 * @param reply
+	 *            The reply message possibly containing extensions
+	 * 
+	 */
+	private void processExtensions(AbstractSLPReplyMessage reply) {
+		for (AbstractExtension ae : reply.getExtensions()) {
+			if (ae instanceof UnsupportedExtension) {
+				return;
+			}
+			switch (ae.getId()) {
+			case AbstractExtension.ATTRIBUTE_LIST_EXTENSION:
+				AttributeListExtension ale = (AttributeListExtension) ae;
+				if (SLPCore.CONFIG.getSecurityEnabled()) {
+					if (!ale.verify()) {
+						return;
+					}
+				}
+				synchronized (services) {
+					for (Service srv : services) {
+						if (srv.toString().toLowerCase().equals(
+								ale.getUrl().toLowerCase())) {
+							srv.setAttributes(SLPUtils
+									.stringArrayToDict(SLPUtils
+											.stringToStringArray(ale
+													.getAttributeList(), ",")));
+						}
+					}
+				}
+
+			}
+		}
+	}
+
+	public Service nextService() {
+		// 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 (services) {
+			while (!done) {
+				if (services.size() > nextServicePosition) {
+					return services.get(nextServicePosition++);
+				}
+				try {
+					services.wait(timeout - System.currentTimeMillis() + 1000);
+				} catch (InterruptedException e) {
+
+				}
+			}
+			if (services.size() > nextServicePosition) {
+				return services.get(nextServicePosition++);
+			}
+			return null;
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see ch.ethz.iks.slp.ServiceReplyFuture#getResultServices()
+	 */
+	public List<Service> getResultServices() {
+		while (!done) {
+			synchronized (donelock) {
+				try {
+					donelock.wait();
+				} catch (InterruptedException ie) {
+
+				}
+			}
+		}
+		return services;
+	}
+
+}

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