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