Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormkuppe2008-10-08 07:18:57 +0000
committermkuppe2008-10-08 07:18:57 +0000
commit7874355d938ba0a8ee5837754f6b3176a2398785 (patch)
treec0329eefad34537d1e12d2cbd9f94a49e90b8997
parente7a10709b751f2d84f26ab3922b76c1f97cf26b0 (diff)
downloadorg.eclipse.ecf-7874355d938ba0a8ee5837754f6b3176a2398785.tar.gz
org.eclipse.ecf-7874355d938ba0a8ee5837754f6b3176a2398785.tar.xz
org.eclipse.ecf-7874355d938ba0a8ee5837754f6b3176a2398785.zip
https://bugs.eclipse.org/bugs/show_bug.cgi?id=244784
https://dev.eclipse.org/ipzilla/show_bug.cgi?id=2585
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/.checkstyle6
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/.classpath11
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/.project36
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.wst.validation.prefs6
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/META-INF/MANIFEST.MF9
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/build.properties7
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/maven-site-jslp.vm353
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/pom.xml198
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/runtimeTests/pom.xml52
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/SelfDiscoveryTest.java108
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/TestActivator.java58
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Advertiser.java161
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Locator.java148
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationEnumeration.java49
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationException.java167
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceType.java252
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceURL.java373
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Activator.java81
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AdvertiserImpl.java237
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeReply.java239
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeRequest.java207
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticatedURL.java174
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticationBlock.java266
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/DAAdvertisement.java269
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/LocatorImpl.java315
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/OSGiPlatformAbstraction.java234
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/PlatformAbstraction.java127
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ReplyMessage.java53
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/RequestMessage.java52
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPConfiguration.java524
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPCore.java997
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemon.java61
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemonImpl.java606
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPMessage.java443
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPUtils.java262
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Service.java101
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceAcknowledgement.java130
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceDeregistration.java185
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceLocationEnumerationImpl.java106
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRegistration.java288
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceReply.java194
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRequest.java191
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeReply.java143
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeRequest.java180
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/filter/Filter.java54
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/package.html3
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/package.html3
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/main/resources/LICENSE.txt27
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/resources/images/jSLP.jpgbin0 -> 4852 bytes
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/site.xml53
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/index.xml42
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/index.xml30
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/userguide.xml97
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/index.xml57
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/modularity.xml49
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/userguide.xml145
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/properties.xml130
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/security.xml44
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/using.xml56
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/src/test/java/ch/ethz/iks/slp/impl/ServiceURLTest.java114
-rw-r--r--protocols/bundles/ch.ethz.iks.slp/test/init.xargs6
62 files changed, 9581 insertions, 0 deletions
diff --git a/protocols/bundles/ch.ethz.iks.slp/.checkstyle b/protocols/bundles/ch.ethz.iks.slp/.checkstyle
new file mode 100644
index 000000000..041374e14
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/.checkstyle
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<fileset-config file-format-version="1.2.0" simple-config="true">
+ <fileset name="Alle" enabled="true" check-config-name="Sun Checks (Eclipse)" local="false">
+ <file-match-pattern match-pattern="." include-pattern="true"/>
+ </fileset>
+</fileset-config>
diff --git a/protocols/bundles/ch.ethz.iks.slp/.classpath b/protocols/bundles/ch.ethz.iks.slp/.classpath
new file mode 100644
index 000000000..31e4b8c95
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.2"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="con" path="com.buglabs.osgi.concierge.jdt.OSGiBundleClassPathContainerInitializer"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/protocols/bundles/ch.ethz.iks.slp/.project b/protocols/bundles/ch.ethz.iks.slp/.project
new file mode 100644
index 000000000..9a54f00bb
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/.project
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>ch.ethz.iks.slp</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ <nature>com.buglabs.osgi.concierge.natures.ConciergeProjectNature</nature>
+ <nature>com.atlassw.tools.eclipse.checkstyle.CheckstyleNature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
diff --git a/protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.jdt.core.prefs b/protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..7c8bc64a8
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Fri Nov 16 15:54:18 CET 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.1
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.3
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=ignore
+org.eclipse.jdt.core.compiler.source=1.3
diff --git a/protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.wst.validation.prefs b/protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 000000000..43dc60c08
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,6 @@
+#Wed May 31 17:52:13 CEST 2006
+DELEGATES_PREFERENCE=delegateValidatorListorg.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator\=org.eclipse.wst.xsd.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator\=org.eclipse.wst.wsdl.validation.internal.eclipse.Validator;
+USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.jst.jsp.core.internal.validation.JSPJavaValidator;org.eclipse.jst.jsp.core.internal.validation.JSPELValidator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.jst.jsp.core.internal.validation.JSPDirectiveValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;
+USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.wsi.ui.internal.WSIMessageValidator;org.eclipse.jst.jsp.core.internal.validation.JSPJavaValidator;org.eclipse.jst.jsp.core.internal.validation.JSPELValidator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.jst.jsp.core.internal.validation.JSPDirectiveValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;
+USER_PREFERENCE=overrideGlobalPreferencesfalse
+eclipse.preferences.version=1
diff --git a/protocols/bundles/ch.ethz.iks.slp/META-INF/MANIFEST.MF b/protocols/bundles/ch.ethz.iks.slp/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..865bbde9d
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-Name: jslp-osgi
+Bundle-SymbolicName: ch.ethz.iks.slp
+Bundle-Version: 1.0.0.qualifier
+Export-Package: ch.ethz.iks.slp
+Bundle-Activator: ch.ethz.iks.slp.impl.Activator
+Bundle-Vendor: Jan S. Rellermeyer, IKS, ETH Zurich
+Import-Package: org.osgi.framework, org.osgi.service.log
+Bundle-Description: jSLP, the pure Java Service Location Protocol implementation
diff --git a/protocols/bundles/ch.ethz.iks.slp/build.properties b/protocols/bundles/ch.ethz.iks.slp/build.properties
new file mode 100644
index 000000000..c5b2afb74
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/build.properties
@@ -0,0 +1,7 @@
+source.. = src/main/java/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
+src.includes = META-INF/,\
+ src/main/java/
+
diff --git a/protocols/bundles/ch.ethz.iks.slp/maven-site-jslp.vm b/protocols/bundles/ch.ethz.iks.slp/maven-site-jslp.vm
new file mode 100644
index 000000000..7b1e6c351
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/maven-site-jslp.vm
@@ -0,0 +1,353 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+#macro ( banner $banner $id )
+ #if ( $banner )
+ #if( $banner.href )
+ <a href="$banner.href" id="$id">
+ #else
+ <span id="$id">
+ #end
+
+ #if( $banner.src )
+ #set ( $src = $banner.src )
+ #if ( ! ( $src.toLowerCase().startsWith("http") || $src.toLowerCase().startsWith("https") ) )
+ #set ( $src = $PathTool.calculateLink( $src, $relativePath ) )
+ #set ( $src = $src.replaceAll( "\\", "/" ) )
+ #end
+ #if ( $banner.alt )
+ #set ( $alt = $banner.alt )
+ #else
+ #set ( $alt = "" )
+ #end
+ <img src="$src" alt="$alt" />
+ #else
+ $banner.name
+ #end
+
+ #if( $banner.href )
+ </a>
+ #else
+ </span>
+ #end
+ #end
+#end
+
+#macro ( links $links )
+ #set ( $counter = 0 )
+ #foreach( $item in $links )
+ #set ( $counter = $counter + 1 )
+ #set ( $currentItemHref = $PathTool.calculateLink( $item.href, $relativePath ) )
+ #set ( $currentItemHref = $currentItemHref.replaceAll( "\\", "/" ) )
+ <a href="$currentItemHref">$item.name</a>
+ #if ( $links.size() > $counter )
+ |
+ #end
+ #end
+#end
+
+#macro ( breadcrumbs $breadcrumbs )
+ #set ( $counter = 0 )
+ #foreach( $item in $breadcrumbs )
+ #set ( $counter = $counter + 1 )
+ #set ( $currentItemHref = $PathTool.calculateLink( $item.href, $relativePath ) )
+ #set ( $currentItemHref = $currentItemHref.replaceAll( "\\", "/" ) )
+
+ #if ( $currentItemHref == $alignedFileName || $currentItemHref == "" )
+ $item.name
+ #else
+ <a href="$currentItemHref">$item.name</a>
+ #end
+ #if ( $breadcrumbs.size() > $counter )
+ &gt;
+ #end
+ #end
+#end
+
+#macro ( displayTree $display $item )
+ #if ( $item && $item.items && $item.items.size() > 0 )
+ #foreach( $subitem in $item.items )
+ #set ( $subitemHref = $PathTool.calculateLink( $subitem.href, $relativePath ) )
+ #set ( $subitemHref = $subitemHref.replaceAll( "\\", "/" ) )
+
+ #if ( $alignedFileName == $subitemHref )
+ #set ( $display = true )
+ #end
+
+ #displayTree( $display $subitem )
+ #end
+ #end
+#end
+
+#macro ( menuItem $item )
+ #set ( $collapse = "none" )
+ #set ( $currentItemHref = $PathTool.calculateLink( $item.href, $relativePath ) )
+ #set ( $currentItemHref = $currentItemHref.replaceAll( "\\", "/" ) )
+
+ #if ( $item && $item.items && $item.items.size() > 0 )
+ #if ( $item.collapse == false )
+ #set ( $collapse = "expanded" )
+ #else
+ ## By default collapsed
+ #set ( $collapse = "collapsed" )
+ #end
+
+ #set ( $display = false )
+ #displayTree( $display $item )
+
+ #if ( $alignedFileName == $currentItemHref || $display )
+ #set ( $collapse = "expanded" )
+ #end
+ #end
+ <li class="$collapse">
+ #if ( $item.img )
+ #if ( ! ( $item.img.toLowerCase().startsWith("http") || $item.img.toLowerCase().startsWith("https") ) )
+ #set ( $src = $PathTool.calculateLink( $item.img, $relativePath ) )
+ #set ( $src = $item.img.replaceAll( "\\", "/" ) )
+ <img src="$src"/>
+ #else
+ <img src="$item.img" align="absbottom" style="border-width: 0"/>
+ #end
+ #end
+ #if ( $alignedFileName == $currentItemHref )
+ <strong>$item.name</strong>
+ #else
+ <a href="$currentItemHref">$item.name</a>
+ #end
+ #if ( $item && $item.items && $item.items.size() > 0 )
+ #if ( $collapse == "expanded" )
+ <ul>
+ #foreach( $subitem in $item.items )
+ #menuItem( $subitem )
+ #end
+ </ul>
+ #end
+ #end
+ </li>
+#end
+
+#macro ( mainMenu $menus )
+ #foreach( $menu in $menus )
+ #if ( $menu.name )
+ <h5>$menu.name</h5>
+ #end
+ <ul>
+ #foreach( $item in $menu.items )
+ #menuItem( $item )
+ #end
+ </ul>
+ #end
+#end
+
+#macro ( copyright )
+ #if ( $project )
+ #set ( $currentYear = ${currentDate.year} + 1900 )
+
+ #if ( ${project.inceptionYear} && ( ${project.inceptionYear} != ${currentYear.toString()} ) )
+ ${project.inceptionYear}-${currentYear}
+ #else
+ ${currentYear}
+ #end
+
+ #if ( ${project.organization} && ${project.organization.name} )
+ ${project.organization.name}
+ #end
+ #end
+#end
+
+#macro ( publishDate $position $publishDate $version )
+ #if ( $publishDate && $publishDate.format )
+ #set ( $format = $publishDate.format )
+ #else
+ #set ( $format = "MM/dd/yyyy" )
+ #end
+
+ $dateFormat.applyPattern( $format )
+
+ #set ( $dateToday = $dateFormat.format( $currentDate ) )
+
+ #if ( $publishDate && $publishDate.position )
+ #set ( $datePosition = $publishDate.position )
+ #else
+ #set ( $datePosition = "left" )
+ #end
+
+ #if ( $version )
+ #if ( $version.position )
+ #set ( $versionPosition = $version.position )
+ #else
+ #set ( $versionPosition = "left" )
+ #end
+ #end
+
+ #set ( $breadcrumbs = $decoration.body.breadcrumbs )
+
+ #if ( $datePosition.equalsIgnoreCase( $position ) )
+ #if ( ( $datePosition.equalsIgnoreCase( "right" ) ) || ( $datePosition.equalsIgnoreCase( "bottom" ) ) )
+ &nbsp;| $i18n.getString( "site-renderer", $locale, "template.lastpublished" ): $dateToday
+ #if ( $versionPosition.equalsIgnoreCase( $position ) )
+ &nbsp;| $i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}
+ #end
+ #elseif ( ( $datePosition.equalsIgnoreCase( "navigation-bottom" ) ) || ( $datePosition.equalsIgnoreCase( "navigation-top" ) ) )
+ <div id="lastPublished">
+ $i18n.getString( "site-renderer", $locale, "template.lastpublished" ): $dateToday
+ #if ( $versionPosition.equalsIgnoreCase( $position ) )
+ &nbsp;| $i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}
+ #end
+ </div>
+ #elseif ( $datePosition.equalsIgnoreCase("left") )
+ <div class="xleft">
+ $i18n.getString( "site-renderer", $locale, "template.lastpublished" ): $dateToday
+ #if ( $versionPosition.equalsIgnoreCase( $position ) )
+ &nbsp;| $i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}
+ #end
+ #if ( $breadcrumbs && $breadcrumbs.size() > 0 )
+ | #breadcrumbs( $breadcrumbs )
+ #end
+ </div>
+ #end
+ #elseif ( $versionPosition.equalsIgnoreCase( $position ) )
+ #if ( ( $versionPosition.equalsIgnoreCase( "right" ) ) || ( $versionPosition.equalsIgnoreCase( "bottom" ) ) )
+ &nbsp;| $i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}
+ #elseif ( ( $versionPosition.equalsIgnoreCase( "navigation-bottom" ) ) || ( $versionPosition.equalsIgnoreCase( "navigation-top" ) ) )
+ <div id="lastPublished">
+ $i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}
+ </div>
+ #elseif ( $versionPosition.equalsIgnoreCase("left") )
+ <div class="xleft">
+ $i18n.getString( "site-renderer", $locale, "template.version" ): ${project.version}
+ #if ( $breadcrumbs && $breadcrumbs.size() > 0 )
+ | #breadcrumbs( $breadcrumbs )
+ #end
+ </div>
+ #end
+ #elseif ( $position.equalsIgnoreCase( "left" ) )
+ #if ( $breadcrumbs && $breadcrumbs.size() > 0 )
+ <div class="xleft">
+ #breadcrumbs( $breadcrumbs )
+ </div>
+ #end
+ #end
+#end
+
+#macro ( poweredByLogo $poweredBy )
+ #if( $poweredBy )
+ #foreach ($item in $poweredBy)
+ #if( $item.href )
+ #set ( $href = $PathTool.calculateLink( $item.href, $relativePath ) )
+ #set ( $href = $href.replaceAll( "\\", "/" ) )
+ #else
+ #set ( $href="http://maven.apache.org/" )
+ #end
+
+ #if( $item.name )
+ #set ( $name = $item.name )
+ #else
+ #set ( $name = $i18n.getString( "site-renderer", $locale, "template.builtby" ) )
+ #set ( $name = "${name} Maven" )
+ #end
+
+ #if( $item.img )
+ #set ( $img = $item.img )
+ #else
+ #set ( $img = "images/maven-feather.png" )
+ #end
+
+ <a href="$href" title="$name" id="poweredBy">
+ #set ( $img = $PathTool.calculateLink( $img, $relativePath ) )
+ #set ( $img = $img.replaceAll( "\\", "/" ) )
+ <img alt="$name" src="$img" />
+ </a>
+ #end
+ #if( $poweredBy.isEmpty() )
+ <a href="http://maven.apache.org/" title="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" id="poweredBy">
+ <img alt="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" src="$relativePath/images/maven-feather.png"></img>
+ </a>
+ <center>
+ <a href="http://sourceforge.net/projects/jslp">
+ <img src="http://sourceforge.net/sflogo.php?group_id=151721&amp;type=3" border="0" alt="sf logo"/>
+ </a>
+ </center>
+
+<!-- Start of StatCounter Code -->
+<script type="text/javascript">
+<!--
+var sc_project=1666943;
+var sc_invisible=1;
+var sc_partition=11;
+var sc_security="1d05fd8a";
+//-->
+</script>
+
+<script type="text/javascript" src="http://www.statcounter.com/counter/counter_xhtml.js"></script><noscript><div class="statcounter"><a class="statcounter" href="http://www.statcounter.com/"><img class="statcounter" src="http://c12.statcounter.com/counter.php?sc_project=1666943&java=0&security=1d05fd8a&invisible=1" alt="counter easy hit" /></a></div></noscript>
+<!-- End of StatCounter Code -->
+
+ #end
+ #else
+ <a href="http://maven.apache.org/" title="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" id="poweredBy">
+ <img alt="$i18n.getString( "site-renderer", $locale, "template.builtby" ) Maven" src="$relativePath/images/maven-feather.png"></img>
+ </a>
+ #end
+#end
+
+<html>
+ <head>
+ <title>$title</title>
+ <style type="text/css" media="all">
+ @import url("$relativePath/css/maven-base.css");
+ @import url("$relativePath/css/maven-theme.css");
+ @import url("$relativePath/css/site.css");
+ </style>
+ <link rel="stylesheet" href="$relativePath/css/print.css" type="text/css" media="print" />
+ #foreach( $author in $authors )
+ <meta name="author" content="$author" />
+ #end
+ <meta http-equiv="Content-Type" content="text/html; charset=${outputEncoding}" />
+ #if ( $decoration.body.head )
+ #foreach( $item in $decoration.body.head.getChildren() )
+ #if ( $item.name == "script" )
+ $item.toUnescapedString()
+ #else
+ $item.toString()
+ #end
+ #end
+ #end
+ </head>
+ <body class="composite">
+ <div id="banner">
+ #banner( $decoration.bannerLeft "bannerLeft" )
+ #banner( $decoration.bannerRight "bannerRight" )
+ <div class="clear">
+ <hr/>
+ </div>
+ </div>
+ <div id="breadcrumbs">
+ #publishDate( "left" $decoration.publishDate $decoration.version )
+ <div class="xright">#links( $decoration.body.links )#publishDate( "right" $decoration.publishDate $decoration.version )</div>
+ <div class="clear">
+ <hr/>
+ </div>
+ </div>
+ <div id="leftColumn">
+ <div id="navcolumn">
+ #publishDate( "navigation-top" $decoration.publishDate $decoration.version )
+ #mainMenu( $decoration.body.menus )
+ #poweredByLogo( $decoration.poweredBy )
+ #publishDate( "navigation-bottom" $decoration.publishDate $decoration.version )
+ </div>
+ </div>
+ <div id="bodyColumn">
+ <div id="contentBox">
+ $bodyContent
+ </div>
+ </div>
+ <div class="clear">
+ <hr/>
+ </div>
+ <div id="footer">
+ <div class="xright">&#169;#copyright()#publishDate( "bottom" $decoration.publishDate $decoration.version )</div>
+ <div class="clear">
+ <hr/>
+ </div>
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/pom.xml b/protocols/bundles/ch.ethz.iks.slp/pom.xml
new file mode 100644
index 000000000..b8fc7afd1
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/pom.xml
@@ -0,0 +1,198 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <name>jSLP-OSGi</name>
+ <groupId>ch.ethz.iks.slp</groupId>
+ <artifactId>jslp-osgi</artifactId>
+ <version>1.0.0.RC5</version>
+ <packaging>bundle</packaging>
+
+ <url>http://jslp.sourceforge.net</url>
+
+ <organization>
+ <name>IKS, ETH Zurich</name>
+ <url>http://www.iks.inf.ethz.ch</url>
+ </organization>
+
+ <developers>
+ <developer>
+ <id>rjan</id>
+ <name>Jan S. Rellermeyer</name>
+ <email>rellermeyer_at_inf.ethz.ch</email>
+ <url>http://people.inf.ethz.ch/rjan</url>
+ <organization>IKS, ETH Zurich</organization>
+ <organizationUrl>http://www.iks.inf.ethz.ch</organizationUrl>
+ <roles>
+ <role>Project creator</role>
+ <role>Researcher</role>
+ </roles>
+ <timezone>+1</timezone>
+ </developer>
+ <developer>
+ <id>lemmster</id>
+ <name>Markus Alexander Kuppe</name>
+ <email>jslp.sf.net_at_lemmster.de</email>
+ <url>http://www.lemmster.de</url>
+ <organization>Versant GmbH</organization>
+ <organizationUrl>http://www.versant.com</organizationUrl>
+ <roles>
+ <role>Developer</role>
+ </roles>
+ <timezone>+1</timezone>
+ </developer>
+ </developers>
+
+ <licenses>
+ <license>
+ <name>BSD license</name>
+ <distribution>repo</distribution>
+ <url>src/main/resources/LICENSE.txt</url>
+ </license>
+ </licenses>
+
+ <scm>
+ <connection>scm:svn:https://jslp.svn.sourceforge.net/svnroot/jslp</connection>
+ <developerConnection>scm:svn:rjan@https://jslp.svn.sourceforge.net/svnroot/jslp</developerConnection>
+ <url>http://jslp.svn.sourceforge.net/jslp</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>integration-test</phase>
+ <configuration>
+ <tasks>
+ <echo message="Compiling the unit test environment..."/>
+ <mkdir dir="runtimeTests/target"/>
+ <condition property="maven.executable" value="mvn.bat">
+ <os family="windows" />
+ </condition>
+ <property name="maven.executable" value="mvn" />
+ <exec dir="runtimeTests" executable="${maven.executable}">
+ <arg line="package"/>
+ </exec>
+ <delete dir="test/storage" quiet="true"/>
+ <java fork="true" classname="ch.ethz.iks.concierge.framework.Framework" failonerror="true" resultproperty="testresult">
+ <classpath>
+ <pathelement location="test/concierge-1.0.0.RC2.jar"/>
+ <pathelement location="test/junit.jar"/>
+ </classpath>
+ <jvmarg value="-Dxargs=test/init.xargs"/>
+ <jvmarg value="-Dnet.slp.port=10427"/>
+ </java>
+ <delete dir="test/storage" quiet="true"/>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.2</source>
+ <target>1.1</target>
+ <optimize>true</optimize>
+ <debug>false</debug>
+ </configuration>
+ </plugin>
+ <!-- http://felix.apache.org/site/maven-bundle-plugin-bnd.html -->
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Include-Resource>{maven-resources}, {maven-dependencies}, target/classes</Include-Resource>
+ <Bundle-Version>${pom.version}</Bundle-Version>
+ <Bundle-Name>jslp-osgi</Bundle-Name>
+ <Bundle-SymbolicName>ch.ethz.iks.slp</Bundle-SymbolicName>
+ <_include>~META-INF/MANIFEST.MF</_include>
+ <!-- BND just produces Bundle-ManifestVersion: 2 headers which we don't want -->
+ <_removeheaders>Bundle-ManifestVersion</_removeheaders>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ </resources>
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <artifactId>maven-site-plugin</artifactId>
+ <configuration>
+ <templateFile>maven-site-jslp.vm</templateFile>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>ch.ethz.iks.slp.impl,org.osgi.service.log</excludePackageNames>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi</artifactId>
+ <version>3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.0.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <repositories>
+ <repository>
+ <id>iks-repository</id>
+ <name>ETH Zurich IKS Repository</name>
+ <url>http://www.flowsgi.inf.ethz.ch/repository/maven2/</url>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>apache snapshot</id>
+ <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+ </pluginRepository>
+ <pluginRepository>
+ <id>iks-repository</id>
+ <name>ETH Zurich IKS Repository</name>
+ <url>http://www.flowsgi.inf.ethz.ch/repository/maven2/</url>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <distributionManagement>
+ <site>
+ <id>sourceforge-site</id>
+ <url>scp://shell.sourceforge.net/home/groups/j/js/jslp/htdocs/</url>
+ </site>
+ <repository>
+ <id>iks-snapshots</id>
+ <name>ETH Zurich IKS Snapshots</name>
+ <url>scp://flowsgi.inf.ethz.ch/repository/maven2</url>
+ </repository>
+ </distributionManagement>
+</project> \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/runtimeTests/pom.xml b/protocols/bundles/ch.ethz.iks.slp/runtimeTests/pom.xml
new file mode 100644
index 000000000..b2dae2961
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/runtimeTests/pom.xml
@@ -0,0 +1,52 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <name>jSLP-Test</name>
+ <groupId>ch.ethz.iks.slp</groupId>
+ <artifactId>jslp-test</artifactId>
+ <version>1.0.0.RC5</version>
+ <packaging>osgi-bundle</packaging>
+
+ <build>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix.plugins</groupId>
+ <artifactId>maven-osgi-plugin</artifactId>
+ <extensions>true</extensions>
+ <version>0.9.0-incubator-SNAPSHOT</version>
+ <configuration>
+ <osgiManifest>
+ <bundleActivator>ch.ethz.iks.slp.impl.TestActivator</bundleActivator>
+ <bundleName>jslp-test</bundleName>
+ <bundleSymbolicName>ch.ethz.iks.slp.test</bundleSymbolicName>
+ <bundleVendor>Jan S. Rellermeyer, IKS, ETH Zurich</bundleVendor>
+ <importPackage>org.osgi.framework, ch.ethz.iks.slp, junit.framework, junit.textui</importPackage>
+ </osgiManifest>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi</artifactId>
+ <version>3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.ethz.iks.slp</groupId>
+ <artifactId>jslp-osgi</artifactId>
+ <version>${pom.version}</version>
+ <scope>system</scope>
+ <systemPath>${user.dir}/target/jslp-osgi-${pom.version}.jar</systemPath>
+ </dependency>
+ </dependencies>
+
+</project> \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/SelfDiscoveryTest.java b/protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/SelfDiscoveryTest.java
new file mode 100644
index 000000000..d979a124c
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/SelfDiscoveryTest.java
@@ -0,0 +1,108 @@
+package ch.ethz.iks.slp.impl;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import ch.ethz.iks.slp.ServiceLocationEnumeration;
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceType;
+import ch.ethz.iks.slp.ServiceURL;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+public class SelfDiscoveryTest extends TestCase {
+
+ private ServiceURL service;
+
+ public SelfDiscoveryTest() {
+ super("runTests");
+ }
+
+ public void setUp() throws InterruptedException {
+ try {
+ service = new ServiceURL("service:osgi://gantenbein:123", 10800);
+ Dictionary properties = new Hashtable();
+ properties.put("attr", Boolean.FALSE);
+ properties.put("other", "value");
+ TestActivator.advertiser.register(service, properties);
+ } catch (ServiceLocationException e) {
+ Assert.fail(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ public void tearDown() throws InterruptedException {
+ try {
+ TestActivator.advertiser.deregister(service);
+ } catch (ServiceLocationException e) {
+ Assert.fail(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ public void runTests() throws Exception {
+ testService();
+ testAttributes();
+ testFilter();
+ testFilter2();
+ }
+
+ public void testService() throws Exception {
+
+ System.out.println("locating service:osgi");
+ int count = 0;
+ for (ServiceLocationEnumeration services = TestActivator.locator
+ .findServices(new ServiceType("service:osgi"), null, null); services
+ .hasMoreElements();) {
+ assertEquals(services.next().toString(),
+ "service:osgi://gantenbein:123");
+ count++;
+ }
+ assertEquals(count, 1);
+
+ }
+
+ public void testAttributes() throws Exception {
+
+ System.out.println("listing the attributes for service:osgi");
+ int count = 0;
+ for (ServiceLocationEnumeration attributes = TestActivator.locator
+ .findAttributes(new ServiceType("service:osgi"), null, null); attributes
+ .hasMoreElements();) {
+ final String attribute = attributes.next().toString();
+ System.out.println("attribute " + attribute);
+ assertTrue("(attr=false)".equals(attribute)
+ || "(other=value)".equals(attribute));
+ count++;
+ }
+ assertEquals(count, 2);
+ }
+
+ public void testFilter() throws Exception {
+
+ System.out.println("locating service:osgi with filter (attr=false)");
+ int count = 0;
+ for (ServiceLocationEnumeration services = TestActivator.locator
+ .findServices(new ServiceType("service:osgi"), null,
+ "(attr=false)"); services.hasMoreElements();) {
+ assertEquals(services.next().toString(),
+ "service:osgi://gantenbein:123");
+ count++;
+ }
+ assertEquals(count, 1);
+ }
+
+ public void testFilter2() throws Exception {
+
+ System.out.println("locating service:osgi with filter (attr=*)");
+ int count = 0;
+ for (ServiceLocationEnumeration services = TestActivator.locator
+ .findServices(new ServiceType("service:osgi"), null, "(attr=*)"); services
+ .hasMoreElements();) {
+ assertEquals(services.next().toString(),
+ "service:osgi://gantenbein:123");
+ count++;
+ }
+ assertEquals(count, 1);
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/TestActivator.java b/protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/TestActivator.java
new file mode 100644
index 000000000..ce1450e8a
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/runtimeTests/src/main/java/ch/ethz/iks/slp/impl/TestActivator.java
@@ -0,0 +1,58 @@
+package ch.ethz.iks.slp.impl;
+
+import java.util.Enumeration;
+
+import junit.framework.TestFailure;
+import junit.framework.TestResult;
+import junit.textui.TestRunner;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+import ch.ethz.iks.slp.Advertiser;
+import ch.ethz.iks.slp.Locator;
+
+public class TestActivator implements BundleActivator {
+
+ static Advertiser advertiser;
+ static Locator locator;
+
+ public void start(BundleContext context) throws Exception {
+ try {
+ advertiser = (Advertiser) context.getService(context
+ .getServiceReference(Advertiser.class.getName()));
+ locator = (Locator) context.getService(context
+ .getServiceReference(Locator.class.getName()));
+ } catch (Exception e) {
+ System.exit(1);
+ }
+ TestResult result = TestRunner.run(new SelfDiscoveryTest());
+ if (result.wasSuccessful()) {
+ System.exit(0);
+ } else {
+ if (result.errorCount() > 0) {
+ System.err.println("Errors:");
+ for (Enumeration errors = result.errors(); errors
+ .hasMoreElements();) {
+ TestFailure error = (TestFailure) errors.nextElement();
+ System.err.println(error.trace());
+ }
+ }
+ if (result.failureCount() > 0) {
+ System.err.println("Failures:");
+ for (Enumeration failures = result.failures(); failures
+ .hasMoreElements();) {
+ TestFailure failure = (TestFailure) failures.nextElement();
+ System.err.println(failure.trace());
+ }
+ }
+ System.exit(1);
+ }
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ advertiser = null;
+ locator = null;
+ }
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Advertiser.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Advertiser.java
new file mode 100644
index 000000000..eed816367
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Advertiser.java
@@ -0,0 +1,161 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp;
+
+import java.net.InetAddress;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Advertiser implements the SA properties of SLP. Services can be registered
+ * and deregistered. The SLP framework handles DA discovery.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @since 0.1
+ */
+public interface Advertiser {
+
+ /**
+ * Returns the locale of this Advertiser instance.
+ *
+ * @return the current Locale.
+ */
+ Locale getLocale();
+
+ /**
+ * Get the locale of this instance.
+ *
+ * @param locale
+ * the Locale.
+ * @see Advertiser#getLocale()
+ */
+ void setLocale(final Locale locale);
+
+ /**
+ * Register a service with the SLP framework. The service will be registered
+ * with all known DAs that support the default scope and with the local SA
+ * registry for multicast discovery.
+ *
+ * @param url
+ * the <code>ServiceURL</code> of the service.
+ * @param attributes
+ * a <code>Dictionary</code> of attributes for the service. RFC
+ * 2614 proposes a <code>Vector</code> of attribute-value-pairs
+ * here but the <code>Dictionary</code> makes this
+ * implementation more close to <code>OSGi</code>.
+ * @throws ServiceLocationException
+ * in case that the registration failed for any reason.
+ */
+ void register(ServiceURL url, Dictionary attributes)
+ throws ServiceLocationException;
+
+ /**
+ * Register a service with the SLP framework. The service will be registered
+ * with all known DAs that support at least one of the given scopes and with
+ * the local SA registry for multicast discovery.
+ *
+ * @param url
+ * the ServiceURL of the service.
+ * @param scopes
+ * a <code>List</code> of scope names as <code>Strings</code>.
+ * @param attributes
+ * a <code>Dictionary</code> of attributes for the service. RFC
+ * 2614 proposes a <code>Vector</code> of attribute-value-pairs
+ * here but the <code>Dictionary</code> makes this
+ * implementation more close to <code>OSGi</code>
+ * @throws ServiceLocationException
+ * in case that the registration failed for any reason.
+ */
+ void register(ServiceURL url, List scopes, Dictionary attributes)
+ throws ServiceLocationException;
+
+ /**
+ * Unregister a service with the SLP framework. The service will be
+ * unregistered with all known DAs in the scopes that it was registered in.
+ *
+ * @param url
+ * the <code>ServiceURL</code> of the service.
+ * @throws ServiceLocationException
+ * in case that the deregistration failed for any reason.
+ */
+ void deregister(ServiceURL url) throws ServiceLocationException;
+
+ /**
+ * deregister a service in some scopes.
+ *
+ * @param url
+ * the ServiceURL of the service.
+ * @param scopes
+ * the scopes.
+ * @throws ServiceLocationException
+ * if the deregistration has failed for any reason.
+ * @see Advertiser#deregister(ServiceURL, List)
+ * @since 0.7.1
+ */
+ void deregister(final ServiceURL url, final List scopes)
+ throws ServiceLocationException;
+
+ /**
+ * <b>Not yet implemented.</b> Add attributes to an already registered
+ * service. Allows incremental registration.
+ *
+ * @param url
+ * the <code>ServiceURL</code> of the service.
+ * @param attributes
+ * the attributes to be added.
+ * @throws ServiceLocationException
+ * whenever called.
+ */
+ void addAttributes(ServiceURL url, Dictionary attributes)
+ throws ServiceLocationException;
+
+ /**
+ * <b>Not yet implemented.</b> Remove attributes to an already registered
+ * service. Allows incremental registration.
+ *
+ * @param url
+ * the <code>ServiceURL</code> of the service.
+ * @param attributeIds
+ * the attributes to be removed.
+ * @throws ServiceLocationException
+ * whenever called.
+ */
+ void deleteAttributes(ServiceURL url, Dictionary attributeIds)
+ throws ServiceLocationException;
+
+ /**
+ * Get the IP address of this machine that is configured as primary jSLP
+ * address. Can be used to register Services that are located on this host.
+ *
+ * @return the local InetAddress.
+ */
+ InetAddress getMyIP();
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Locator.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Locator.java
new file mode 100644
index 000000000..86183300d
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/Locator.java
@@ -0,0 +1,148 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp;
+
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Locator implements the UA properties of SLP. Services can be discovered by
+ * type or by URL, attributes of discovered services can be retrieved and
+ * service types can be listed.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @since 0.1
+ */
+public interface Locator {
+ /**
+ * Returns the locale of this Locator instance.
+ *
+ * @return the current Locale.
+ */
+ Locale getLocale();
+
+ /**
+ * Get the locale of this instance.
+ *
+ * @param locale
+ * the Locale.
+ * @see Advertiser#getLocale()
+ */
+ void setLocale(final Locale locale);
+
+ /**
+ * Find all services types that are currently
+ * registered in the network.
+ *
+ * @param namingAuthority
+ * the naming authority for the service type. If omitted,
+ * ALL Service Types are returned, regardless of Naming Authority.
+ * With the empty <code>String</code> (""), <code>IANA</code> will be assumed.
+ * @param scopes
+ * a <code>List</code> of scopes in that service types are to
+ * be discovered.
+ * @return a ServiceLocationEnumeration over the discovered ServiceTypes.
+ * @throws ServiceLocationException
+ * whenever called.
+ */
+ ServiceLocationEnumeration findServiceTypes(String namingAuthority,
+ List scopes) throws ServiceLocationException;
+
+ /**
+ * Find all services that match a certain service type.
+ *
+ * @param type
+ * the ServiceType.
+ * @param scopes
+ * A <code>List</code> of scope <code>Strings</code>, RFC
+ * 2614 uses <code>Vector</code> here but jSLP prefers the
+ * Collection Framework.
+ * @param searchFilter
+ * an RFC 1960 compliant <code>String</code> of a LDAP filter.
+ * RFC 2614 proposes the newer RFC 2254 style filters that adds
+ * support for extensible matches.
+ * @return a ServiceLocationEnumeration over the <code>ServiceURLs</code>
+ * of the found services.
+ * @throws ServiceLocationException
+ * in case of an exception in the underlying framework.
+ * @throws InvalidSyntaxException
+ */
+ ServiceLocationEnumeration findServices(ServiceType type, List scopes,
+ String searchFilter) throws ServiceLocationException, IllegalArgumentException;
+
+ /**
+ * Find all services that match a ServiceURL.
+ *
+ * @param url
+ * the ServiceURL.
+ * @param scopes
+ * A <code>List</code> of scopes <code>Strings</code>, RFC
+ * 2614 uses <code>Vector</code> here but jSLP prefers the
+ * Collection Framework.
+ * @param attributeIds
+ * A List of attribute-value-pairs like
+ *
+ * <pre>
+ * (key = value)
+ * </pre>
+ *
+ * that must match. If null, no attribute constraints are applied.
+ * @return a ServiceLocationEnumeration over the <code>ServiceURLs</code>
+ * of the found services.
+ * @throws ServiceLocationException
+ * in case of an exception in the underlying framework.
+ */
+ ServiceLocationEnumeration findAttributes(ServiceURL url, List scopes,
+ List attributeIds) throws ServiceLocationException;
+
+ /**
+ * Find all services that match a ServiceType.
+ *
+ * @param type
+ * the ServiceType.
+ * @param scopes
+ * A <code>List</code> of scope <code>Strings</code>, RFC
+ * 2614 uses <code>Vector</code> here but jSLP prefers the
+ * Collection Framework.
+ * @param attributeIds
+ * A List of attribute-value-pairs like
+ *
+ * <pre>
+ * (key = value)
+ * </pre>
+ *
+ * that must match. If null, no attribute constraints are applied.
+ * @return a ServiceLocationEnumeration over the ServiceURLs of the found
+ * services.
+ * @throws ServiceLocationException
+ * in case of an exception in the underlying framework.
+ */
+ ServiceLocationEnumeration findAttributes(ServiceType type, List scopes,
+ List attributeIds) throws ServiceLocationException;
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationEnumeration.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationEnumeration.java
new file mode 100644
index 000000000..67eb8f1ab
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationEnumeration.java
@@ -0,0 +1,49 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp;
+
+import java.util.Enumeration;
+
+/**
+ * An enumeration over results of request messages as defined in RFC 2614.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @since 0.1
+ */
+public interface ServiceLocationEnumeration extends Enumeration {
+
+ /**
+ * get the next result of a request.
+ *
+ * @return the next <code>Object</code>
+ * @throws ServiceLocationException
+ * if there is no more result.
+ */
+ Object next() throws ServiceLocationException;
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationException.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationException.java
new file mode 100644
index 000000000..9f4cf5a84
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceLocationException.java
@@ -0,0 +1,167 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp;
+
+import java.io.Serializable;
+
+/**
+ * This exception is thrown whenever a part of the SLP framework causes an
+ * exception. The error code is a hint why the exception occured.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @since 0.1
+ */
+public class ServiceLocationException extends Exception
+ implements Serializable {
+
+ /**
+ * @serial for serialization.
+ */
+ private static final long serialVersionUID = 5718658752610460537L;
+
+ /**
+ * There is data for the service type in the scope in the AttrRqst or
+ * SrvRqst, but not in the requested language.
+ */
+ public static final short LANGUAGE_NOT_SUPPORTED = 1;
+
+ /**
+ * The message fails to obey SLP syntax.
+ */
+ public static final short PARSE_ERROR = 2;
+
+ /**
+ * The SrvReg has problems -- e.g., a zero lifetime or an omitted Language
+ * Tag.
+ */
+ public static final short INVALID_REGISTRATION = 3;
+
+ /**
+ * The SLP message did not include a scope in its scope-list supported by
+ * the SA or DA.
+ */
+ public static final short SCOPE_NOT_SUPPORTED = 4;
+
+ /**
+ * The DA or SA receives a request for an unsupported SLP SPI.
+ */
+ public static final short AUTHENTICATION_UNKNOWN = 5;
+
+ /**
+ * The DA expected URL and ATTR authentication in the SrvReg and did not
+ * receive it.
+ */
+ public static final short AUTHENTICATION_ABSENT = 6;
+
+ /**
+ * Unsupported version number in message header. INTERNAL_ERROR = 10: The DA
+ * (or SA) is too sick to respond.
+ */
+ public static final short AUTHENTICATION_FAILED = 7;
+
+ /**
+ * The DA received a SrvReg without FRESH set, for an unregistered service
+ * or with inconsistent Service Types.
+ */
+ public static final short INVALID_UPDATE = 13;
+
+ /**
+ * The DA rejected the update because it was within the minimal update
+ * intervall.
+ */
+ public static final short REFRESH_REJECTED = 15;
+
+ /**
+ * The feature or extension is not implemented.
+ */
+ public static final short NOT_IMPLEMENTED = 16;
+
+ /**
+ * The initialization of the framework failed.
+ */
+ public static final short NETWORK_INIT_FAILED = 17;
+
+ /**
+ * The network timed out while the framework tried to send a message.
+ */
+ public static final short NETWORK_TIMED_OUT = 18;
+
+ /**
+ * The network encountered an error.
+ */
+ public static final short NETWORK_ERROR = 19;
+
+ /**
+ * The framework encountered an internal system error.
+ */
+ public static final short INTERNAL_SYSTEM_ERROR = 20;
+
+ /**
+ * The type was not well formed.
+ */
+ public static final short TYPE_ERROR = 21;
+
+ /**
+ * The framework encountered a buffer overflow.
+ */
+ public static final short BUFFER_OVERFLOW = 22;
+
+ /**
+ * the error code of this exception instance.
+ */
+ private short errorCode;
+
+ /**
+ * hidden constructor.
+ */
+ private ServiceLocationException() {
+ }
+
+ /**
+ * Create a new ServiceLocation instance.
+ *
+ * @param errcode
+ * the error code, one of the statically defined.
+ * @param message
+ * the message of the exception.
+ */
+ public ServiceLocationException(final short errcode, final String message) {
+ super(message);
+ errorCode = errcode;
+ }
+
+ /**
+ * Get the error code of the exception.
+ *
+ * @return the error code.
+ */
+ public final short getErrorCode() {
+ return errorCode;
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceType.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceType.java
new file mode 100644
index 000000000..9ade2f36c
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceType.java
@@ -0,0 +1,252 @@
+/* modified version by Jan S. Rellermeyer, ETH Zurich
+ * Copyright 2005-2007 IKS, ETH Zurich. All rights reserved.
+ *
+ * based on the Java SLP implementation by Solers Corporation
+ * Copyright 2003 Solers Corporation. All rights reserved.
+ *
+ * Modification and use of this SLP API software and associated documentation
+ * ("Software") is permitted provided that the conditions specified in the
+ * LICENSE.txt file included within this distribution are met.
+ *
+ * Author of the original class: Patrick Callis
+ */
+package ch.ethz.iks.slp;
+
+import java.io.Serializable;
+
+/**
+ * Implementation of the SLP ServiceType class defined in RFC 2614.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @author Patrick Callis, Solers Corp.
+ * @since 0.1
+ */
+public final class ServiceType implements Serializable {
+
+ /**
+ * the serial UID.
+ */
+ private static final long serialVersionUID = 1652247274399819356L;
+
+ /**
+ * the type.
+ */
+ private String type = new String();
+
+ /**
+ * is it a service ?
+ */
+ private boolean isService = false;
+
+ /**
+ * is it abstract ?
+ */
+ private boolean isAbstract = false;
+
+ /**
+ * the concrete type.
+ */
+ private String concreteType = new String();
+
+ /**
+ * the principle type.
+ */
+ private String principleType = new String();
+
+ /**
+ * the abstract type.
+ */
+ private String abstractType = new String();
+
+ /**
+ * the naming authority.
+ */
+ private String namingAuthority = new String();
+
+ /**
+ * creates a new ServiceType instance.
+ *
+ * @param serviceType
+ * the string representation of a ServiceType, e.g.
+ *
+ * <pre>
+ * service:osgi:remote
+ * </pre>
+ */
+ public ServiceType(final String serviceType) {
+ type = serviceType;
+ if (type.startsWith("service:")) {
+ isService = true;
+
+ int principleStart = 8;
+ int principleEnd = type.indexOf(":", principleStart);
+
+ if (principleEnd != -1) {
+ isAbstract = true;
+ principleType = type.substring(principleStart, principleEnd);
+ abstractType = type.substring(0, principleEnd);
+ concreteType = type.substring(principleEnd + 1);
+ } else {
+ isAbstract = false;
+ principleType = type.substring(principleStart);
+ abstractType = "";
+ concreteType = "";
+ }
+
+ int namingStart = type.indexOf(".") + 1;
+ if (namingStart != 0) {
+ int namingEnd = type.indexOf(":", namingStart);
+ String na = "";
+ if (namingEnd == -1) {
+ na = type.substring(namingStart);
+ } else {
+ na = type.substring(namingStart, namingEnd);
+ }
+ // 1954772: isNADefault returns false for "IANA"
+ if("IANA".equalsIgnoreCase(na)) {
+ namingAuthority = "";
+ // remove "iana" from type so toString() is consistent
+ type = type.substring(0, namingStart - 1) + type.substring(namingStart + 4, type.length());
+ } else {
+ namingAuthority = na;
+ }
+ } else {
+ namingAuthority = "";
+ }
+ }
+ }
+
+ /**
+ * is the ServiceType instance a ServiceURL ?
+ *
+ * @return true if this is the case.
+ */
+ public boolean isServiceURL() {
+ return isService;
+ }
+
+ /**
+ * is the ServiceType instance an abstract type ?
+ *
+ * @return true if thie is the case.
+ */
+ public boolean isAbstractType() {
+ return isAbstract;
+ }
+
+ /**
+ * is the naming authority default (IANA) ?
+ *
+ * @return true if this is the case.
+ */
+ public boolean isNADefault() {
+ return "".equals(namingAuthority);
+ }
+
+ /**
+ * get the concrete type part of this ServiceType instance.
+ *
+ * @return a String representing the concrete type.
+ */
+ public String getConcreteTypeName() {
+ return concreteType;
+ }
+
+ /**
+ * get the principle type part of this ServiceType instance.
+ *
+ * @return a String representing the principle part.
+ */
+ public String getPrincipleTypeName() {
+ return principleType;
+ }
+
+ /**
+ * get the name of the abstract type of this ServiceType instance.
+ *
+ * @return a String representing the abstract type.
+ */
+ public String getAbstractTypeName() {
+ return abstractType;
+ }
+
+ /**
+ * get the naming authority.
+ *
+ * @return the naming authority.
+ */
+ public String getNamingAuthority() {
+ return namingAuthority;
+ }
+
+ /**
+ * check if two ServiceTypes are equal.
+ *
+ * @param obj
+ * another ServiceType.
+ * @return true if they equal.
+ */
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof ServiceType)) {
+ return false;
+ }
+ ServiceType t = (ServiceType) obj;
+ return (isService == t.isService && isAbstract == t.isAbstract
+ && concreteType.equals(t.concreteType)
+ && principleType.equals(t.principleType)
+ && abstractType.equals(t.abstractType) && namingAuthority
+ .equals(t.namingAuthority));
+ }
+
+ /**
+ * check if a ServiceType matches a ServiceURL or another ServiceType.
+ *
+ * @param obj
+ * the object to be compared to.
+ * @return true if this type matches the other object.
+ */
+ public boolean matches(final Object obj) {
+ if (!(obj instanceof ServiceType)) {
+ return false;
+ }
+ ServiceType t = (ServiceType) obj;
+ if (!isAbstract) {
+ return equals(t);
+ } else {
+ return equals(t) || t.toString().equals(getAbstractTypeName());
+ }
+ }
+
+ /**
+ * get a String representation of this ServiceType instance.
+ *
+ * @return the String representation.
+ */
+ public String toString() {
+ return type;
+ }
+
+ /**
+ * get the hashCode of this ServiceType instance.
+ *
+ * @return the int value of the hashCode.
+ */
+ public int hashCode() {
+ int code = 0;
+
+ if (concreteType != null) {
+ code ^= (concreteType.hashCode());
+ }
+ if (principleType != null) {
+ code ^= (principleType.hashCode() << 8);
+ }
+ if (abstractType != null) {
+ code ^= (abstractType.hashCode() << 16);
+ }
+ if (namingAuthority != null) {
+ code ^= (namingAuthority.hashCode() << 24);
+ }
+ return code;
+ }
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceURL.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceURL.java
new file mode 100644
index 000000000..7d8193eda
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/ServiceURL.java
@@ -0,0 +1,373 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * Implementation of the SLP ServiceURL class defined in RFC 2614.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+public final class ServiceURL extends ch.ethz.iks.slp.impl.AuthenticatedURL
+ implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 9181946114021582389L;
+
+ /**
+ *
+ */
+ public static final int NO_PORT = 0;
+
+ /**
+ *
+ */
+ public static final int LIFETIME_NONE = 0;
+
+ /**
+ *
+ */
+ public static final int LIFETIME_DEFAULT = 10800;
+
+ /**
+ *
+ */
+ public static final int LIFETIME_MAXIMUM = 65535;
+
+ /**
+ *
+ */
+ public static final int LIFETIME_PERMANENT = -1;
+
+ /**
+ *
+ */
+ private String url = null;;
+
+ /**
+ *
+ */
+ private int lifetime = 0;
+
+ /**
+ *
+ */
+ private ServiceType type = null;
+
+ /**
+ *
+ */
+ private String host = null;
+
+ /**
+ *
+ */
+ private String protocol = null;
+
+ /**
+ *
+ */
+ private int port = 0;
+
+ /**
+ *
+ */
+ private String path = null;
+
+ /**
+ *
+ *
+ */
+ private ServiceURL() {
+ }
+
+ /**
+ * create a new ServiceURL instance from a String.
+ *
+ * @param serviceURL
+ * the string representation of a ServiceURL like
+ *
+ * <pre>
+ * service::&quot;serviceType&quot;://&quot;addrspec&quot;
+ * </pre>
+ *
+ * where servicetype should be of the form abstractType:concreteType and
+ * addrspec is the hostname or dotted decimal notation of the host's address
+ * followed by an optional :portNumber. Example:
+ *
+ * <pre>
+ * service:osgi:remote://my.host.ch:9200
+ * </pre>
+ *
+ * @param lifeTime
+ * the lifetime of the ServiceURL in seconds.
+ * @throws ServiceLocationException
+ * if the String is not parsable.
+ */
+ public ServiceURL(final String serviceURL, final int lifeTime)
+ throws ServiceLocationException {
+ url = serviceURL;
+ lifetime = lifeTime;
+
+ try {
+ parse();
+ } catch (Exception ex) {
+ throw new ServiceLocationException(
+ ServiceLocationException.PARSE_ERROR,
+ "service url is malformed: [" + url + "]. ");
+ }
+ }
+
+ /**
+ * parse the url string.
+ *
+ */
+ private void parse() {
+ int pos1 = url.indexOf("://");
+ type = new ServiceType(url.substring(0, pos1++));
+
+ int pos2 = url.indexOf("://", pos1 + 1);
+ if (pos2 > -1) {
+ protocol = url.substring(pos1 + 2, pos2);
+ pos1 = pos2 + 1;
+ }
+
+ int hostEnd = url.indexOf(":", pos1 + 2);
+
+ int pathStart;
+ if (hostEnd == -1) {
+ port = NO_PORT;
+ pathStart = hostEnd = url.indexOf("/", pos1 + 2);
+ } else {
+ pathStart = url.indexOf("/", hostEnd + 1);
+ if (pathStart == -1) {
+ port = Integer.parseInt(url.substring(hostEnd + 1));
+ } else {
+ port = Integer.parseInt(url.substring(hostEnd + 1, pathStart));
+ }
+ }
+
+ if (hostEnd == -1) {
+ host = url.substring(pos1 + 2);
+ } else {
+ host = url.substring(pos1 + 2, hostEnd);
+ }
+
+ if (pathStart == -1) {
+ path = "";
+ } else {
+ path = url.substring(pathStart);
+ }
+ }
+
+ /**
+ * Check if two instances are equal.
+ *
+ * @inheritDoc java.lang.Object.equals(Object)
+ * @param obj
+ * the object to compare to.
+ * @return true if the instances are equal.
+ */
+ public boolean equals(final Object obj) {
+ if (obj instanceof ServiceURL) {
+ ServiceURL u = (ServiceURL) obj;
+ return (type.equals(u.type)
+ && host.equals(u.host)
+ && port == u.port
+ && ((protocol == null && u.protocol == null) || protocol
+ .equals(u.protocol)) && path.equals(u.path));
+ }
+ return false;
+ }
+
+ /**
+ * Check if a ServiceURL matches another ServiceURL or a ServiceType. In the
+ * first case, the method performs an equality check with equals(Object
+ * obj), for ServiceTypes, the ServiceType part of the ServiceURL is checked
+ * against the given ServiceType.
+ *
+ * @param obj
+ * a ServiceURL or ServiceType. All other objects will return
+ * false.
+ * @return true if the match succeeds.
+ */
+ public boolean matches(final Object obj) {
+ if (obj instanceof ServiceURL) {
+ return equals(obj);
+ } else if (obj instanceof ServiceType) {
+ return type.matches(obj);
+ }
+ return false;
+ }
+
+ /**
+ * get a String representation of the ServiceURL.
+ *
+ * @return the String representation.
+ */
+ public String toString() {
+ return type.toString() + "://"
+ + (protocol != null ? protocol + "://" : "") + host
+ + (port != NO_PORT ? (":" + port) : "") + path;
+ }
+
+ /**
+ * get the hashCode of the ServiceURL instance.
+ *
+ * @return the hashCode.
+ */
+ public int hashCode() {
+ return url.hashCode();
+ }
+
+ /**
+ * get the service type.
+ *
+ * @return the service type.
+ */
+ public ServiceType getServiceType() {
+ return type;
+ }
+
+ /**
+ * get the transport method.
+ *
+ * @return the transport method. IP returns empty string.
+ * @deprecated
+ */
+ public String getTransport() {
+ return "";
+ }
+
+ /**
+ * get the protocol.
+ *
+ * @return the protocol, if specified. Otherwise, returns null.
+ */
+ public String getProtocol() {
+ return protocol;
+ }
+
+ /**
+ * get the host.
+ *
+ * @return the host.
+ */
+ public String getHost() {
+ return host;
+ }
+
+ /**
+ * get the port.
+ *
+ * @return the port.
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * get the URL path.
+ *
+ * @return the URL path.
+ */
+ public String getURLPath() {
+ return path;
+ }
+
+ /**
+ * get the lifetime.
+ *
+ * @return the lifetime.
+ */
+ public int getLifetime() {
+ return lifetime;
+ }
+
+ /**
+ * get the byte representation of the ServiceURL instance.
+ *
+ * @throws IOException
+ * @throws IOException
+ * if an internal processing error occurs.
+ */
+ public void writeTo(DataOutputStream out) throws IOException {
+ out.write(0);
+ out.writeShort((short) lifetime);
+ out.writeUTF(toString());
+ writeAuthBlock(out);
+ }
+
+ public int getLength() {
+ return 1 + 2 + 2 + toString().length() + getAuthBlockLength();
+ }
+
+ /**
+ * Reads a byte stream from a DataInput and constructs a ServiceURL from it,
+ * following the RFC 2608 schema:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved | Lifetime | URL Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |URL len, contd.| URL (variable length) \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |# of URL auths | Auth. blocks (if any) \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @param input
+ * the DataInput streaming the ServiceURL bytes.
+ * @return a ServiceURL instance.
+ * @throws ServiceLocationException
+ * in case of IO exceptions.
+ * @throws IOException
+ */
+ public static ServiceURL fromBytes(final DataInputStream input)
+ throws ServiceLocationException, IOException {
+ ServiceURL surl = new ServiceURL();
+ input.readByte();
+ surl.lifetime = input.readShort();
+ surl.url = input.readUTF();
+ surl.authBlocks = parseAuthBlock(input);
+ surl.parse();
+ return surl;
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Activator.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Activator.java
new file mode 100644
index 000000000..eca7aaf63
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Activator.java
@@ -0,0 +1,81 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package ch.ethz.iks.slp.impl;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Bundle Activator
+ *
+ * @author Jan S. Rellermeyer, ETH Zurich
+ */
+public class Activator implements BundleActivator {
+
+ /**
+ *
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(final BundleContext context) throws Exception {
+
+ // create the platform abstraction layer but do not initialize!!!
+ SLPCore.platform = new OSGiPlatformAbstraction(context);
+
+ // register the service factories so each consumer gets its own Locator/Activator instance
+ context.registerService("ch.ethz.iks.slp.Advertiser", new ServiceFactory() {
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ SLPCore.init();
+ SLPCore.initMulticastSocket();
+ return new AdvertiserImpl();
+ }
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ }
+ }, null);
+ context.registerService("ch.ethz.iks.slp.Locator", new ServiceFactory() {
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ SLPCore.init();
+ return new LocatorImpl();
+ }
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ }
+ }, null);
+ }
+
+ /**
+ *
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(final BundleContext context) throws Exception {
+
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AdvertiserImpl.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AdvertiserImpl.java
new file mode 100644
index 000000000..d3e1d874f
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AdvertiserImpl.java
@@ -0,0 +1,237 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Locale;
+import ch.ethz.iks.slp.Advertiser;
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * Implementation of the Advertiser that provides SLP SA functionality. If the
+ * configuration does not have to support SA functionalities, this class does
+ * not have to be included in the distribution.
+ *
+ * @see ch.ethz.iks.slp.Advertiser
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @since 0.1
+ */
+public final class AdvertiserImpl implements Advertiser {
+
+ /**
+ * the locale of this instance. Will be used for all messages created by
+ * this Advertiser instance.
+ */
+ private Locale locale;
+
+ /**
+ * Constructor for AdvertiserImpl.
+ */
+ public AdvertiserImpl() {
+ locale = SLPCore.DEFAULT_LOCALE;
+ }
+
+ /**
+ * Constructor for AdvertiserImpl.
+ *
+ * @param theLocale
+ * Locale.
+ */
+ public AdvertiserImpl(final Locale locale) {
+ this.locale = locale;
+ }
+
+ /**
+ * Get the locale of this instance.
+ *
+ * @return Locale.
+ * @see Advertiser#getLocale()
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Set the locale of this instance.
+ *
+ * @param locale
+ * the Locale.
+ * @see Advertiser#setLocale()
+ */
+ public void setLocale(final Locale locale) {
+ this.locale = locale;
+ }
+
+ /**
+ * register a new service with the framework.
+ *
+ * @param url
+ * the ServiceURL of the service.
+ * @param attributes
+ * a Dictionary of attributes.
+ * @throws ServiceLocationException
+ * if the registration has failed for any reason.
+ * @see Advertiser#register(ServiceURL, Dictionary)
+ */
+ public void register(final ServiceURL url, final Dictionary attributes)
+ throws ServiceLocationException {
+ register(url, null, attributes);
+ }
+
+ /**
+ * register a new service with the framework using scopes.
+ *
+ * @param url
+ * the ServiceURL of the service.
+ * @param scopes
+ * a List of scopes.
+ * @param attributes
+ * a Dictionary of attributes.
+ * @throws ServiceLocationException
+ * if the registration has failed for any reason.
+ * @see Advertiser#register(ServiceURL, List, Dictionary)
+ */
+ public void register(final ServiceURL url, final List scopes,
+ final Dictionary attributes) throws ServiceLocationException {
+ ServiceRegistration reg = new ServiceRegistration(url, url
+ .getServiceType(), scopes, SLPUtils.dictToAttrList(attributes),
+ locale);
+ try {
+ reg.address = InetAddress.getLocalHost();
+ } catch (UnknownHostException e) {
+ reg.address = SLPCore.getMyIP();
+ }
+ reg.port = SLPCore.SLP_PORT;
+ ServiceAcknowledgement ack = (ServiceAcknowledgement) SLPCore
+ .sendMessage(reg, true);
+ if (ack.errorCode != 0) {
+ throw new ServiceLocationException((short) ack.errorCode,
+ "Registration failed");
+ }
+ }
+
+ /**
+ * deregister a service.
+ *
+ * @param url
+ * the ServiceURL of the service.
+ * @throws ServiceLocationException
+ * if the deregistration has failed for any reason.
+ * @see Advertiser#deregister(ServiceURL)
+ */
+ public void deregister(final ServiceURL url)
+ throws ServiceLocationException {
+ deregister(url, null);
+ }
+
+ /**
+ * deregister a service in some scopes.
+ *
+ * @param url
+ * the ServiceURL of the service.
+ * @param scopes
+ * the scopes.
+ * @throws ServiceLocationException
+ * if the deregistration has failed for any reason.
+ * @see Advertiser#deregister(ServiceURL, List)
+ * @since 0.7.1
+ */
+
+ public void deregister(final ServiceURL url, final List scopes)
+ throws ServiceLocationException {
+ ServiceDeregistration dereg = new ServiceDeregistration(url, scopes,
+ null, locale);
+ try {
+ dereg.address = InetAddress.getLocalHost();
+ } catch (UnknownHostException e) {
+ dereg.address = SLPCore.getMyIP();
+ }
+ dereg.port = SLPCore.SLP_PORT;
+ ServiceAcknowledgement ack = (ServiceAcknowledgement) SLPCore
+ .sendMessage(dereg, true);
+ if (ack.errorCode != 0) {
+ throw new ServiceLocationException((short) ack.errorCode,
+ "Deregistration failed");
+ }
+ }
+
+ /**
+ * currently not supported.
+ *
+ * @see Advertiser#addAttributes(ServiceURL, Dictionary)
+ * @param url
+ * the serviceURL
+ * @param attributes
+ * the attributes to add.
+ * @throws ServiceLocationException
+ * always.
+ */
+ public void addAttributes(final ServiceURL url, final Dictionary attributes)
+ throws ServiceLocationException {
+ throw new ServiceLocationException(
+ ServiceLocationException.NOT_IMPLEMENTED,
+ "incremental registration not supported");
+ }
+
+ /**
+ * currently not supported.
+ *
+ * @see Advertiser#deleteAttributes(ServiceURL, Dictionary)
+ * @param url
+ * the serviceURL.
+ * @param attributes
+ * the attributes to delete.
+ * @throws ServiceLocationException
+ * always.
+ */
+ public void deleteAttributes(final ServiceURL url,
+ final Dictionary attributes) throws ServiceLocationException {
+ throw new ServiceLocationException(
+ ServiceLocationException.NOT_IMPLEMENTED,
+ "incremental registration not supported");
+ }
+
+ /**
+ * Get the IP address of this machine that is configured as primary jSLP
+ * address. Can be used to register Services that are located on this host.
+ *
+ * @return the local InetAddress.
+ */
+ public InetAddress getMyIP() {
+ try {
+ return SLPCore.getMyIP();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeReply.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeReply.java
new file mode 100644
index 000000000..8e96b5e2e
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeReply.java
@@ -0,0 +1,239 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * a AttributeReply Message is sent as reaction to a AttributeRequest message.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+class AttributeReply extends ReplyMessage {
+ /**
+ * a List of attributes that have been retrieved.
+ */
+ List attributes;
+
+ /**
+ * an array of AuthenticationBlocks. Used to verify that the reply has not
+ * been modified during transport.
+ */
+ AuthenticationBlock[] authBlocks;
+
+ /**
+ * create a new AttributeReply from a list of attributes.
+ *
+ * @param attList
+ * a list of attributes in
+ *
+ * <verbatim> (key=value) </verbatim>
+ *
+ * format.
+ */
+ AttributeReply(final AttributeRequest req, final List attList) {
+ funcID = ATTRRPLY;
+ errorCode = 0;
+ attributes = attList;
+ locale = req.locale;
+ xid = req.xid;
+ address = req.address;
+ port = req.port;
+ authBlocks = new AuthenticationBlock[0];
+ }
+
+ /**
+ * create a new AttributeReply from a DataInput streaming the bytes of an
+ * AttributeReply message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ */
+ AttributeReply(final DataInputStream input) throws IOException,
+ ServiceLocationException {
+ errorCode = input.readShort();
+ attributes = stringToList(input.readUTF(), ",");
+ authBlocks = AuthenticationBlock.parse(input);
+
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ if (!verify()) {
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED,
+ "Authentication failed for " + toString());
+ }
+ }
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = AttrRply = 7) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Error Code | length of &lt;attr-list&gt; |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | &lt;attr-list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |# of AttrAuths | Attribute Authentication Block (if present) \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ * @throws IOException
+ */
+ void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeShort(errorCode);
+ out.writeUTF(listToString(attributes, ","));
+ out.write(authBlocks.length);
+ for (int i = 0; i < authBlocks.length; i++) {
+ authBlocks[i].write(out);
+ }
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ int len = getHeaderSize() + 4 + listToString(attributes, ",").length() + 1;
+ for (int i=0; i<authBlocks.length; i++) {
+ len += authBlocks[i].getLength();
+ }
+ return len;
+ }
+
+ /**
+ * get the result.
+ *
+ * @see ch.ethz.iks.slp.impl.ReplyMessage#getResult()
+ * @return the <code>List</code> of results.
+ */
+ List getResult() {
+ return attributes;
+ }
+
+ /**
+ * get a string representation of the AttributeReply message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", errorCode " + errorCode);
+ buffer.append(", attrCount " + attributes.size());
+ buffer.append(", attributes " + attributes);
+ return buffer.toString();
+ }
+
+ /**
+ * sign this AttributeReply.
+ *
+ * @param spiStr
+ * a String of SPIs.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ void sign(final String spiStr) throws ServiceLocationException {
+ List spiList = stringToList(spiStr, ",");
+ authBlocks = new AuthenticationBlock[spiList.size()];
+ for (int k = 0; k < spiList.size(); k++) {
+ int timestamp = SLPUtils.getTimestamp();
+
+ String spi = (String) spiList.get(k);
+ byte[] data = getAuthData(spi, timestamp);
+ authBlocks[k] = new AuthenticationBlock(
+ AuthenticationBlock.BSD_DSA, spi, timestamp, data, null);
+ }
+ }
+
+ /**
+ * verify this AttributeReply.
+ *
+ * @return true if verification suceeds.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ boolean verify() throws ServiceLocationException {
+ for (int i = 0; i < authBlocks.length; i++) {
+ if (authBlocks[i].verify(getAuthData(authBlocks[i].getSPI(),
+ authBlocks[i].getTimestamp()))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * get the authentication data.
+ *
+ * @param spiStr
+ * the SPI.
+ * @param timestamp
+ * the timestamp.
+ * @return the auth data.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ private byte[] getAuthData(final String spiStr, final int timestamp)
+ throws ServiceLocationException {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ dos.writeUTF(spiStr);
+ dos.writeUTF(listToString(attributes, ","));
+ dos.writeInt(timestamp);
+ return bos.toByteArray();
+ } catch (IOException ioe) {
+ throw new ServiceLocationException(
+ ServiceLocationException.INTERNAL_SYSTEM_ERROR, ioe
+ .getMessage());
+ }
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeRequest.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeRequest.java
new file mode 100644
index 000000000..22be8f9dd
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AttributeRequest.java
@@ -0,0 +1,207 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceType;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * a AttributeRequest Message is sent to discover the attributes of a service.
+ *
+ * @author Jan S. Rellermeyer
+ * @since 0.1
+ */
+class AttributeRequest extends RequestMessage {
+ /**
+ * the url of the service.
+ */
+ String url;
+
+ /**
+ * a list of tags that are requested if they exist.
+ */
+ List tagList;
+
+ /**
+ * the spi string.
+ */
+ String spi;
+
+ /**
+ * create an AttributeRequest message for a ServiceURL.
+ *
+ * @param serviceURL
+ * the ServiceURL
+ * @param scopes
+ * a list of scopes that are included.
+ * @param tags
+ * a list of tags that are requested. If omitted, all attribute
+ * values will be returned.
+ * @param theLocale
+ * the Locale of the message.
+ */
+ AttributeRequest(final ServiceURL serviceURL, final List scopes,
+ final List tags, final Locale theLocale) {
+ funcID = ATTRRQST;
+ url = serviceURL.toString();
+ scopeList = scopes;
+ if (scopeList == null) {
+ scopeList = new ArrayList();
+ scopeList.add("default");
+ }
+ tagList = tags;
+ if (tagList == null) {
+ tagList = new ArrayList();
+ }
+ locale = theLocale == null ? SLPCore.DEFAULT_LOCALE : theLocale;
+ spi = SLPCore.CONFIG.getSecurityEnabled() ? SLPCore.CONFIG.getSPI()
+ : "";
+ }
+
+ /**
+ * create an AttributeRequest message for a ServiceType.
+ *
+ * @param type
+ * the ServiceType.
+ * @param scopes
+ * a list of scopes that are included.
+ * @param tags
+ * a list of tags that are requested. If omitted, all attribute
+ * values will be returned.
+ * @param theLocale
+ * the Locale of the message.
+ */
+ AttributeRequest(final ServiceType type, final List scopes,
+ final List tags, final Locale theLocale) {
+ funcID = ATTRRQST;
+ url = type.toString();
+ scopeList = scopes;
+ if (scopeList == null) {
+ scopeList = new ArrayList();
+ scopeList.add("default");
+ }
+ tagList = tags;
+ if (tagList == null) {
+ tagList = new ArrayList();
+ }
+ locale = theLocale == null ? SLPCore.DEFAULT_LOCALE : theLocale;
+ spi = SLPCore.CONFIG.getSecurityEnabled() ? SLPCore.CONFIG.getSPI()
+ : "";
+ }
+
+ /**
+ * create a new AttributeRequest from a DataInput streaming the bytes of an
+ * AttributeReply message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * if IO Exceptions occure.
+ */
+ AttributeRequest(final DataInputStream input) throws IOException {
+ prevRespList = stringToList(input.readUTF(), ",");
+ url = input.readUTF();
+ scopeList = stringToList(input.readUTF(), ",");
+ tagList = stringToList(input.readUTF(), ",");
+ spi = input.readUTF();
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = AttrRqst = 6) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of PRList | &lt;PRList&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of URL | URL \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;scope-list&gt; | &lt;scope-list&gt; string \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;tag-list&gt; string | &lt;tag-list&gt; string \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;SLP SPI&gt; string | &lt;SLP SPI&gt; string \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeUTF(listToString(prevRespList, ","));
+ out.writeUTF(url);
+ out.writeUTF(listToString(scopeList, ","));
+ out.writeUTF(listToString(tagList, ","));
+ out.writeUTF(spi);
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ return getHeaderSize() + 2 + listToString(prevRespList, ",").length()
+ + 2 + url.length() + 2 + listToString(scopeList, ",").length()
+ + 2 + listToString(tagList, ",").length() + 2 + spi.length();
+ }
+
+ /**
+ * get a string representation of the AttributeReply message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", prevRespList: " + prevRespList);
+ buffer.append(", URL: " + url);
+ buffer.append(", scopeList: " + scopeList);
+ buffer.append(", tag-list: " + tagList);
+ buffer.append(", slpSpi: " + spi);
+ return buffer.toString();
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticatedURL.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticatedURL.java
new file mode 100644
index 000000000..5ae781a13
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticatedURL.java
@@ -0,0 +1,174 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * an authenticated URL block within an SLPMessage.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.4
+ */
+public abstract class AuthenticatedURL {
+
+ /**
+ * the lifetime of the authenticated URL.
+ */
+ int lifetime;
+
+ /**
+ * the auth blocks.
+ */
+ protected AuthenticationBlock[] authBlocks;
+
+ /**
+ * create a new authenticated URL.
+ */
+ public AuthenticatedURL() {
+ authBlocks = new AuthenticationBlock[0];
+ }
+
+ /**
+ * sign the ServiceURL.
+ *
+ * @param spiList
+ * the List of SPIs
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ protected final void sign(final List spiList)
+ throws ServiceLocationException {
+ authBlocks = new AuthenticationBlock[spiList.size()];
+ for (int k = 0; k < spiList.size(); k++) {
+ int timestamp = SLPUtils.getTimestamp();
+ timestamp += lifetime;
+
+ String spi = (String) spiList.get(k);
+ byte[] data = getAuthData(spi, timestamp);
+ authBlocks[k] = new AuthenticationBlock(
+ AuthenticationBlock.BSD_DSA, spi, timestamp, data, null);
+ }
+ }
+
+ /**
+ * verifies the authentication blocks of the ServiceURL.
+ *
+ * @return true if the verification succeeds.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ protected final boolean verify() throws ServiceLocationException {
+ for (int i = 0; i < authBlocks.length; i++) {
+ byte[] data = getAuthData(authBlocks[i].getSPI(), authBlocks[i]
+ .getTimestamp());
+ if (authBlocks[i].verify(data)) {
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * get the byte representation of the authentication data.
+ *
+ * @param spi
+ * the SPI string as defined in RFC 2608
+ * @param timestamp
+ * a timestamp as defined in RFC 2608
+ * @return a byte array.
+ * @throws ServiceLocationException
+ * in case of internal errors.
+ */
+ private byte[] getAuthData(final String spi, final int timestamp)
+ throws ServiceLocationException {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+
+ byte[] temp = spi.getBytes();
+ dos.writeShort(temp.length);
+ dos.write(temp);
+ temp = toString().getBytes();
+ dos.writeShort(temp.length);
+ dos.write(temp);
+ dos.writeInt(timestamp);
+ return bos.toByteArray();
+ } catch (IOException ioe) {
+ throw new ServiceLocationException(
+ ServiceLocationException.INTERNAL_SYSTEM_ERROR, ioe
+ .getMessage());
+ }
+ }
+
+ /**
+ * get the authentication block bytes.
+ *
+ * @return the bytes of the authentication block.
+ * @throws IOException
+ * in case of IO errors.
+ */
+ protected void writeAuthBlock(final DataOutputStream out)
+ throws IOException {
+ out.write(authBlocks.length);
+ for (int i = 0; i < authBlocks.length; i++) {
+ authBlocks[i].write(out);
+ }
+ }
+
+ protected final int getAuthBlockLength() {
+ int len = 1;
+ for (int i = 0; i < authBlocks.length; i++) {
+ len += authBlocks[i].getLength();
+ }
+ return len;
+ }
+
+ /**
+ * parse the auth blocks.
+ *
+ * @param input
+ * the data input.
+ * @return the auth blocks.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ * @throws IOException
+ */
+ protected static final AuthenticationBlock[] parseAuthBlock(
+ final DataInputStream input) throws ServiceLocationException,
+ IOException {
+ return AuthenticationBlock.parse(input);
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticationBlock.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticationBlock.java
new file mode 100644
index 000000000..0506c4503
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/AuthenticationBlock.java
@@ -0,0 +1,266 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * Implementation of the SLP Authentication Block.
+ *
+ * @author Jan S. Rellermeyer, ETH Zurich
+ * @since 0.4
+ */
+class AuthenticationBlock {
+
+ /**
+ * the BSD code for DSA.
+ */
+ public static final short BSD_DSA = 0x0002;
+
+ /**
+ * the timestamp.
+ */
+ private int timestamp;
+
+ /**
+ * the data.
+ */
+ private byte[] data = null;
+
+ /**
+ * the signature.
+ */
+ private byte[] sig = null;
+
+ /**
+ * the SPI.
+ */
+ private String spi = null;
+
+ /**
+ * create a new Instance of an AuthenticationBlock.
+ *
+ * @param bsd
+ * the BSD, only BSD_DSA is currently supported.
+ * @param spiStr
+ * the SPI String.
+ * @param timeStamp
+ * the timestamp.
+ * @param byteData
+ * the binary data.
+ * @param signature
+ * the signature, if avaliable.
+ * @throws ServiceLocationException
+ * in case of processing errors.
+ */
+ AuthenticationBlock(final short bsd, final String spiStr,
+ final int timeStamp, final byte[] byteData, final byte[] signature)
+ throws ServiceLocationException {
+ this();
+
+ if (bsd != 0x0002) {
+ throw new ServiceLocationException(
+ ServiceLocationException.NOT_IMPLEMENTED,
+ "Only BSD 0x0002 (DSA) is supported.");
+ }
+
+ timestamp = timeStamp;
+ data = byteData;
+ spi = spiStr;
+
+ if (signature == null) {
+ sign();
+ } else {
+ sig = signature;
+ }
+ }
+
+ /**
+ *
+ *
+ */
+ AuthenticationBlock() {
+ }
+
+ /**
+ * sign the AuthenticationBlock.
+ *
+ * @throws ServiceLocationException
+ * in case of processing errors.
+ */
+ private void sign() throws ServiceLocationException {
+ try {
+ PrivateKey privateKey = SLPCore.CONFIG.getPrivateKey(spi);
+ SLPCore.platform.logDebug("Signing with SPI: " + spi);
+ Signature signature = Signature.getInstance("SHA1withDSA");
+ signature.initSign(privateKey);
+ signature.update(data);
+ sig = signature.sign();
+ } catch (Exception e) {
+ SLPCore.platform.logError(e.getMessage(), e.fillInStackTrace());
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED,
+ "Could not sign data");
+ }
+ }
+
+ /**
+ * get the SPI.
+ *
+ * @return the SPI.
+ */
+ String getSPI() {
+ return spi;
+ }
+
+ /**
+ * get the timestamp.
+ *
+ * @return the timestamp.
+ */
+ int getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * verify the authBlock.
+ *
+ * @param verData
+ * the auth data.
+ * @return true if verification suceeds.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ boolean verify(final byte[] verData) throws ServiceLocationException {
+ try {
+ PublicKey publicKey = SLPCore.CONFIG.getPublicKey(spi);
+
+ Signature signature = Signature.getInstance("SHA1withDSA");
+ signature.initVerify(publicKey);
+ signature.update(verData);
+ boolean success = signature.verify(sig);
+ SLPCore.platform.logDebug((success ? "Verified with SPI: "
+ : "Verification failed with SPI: ")
+ + spi);
+
+ return success;
+ } catch (Exception e) {
+ SLPCore.platform.logError(e.getMessage(), e.fillInStackTrace());
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED,
+ "Could not verify data with SPI: " + spi);
+ }
+ }
+
+ /**
+ * calculates the length of this auth block.
+ *
+ * @return the length.
+ */
+ int getLength() {
+ return 2 // BSD
+ + 2 // Block length
+ + 4 // timestamp
+ + 2 // spi length
+ + spi.getBytes().length // spi
+ + sig.length; // signature
+ }
+
+ /**
+ * get the bytes.
+ *
+ * @return the bytes.
+ * @throws IOException
+ * in case of IO errors.
+ */
+ void write(final DataOutputStream out) throws IOException {
+ out.writeShort(BSD_DSA); // BSD
+ out.writeShort((short) getLength());
+ out.writeInt(timestamp);
+ byte[] temp = spi.getBytes();
+ out.writeShort(temp.length);
+ out.write(temp);
+ out.write(sig);
+ }
+
+ /**
+ * parse a AuthenticationBlock array.
+ *
+ * @param input
+ * the DataInput.
+ * @return a AuthenticationBlock array.
+ * @throws ServiceLocationException
+ * in case of parse / IO errors.
+ * @throws IOException
+ * @throws ServiceLocationException
+ */
+ static AuthenticationBlock[] parse(final DataInputStream input)
+ throws IOException, ServiceLocationException {
+
+ List blocks = new ArrayList();
+ short blockCount = (short) input.readByte();
+ for (int i = 0; i < blockCount; i++) {
+ AuthenticationBlock authBlock = new AuthenticationBlock();
+ short bsd = (short) input.readShort();
+ if (bsd != BSD_DSA) {
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED, "BSD "
+ + bsd + " is not supported.");
+ }
+ int size = input.readShort();
+ authBlock.timestamp = input.readInt();
+ authBlock.spi = input.readUTF();
+ authBlock.sig = new byte[size - 2 - 2 - 4 - 2
+ - authBlock.spi.getBytes().length];
+ try {
+ input.readFully(authBlock.sig);
+ } catch (IOException ioe) {
+ throw new ServiceLocationException(
+ ServiceLocationException.PARSE_ERROR, ioe.getMessage());
+ }
+ blocks.add(authBlock);
+ }
+
+ if (!SLPCore.CONFIG.getSecurityEnabled()) {
+ return new AuthenticationBlock[0];
+ }
+
+ return (AuthenticationBlock[]) blocks
+ .toArray(new AuthenticationBlock[0]);
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/DAAdvertisement.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/DAAdvertisement.java
new file mode 100644
index 000000000..1860f560e
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/DAAdvertisement.java
@@ -0,0 +1,269 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * A DAAdvertisement is sent by a DA to advertise it's service.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+class DAAdvertisement extends ReplyMessage {
+
+ /**
+ * the errorCode of the message.
+ */
+ int errorCode;
+
+ /**
+ * the stateless boot timestamp. If 0, the DA will go down. SAs can
+ * determine if the DA has been rebooted since the last registration and if
+ * services have to be reregistered.
+ */
+ int statelessBootTimestamp;
+
+ /**
+ * the url of the DA.
+ */
+ String url;
+
+ /**
+ * a List of scopes that the DA supports.
+ */
+ List scopeList;
+
+ /**
+ * a List of attributes.
+ */
+ List attrList;
+
+ /**
+ * the spi string.
+ */
+ String spi;
+
+ /**
+ * the original URL.
+ */
+ private String origURL;
+
+ /**
+ * the original attributes.
+ */
+ private String origAttrs;
+
+ /**
+ * the original scopes.
+ */
+ private String origScopes;
+
+ /**
+ * the auth blocks.
+ */
+ AuthenticationBlock[] authBlocks;
+
+ /**
+ * create a new DAAdvertisement from a DataInput streaming the bytes of a
+ * DAAdvertisement message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ * @throws IOException
+ */
+ DAAdvertisement(final DataInputStream input)
+ throws ServiceLocationException, IOException {
+ errorCode = input.readShort();
+ statelessBootTimestamp = input.readInt();
+ origURL = input.readUTF().trim();
+ if (!origURL.equals("")) {
+ url = origURL
+ .substring(origURL.indexOf("//") + 2, origURL.length());
+ }
+ int pos = url.indexOf(":");
+ if (pos > -1) {
+ url = url.substring(0, pos);
+ }
+ origScopes = input.readUTF();
+ scopeList = stringToList(origScopes, ",");
+ if (scopeList.isEmpty()) {
+ throw new ServiceLocationException(
+ ServiceLocationException.PARSE_ERROR, "received DAadvert "
+ + "with empty scope list");
+ }
+ origAttrs = input.readUTF();
+ attrList = stringToList(origAttrs, ",");
+ spi = input.readUTF();
+ authBlocks = AuthenticationBlock.parse(input);
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ if (!verify()) {
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED,
+ "could not verify " + toString());
+ }
+ }
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = DAAdvert = 8) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Error Code | DA Stateless Boot Timestamp |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |DA Stateless Boot Time,, contd.| Length of URL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * \ URL \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length of &lt;scope-list&gt; | &lt;scope-list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length of &lt;attr-list&gt; | &lt;attr-list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length of &lt;SLP SPI List&gt; | &lt;SLP SPI List&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | # Auth Blocks | Authentication block (if any) \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ // this is never sent, since we are not a DA...
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ int len = getHeaderSize() + 8 + origURL.length() + 2
+ + origScopes.length() + 2 + origAttrs.length() + 2
+ + spi.length() + 1;
+ for (int i = 0; i < authBlocks.length; i++) {
+ len += authBlocks[i].getLength();
+ }
+ return len;
+ }
+
+ /**
+ * get a string representation of the AttributeReply message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", errorCode " + errorCode);
+ buffer.append(", statelessBootTimestamp " + statelessBootTimestamp);
+ buffer.append(", url " + url);
+ buffer.append(", scopeList " + scopeList);
+ buffer.append(", attrList " + attrList);
+ buffer.append(", spi " + spi);
+ return buffer.toString();
+ }
+
+ /**
+ * verify the DAAdvertisement.
+ *
+ * @return true if verification succeeded.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ boolean verify() throws ServiceLocationException {
+ for (int i = 0; i < authBlocks.length; i++) {
+ if (authBlocks[i].verify(getAuthData(authBlocks[i].getSPI(),
+ authBlocks[i].getTimestamp()))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * get the authentication data.
+ *
+ * @param spiStr
+ * the SPI
+ * @param timestamp
+ * the timestamp
+ * @return the authentication data.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ private byte[] getAuthData(final String spiStr, final int timestamp)
+ throws ServiceLocationException {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+
+ dos.writeUTF(spiStr);
+ dos.writeInt(statelessBootTimestamp);
+ dos.writeUTF(origURL);
+ /*
+ * THIS IS WRONG: RFC 2608 wants the attrs first, followed by the
+ * scopes but OpenSLP makes it the other way around !!!
+ *
+ * see bug #1346056
+ */
+ dos.writeUTF(origScopes);
+ dos.writeUTF(origAttrs);
+ dos.writeUTF(spi);
+ dos.writeInt(timestamp);
+
+ return bos.toByteArray();
+ } catch (IOException ioe) {
+ throw new ServiceLocationException(
+ ServiceLocationException.INTERNAL_SYSTEM_ERROR, ioe
+ .getMessage());
+ }
+ }
+
+ List getResult() {
+ return scopeList;
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/LocatorImpl.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/LocatorImpl.java
new file mode 100644
index 000000000..959cc7142
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/LocatorImpl.java
@@ -0,0 +1,315 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import ch.ethz.iks.slp.Advertiser;
+import ch.ethz.iks.slp.Locator;
+import ch.ethz.iks.slp.ServiceLocationEnumeration;
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceType;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * Implementation of the Locator interface. If the configuration does not have
+ * to provide UA functionalities, this class does not have to be included in the
+ * distribution.
+ *
+ * @see ch.ethz.iks.slp.Locator
+ * @author Jan S. Rellermeyer, ETH Zurich
+ * @since 0.1
+ */
+public final class LocatorImpl implements Locator {
+ /**
+ *
+ */
+ private Locale locale;
+
+ /**
+ * create a new LocatorImpl instance.
+ */
+ public LocatorImpl() {
+ locale = SLPCore.DEFAULT_LOCALE;
+ }
+
+ /**
+ * create a new LocatorImpl instance.
+ *
+ * @param theLocale
+ * the Locale for this instance.
+ */
+ public LocatorImpl(final Locale locale) {
+ this.locale = locale;
+ }
+
+ /**
+ * returns the locale for this instance.
+ *
+ * @return the Locale.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Set the locale of this instance.
+ *
+ * @param locale
+ * the Locale.
+ * @see Advertiser#setLocale()
+ */
+ public void setLocale(final Locale locale) {
+ this.locale = locale;
+ }
+
+ /**
+ * find the service types.
+ *
+ * @param namingAuthority
+ * the naming authority.
+ * @param scopes
+ * the scopes.
+ * @return a ServiceLocationEnumeration over the results.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ * @see Locator#findServiceTypes(String, List)
+ */
+ public ServiceLocationEnumeration findServiceTypes(
+ final String namingAuthority, final List scopes)
+ throws ServiceLocationException {
+ RequestMessage srvTypeReq = new ServiceTypeRequest(namingAuthority,
+ scopes, locale);
+ return new ServiceLocationEnumerationImpl(sendRequest(srvTypeReq,
+ scopes));
+ }
+
+ /**
+ * find services.
+ *
+ * @param type
+ * the service type.
+ * @param scopes
+ * the scopes.
+ * @param searchFilter
+ * an LDAP filter expression.
+ * @return a ServiceLocationEnumeration over the results.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ * @see Locator#findAttributes(ServiceType, List, List)
+ */
+ public ServiceLocationEnumeration findServices(final ServiceType type,
+ final List scopes, final String searchFilter)
+ throws ServiceLocationException {
+ try {
+ RequestMessage srvReq = new ServiceRequest(type, scopes,
+ searchFilter, locale);
+ return new ServiceLocationEnumerationImpl(sendRequest(srvReq,
+ scopes));
+ } catch (IllegalArgumentException ise) {
+ throw new ServiceLocationException(
+ ServiceLocationException.INTERNAL_SYSTEM_ERROR, ise
+ .getMessage()
+ + ": " + searchFilter);
+ }
+ }
+
+ /**
+ * find attributes by service URL.
+ *
+ * @param url
+ * the ServiceURL of the service.
+ * @param scopes
+ * a List of scoped to be included.
+ * @param attributeIds
+ * a List of attributes for which the values should be returned,
+ * if they exist.
+ * @return ServiceLocationEnumeration over the results.
+ * @throws ServiceLocationException
+ * in case of network errors etc.
+ * @see Locator#findAttributes(ServiceURL, List, List)
+ */
+ public ServiceLocationEnumeration findAttributes(final ServiceURL url,
+ final List scopes, final List attributeIds)
+ throws ServiceLocationException {
+ return findAttributes(new AttributeRequest(url, scopes, attributeIds,
+ locale));
+ }
+
+ /**
+ * find attributes by service type.
+ *
+ * @param type
+ * the service type.
+ * @param scopes
+ * the scopes.
+ * @param attributeIds
+ * a List of attributes for which the values should be returned,
+ * if they exist.
+ * @return a ServiceLocationEnumeration over the results.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ * @see Locator#findAttributes(ServiceType, List, List)
+ */
+ public ServiceLocationEnumeration findAttributes(final ServiceType type,
+ final List scopes, final List attributeIds)
+ throws ServiceLocationException {
+ return findAttributes(new AttributeRequest(type, scopes, attributeIds,
+ locale));
+ }
+
+ /**
+ * common method that handles a predefined AttributeRequest.
+ *
+ * @param attReq
+ * the AttributeRequest.
+ * @return the resulting Attributes as String.
+ * @throws ServiceLocationException
+ * in case of network errors.
+ */
+ private ServiceLocationEnumeration findAttributes(
+ final AttributeRequest attReq) throws ServiceLocationException {
+ return new ServiceLocationEnumerationImpl(sendRequest(attReq,
+ attReq.scopeList));
+ }
+
+ /**
+ * send a request. Uses direct communication to a DA or multicast
+ * convergence, if no DA is known for the specific scope.
+ *
+ * @param req
+ * the request.
+ * @param scopeList
+ * the scopes.
+ * @return the list of results.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ */
+ private List sendRequest(final RequestMessage req, final List scopeList)
+ throws ServiceLocationException {
+ List scopes = scopeList != null ? scopeList : Arrays
+ .asList(new String[] { "default" });
+
+ ArrayList result = new ArrayList();
+ for (Iterator scopeIter = scopes.iterator(); scopeIter.hasNext();) {
+ String scope = (String) scopeIter.next();
+ scope = scope.toLowerCase();
+ List dAs = (List) SLPCore.dAs.get(scope);
+
+ SLPCore.platform
+ .logDebug("DAS FOR SCOPE " + scope + ": " + dAs);
+
+ // no DA for the scope known ?
+ // try to find one
+ if ((dAs == null || dAs.isEmpty()) && !SLPCore.noDiscovery) {
+ SLPCore.daLookup(Arrays.asList(new String[] { scope }));
+
+ // wait a short time for incoming replies
+ synchronized (SLPCore.dAs) {
+ try {
+ SLPCore.dAs.wait(SLPCore.CONFIG.getWaitTime() / 4);
+ } catch (InterruptedException e) {
+ SLPCore.platform.logError(e.getMessage(), e);
+ // Restore the interrupted status as we're not the owner of the current thread
+ Thread.currentThread().interrupt();
+ }
+ }
+ dAs = (List) SLPCore.dAs.get(scope);
+ }
+
+ if (dAs != null && !dAs.isEmpty()) {
+ // a DA is known for this scope, so contact it
+ try {
+ result.addAll(sendRequestToDA(req, dAs));
+ } catch (ServiceLocationException slp) {
+ result.addAll(SLPCore.multicastConvergence(req));
+ }
+ continue;
+ } else {
+ if (SLPCore.noDiscovery) {
+ throw new ServiceLocationException(
+ ServiceLocationException.SCOPE_NOT_SUPPORTED,
+ "Scope " + scope + " is not supported");
+ }
+
+ // still no DA available, use multicast
+ result.addAll(SLPCore.multicastConvergence(req));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * send a request to a DA.
+ *
+ * @param req
+ * the request.
+ * @param dAaddresses
+ * the DA address.
+ * @return the <code>List</code> of results.
+ * @throws ServiceLocationException
+ */
+ private List sendRequestToDA(final RequestMessage req,
+ final List dAaddresses) throws ServiceLocationException {
+ for (int index = 0; index < dAaddresses.size(); index++) {
+ ReplyMessage reply = null;
+ try {
+ // set the receiver address
+ req.address = InetAddress.getByName((String) dAaddresses
+ .get(index));
+ req.port = SLPCore.SLP_RESERVED_PORT;
+ reply = (ReplyMessage) SLPCore.sendMessage(req, true);
+ if (reply.errorCode == 0) {
+ // we could receive a valid reply from the DA
+ return reply.getResult();
+ }
+ } catch (Exception e) {
+ SLPCore.platform.logError(e.getMessage(), e
+ .fillInStackTrace());
+ // something went wrong.
+ // remove DA from list.
+ final Object url = dAaddresses.get(index);
+ SLPUtils.removeValueFromAll(SLPCore.dAs, url);
+ SLPCore.dASPIs.remove(url);
+ // Try the next DA in the list.
+ continue;
+ }
+ }
+ // did not work. Return an empty result array.
+ throw new ServiceLocationException(
+ ServiceLocationException.INTERNAL_SYSTEM_ERROR,
+ "No DA reachable");
+ }
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/OSGiPlatformAbstraction.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/OSGiPlatformAbstraction.java
new file mode 100644
index 000000000..56c114a5c
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/OSGiPlatformAbstraction.java
@@ -0,0 +1,234 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+
+import ch.ethz.iks.slp.impl.filter.Filter;
+
+/**
+ * Platform abstraction for the OSGi implementation.
+ *
+ * @author Jan S. Rellermeyer, ETH Zurich
+ */
+public class OSGiPlatformAbstraction implements PlatformAbstraction,
+ ServiceListener {
+
+ /**
+ *
+ */
+ private final BundleContext context;
+
+ /**
+ *
+ */
+ private LogService log = new NullPatternLogService();
+
+ /**
+ * Constructor.
+ *
+ * @param context
+ * the bundle context from the OSGi framework.
+ * @param log
+ * the LogService, or null.
+ * @param debug
+ * true if debugging is enabled.
+ * @throws InvalidSyntaxException
+ * may never happen
+ */
+ OSGiPlatformAbstraction(BundleContext context) throws InvalidSyntaxException {
+ this.context = context;
+
+ // initially get the LogService
+ final ServiceReference sref = context
+ .getServiceReference(LogService.class.getName());
+ if (sref != null) {
+ this.log = (LogService) context.getService(sref);
+ }
+
+ // track the LogService for life cycle events
+ context.addServiceListener(this, "(" + Constants.OBJECTCLASS + "=" + LogService.class.getName() + ")");
+
+ logDebug("jSLP OSGi started.");
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#createFilter(java.lang.String)
+ */
+ public Filter createFilter(String filterString) {
+ try {
+ final org.osgi.framework.Filter filter = context
+ .createFilter(filterString);
+ return new Filter() {
+ public boolean match(Dictionary values) {
+ return filter.match(values);
+ }
+
+ public String toString() {
+ return filter.toString();
+ }
+ };
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logDebug(java.lang.String)
+ */
+ public void logDebug(String message) {
+ if(SLPCore.CONFIG.getDebugEnabled()) {
+ log.log(LogService.LOG_DEBUG, message);
+ }
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logDebug(java.lang.String,
+ * java.lang.Throwable)
+ */
+ public void logDebug(String message, Throwable exception) {
+ if(SLPCore.CONFIG.getDebugEnabled()) {
+ log.log(LogService.LOG_DEBUG, message, exception);
+ }
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logError(java.lang.String)
+ */
+ public void logError(String message) {
+ log.log(LogService.LOG_ERROR, message);
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logError(java.lang.String,
+ * java.lang.Throwable)
+ */
+ public void logError(String message, Throwable exception) {
+ log.log(LogService.LOG_ERROR, message, exception);
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logTraceMessage(java.lang.String)
+ */
+ public void logTraceMessage(String message) {
+ if(SLPCore.CONFIG.getTraceMessage()) {
+ log.log(LogService.LOG_INFO, message);
+ }
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logTraceDrop(java.lang.String)
+ */
+ public void logTraceDrop(String message) {
+ if(SLPCore.CONFIG.getTraceDrop()) {
+ log.log(LogService.LOG_INFO, message);
+ }
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logTraceMessage(java.lang.String)
+ */
+ public void logTraceReg(String message) {
+ if(SLPCore.CONFIG.getTraceReg()) {
+ log.log(LogService.LOG_INFO, message);
+ }
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logWarning(java.lang.String)
+ */
+ public void logWarning(String message) {
+ log.log(LogService.LOG_WARNING, message);
+ }
+
+ /**
+ *
+ * @see ch.ethz.iks.slp.impl.PlatformAbstraction#logWarning(java.lang.String,
+ * java.lang.Throwable)
+ */
+ public void logWarning(String message, Throwable exception) {
+ log.log(LogService.LOG_WARNING, message, exception);
+ }
+
+ /**
+ *
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(final ServiceEvent event) {
+ switch (event.getType()) {
+ case ServiceEvent.REGISTERED:
+ log = (LogService) context.getService(event.getServiceReference());
+ return;
+ case ServiceEvent.UNREGISTERING:
+ log = new NullPatternLogService();
+ default:
+ }
+ }
+
+ // if no LogService is present, we use a dummy log
+ private class NullPatternLogService implements LogService {
+
+ public void log(int level, String message) {
+ if(level == LogService.LOG_ERROR || level == LogService.LOG_WARNING) {
+ System.err.println(message);
+ } else {
+ System.out.println(message);
+ }
+ }
+
+ public void log(int level, String message, Throwable exception) {
+ log(level, message + exception.getMessage());
+ }
+
+ public void log(ServiceReference sr, int level, String message) {
+ log(null, level, message);
+ }
+
+ public void log(ServiceReference sr, int level, String message, Throwable t) {
+ log(null, level, message, t);
+ }
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/PlatformAbstraction.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/PlatformAbstraction.java
new file mode 100644
index 000000000..0c8b57ee5
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/PlatformAbstraction.java
@@ -0,0 +1,127 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import ch.ethz.iks.slp.impl.filter.Filter;
+
+/**
+ * Platform abstraction interface. Used to hide the different implementations
+ * for the OSGi platform and for stand-alone Java.
+ *
+ * @author Jan S. Rellermeyer, ETH Zurich.
+ */
+public interface PlatformAbstraction {
+
+ /**
+ * Write a debug message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logDebug(String message);
+
+ /**
+ * Write a debug message to the log.
+ *
+ * @param message
+ * the message.
+ * @param exception
+ * an exception.
+ */
+ void logDebug(String message, Throwable exception);
+
+ /**
+ * Trace a generic message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logTraceMessage(String string);
+
+ /**
+ * Trace a registration to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logTraceReg(String string);
+
+ /**
+ * Trace a drop to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logTraceDrop(String string);
+
+ /**
+ * Write a warning message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logWarning(String message);
+
+ /**
+ * Write a warning message to the log.
+ *
+ * @param message
+ * the message.
+ * @param exception
+ * an exception.
+ */
+ void logWarning(String message, Throwable exception);
+
+ /**
+ * Write an error message to the log.
+ *
+ * @param message
+ * the message.
+ */
+ void logError(String message);
+
+ /**
+ * Write an error message to the log.
+ *
+ * @param message
+ * the message.
+ * @param exception
+ * an exception.
+ */
+ void logError(String message, Throwable exception);
+
+ /**
+ * Create an LDAP filter.
+ *
+ * @param filterString
+ * the filter string.
+ * @return an LDAP filter object.
+ */
+ Filter createFilter(String filterString);
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ReplyMessage.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ReplyMessage.java
new file mode 100644
index 000000000..2754df0bc
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ReplyMessage.java
@@ -0,0 +1,53 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.util.List;
+
+/**
+ * abstract base class for all ReplyMessages.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+abstract class ReplyMessage extends SLPMessage {
+
+ /**
+ * the error code that is returned.
+ */
+ int errorCode;
+
+ /**
+ * get the results.
+ *
+ * @return the List of results.
+ */
+ abstract List getResult();
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/RequestMessage.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/RequestMessage.java
new file mode 100644
index 000000000..ec7e1a951
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/RequestMessage.java
@@ -0,0 +1,52 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.util.List;
+
+/**
+ * Abstract base class for all request messages.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+abstract class RequestMessage extends SLPMessage {
+ /**
+ * the list of previous responders. If a peer receives a request message and
+ * is already in the previous responder list, it will silently drop the
+ * message.
+ */
+ List prevRespList;
+
+ /**
+ * a list of scopes that will be included.
+ */
+ List scopeList;
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPConfiguration.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPConfiguration.java
new file mode 100644
index 000000000..fe99e971e
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPConfiguration.java
@@ -0,0 +1,524 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package ch.ethz.iks.slp.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+/**
+ * SLPConfiguration object holds all configurable properties.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Z�rich
+ * @since 0.1
+ */
+class SLPConfiguration {
+
+ private static final String USE_SCOPES_PROP = "net.slp.useScopes";
+
+ private static final String USE_SCOPES_DEFAULT = "DEFAULT";
+
+ private static final String DA_ADDRESSES_PROP = "net.slp.DAAddresses";
+
+ private static final String DA_ADDRESSES_DEFAULT = null;
+
+ private static final String WAIT_TIME_PROP = "net.slp.waitTime";
+
+ private static final String WAIT_TIME_DEFAULT = "1000";
+
+ private static final String TRACE_DATRAFFIC_PROP = "net.slp.traceDATraffic";
+
+ private static final String TRACE_DATRAFFIC_DEFAULT = "false";
+
+ private static final String TRACE_MESSAGE_PROP = "net.slp.traceMsg";
+
+ private static final String TRACE_MESSAGE_DEFAULT = "false";
+
+ private static final String TRACE_DROP_PROP = "net.slp.traceDrop";
+
+ private static final String TRACE_DROP_DEFAULT = "false";
+
+ private static final String TRACE_REG_PROP = "net.slp.traceReg";
+
+ private static final String TRACE_REG_DEFAULT = "false";
+
+ private static final String MCAST_TTL_PROP = "net.slp.multicastTTL";
+
+ private static final String MCAST_TTL_DEFAULT = "255";
+
+ private static final String MCAST_MAX_WAIT_PROP = "net.slp.multicastMaximumWait";
+
+ private static final String MCAST_MAX_WAIT_DEFAULT = "15000";
+
+ private static final String MCAST_TIMEOUTS_PROP = "net.slp.multicastTimeouts";
+
+ private static final String MCAST_TIMEOUTS_DEFAULT = "3000,2000,1500,1000,750,500";
+
+ private static final String DATAGRAM_MAX_WAIT_PROP = "net.slp.datagramMaximumWait";
+
+ private static final String DATAGRAM_MAX_WAIT_DEFAULT = "5000";
+
+ private static final String DATAGRAM_TIMEOUTS_PROP = "net.slp.datagramTimeouts";
+
+ private static final String DATAGRAM_TIMEOUTS_DEFAULT = "3000,3000,3000,3000,3000";
+
+ private static final String MTU_PROP = "net.slp.MTU";
+
+ private static final String MTU_DEFAULT = "1400";
+
+ private static final String SECURITY_ENABLED_PROP = "net.slp.securityEnabled";
+
+ private static final String SECURITY_ENABLED_DEFAULT = "false";
+
+ private static final String SPI_PROP = "net.slp.spi";
+
+ private static final String SPI_DEFAULT = "";
+
+ private static final String PRIVATE_KEY_PROP = "net.slp.privateKey.";
+
+ private static final String PUBLIC_KEY_PROP = "net.slp.publicKey.";
+
+ private static final String INTERFACES_PROP = "net.slp.interfaces";
+
+ private static final String INTERFACES_DEFAULT = null;
+
+ private static final String NO_DA_DISCOVERY_PROP = "net.slp.noDADiscovery";
+
+ private static final String PORT_PROP = "net.slp.port";
+
+ private static final String DEFAULT_PORT = "427";
+
+ private static final String DEFAULT_CONVERGENCE_FAILERCOUNT = "2";
+
+ private static final String CONVERGENCE_FAILERCOUNT_PROP = "net.slp.failercount";
+
+ private static final String DEBUG_ENABLED_PROP = "ch.ethz.iks.slp.debug";
+
+ private static String[] INTERFACES;
+
+ private static int PORT;
+
+ private static String SCOPES;
+
+ private static boolean NO_DA_DISCOVERY;
+
+ private static String[] DA_ADDRESSES;
+
+ private static boolean TRACE_DA_TRAFFIC;
+
+ private static boolean TRACE_MESSAGES;
+
+ private static boolean TRACE_DROP;
+
+ private static boolean TRACE_REG;
+
+ private static int MCAST_TTL;
+
+ private static int MCAST_MAX_WAIT;
+
+ private static int[] MCAST_TIMEOUTS;
+
+ private static int DATAGRAM_MAX_WAIT;
+
+ private static int[] DATAGRAM_TIMEOUTS;
+
+ private static int MTU;
+
+ private static boolean SECURITY_ENABLED;
+
+ private static String SPI;
+
+ private static int WAIT_TIME;
+
+ private static Map PUBLIC_KEY_CACHE;
+
+ private static Map PRIVATE_KEY_CACHE;
+
+ private static int CONVERGENCE_FAILERCOUNT;
+
+ private static boolean DEBUG_ENABLED;
+
+ /**
+ * create a new SLPConfiguration from properties.
+ *
+ * @param properties
+ * properties.
+ */
+ SLPConfiguration() {
+ processProperties(System.getProperties());
+ }
+
+ /**
+ * create a new SLPConfiguration from config file.
+ *
+ * @param file
+ * the file.
+ * @throws IOException
+ * in case of IO errors.
+ */
+ SLPConfiguration(final File file) throws IOException {
+ Properties props = new Properties();
+ props.load(new FileInputStream(file));
+ props.putAll(System.getProperties());
+ processProperties(props);
+ }
+
+ private static void processProperties(final Properties props) {
+ String ifaces = props.getProperty(INTERFACES_PROP, INTERFACES_DEFAULT);
+ if (ifaces == null) {
+ INTERFACES = null;
+ } else {
+ INTERFACES = (String[]) SLPMessage.stringToList(ifaces, ",")
+ .toArray(new String[0]);
+ }
+ PORT = Integer.parseInt(props.getProperty(PORT_PROP, DEFAULT_PORT));
+ SCOPES = props.getProperty(USE_SCOPES_PROP, USE_SCOPES_DEFAULT);
+ NO_DA_DISCOVERY = new Boolean(props.getProperty(NO_DA_DISCOVERY_PROP,
+ "false")).booleanValue();
+ final String dAs = props.getProperty(DA_ADDRESSES_PROP,
+ DA_ADDRESSES_DEFAULT);
+ if (dAs == null) {
+ DA_ADDRESSES = null;
+ } else {
+ DA_ADDRESSES = (String[]) SLPMessage.stringToList(dAs, ",")
+ .toArray(new String[0]);
+ }
+ TRACE_DA_TRAFFIC = new Boolean(props.getProperty(TRACE_DATRAFFIC_PROP,
+ TRACE_DATRAFFIC_DEFAULT)).booleanValue();
+ TRACE_MESSAGES = new Boolean(props.getProperty(TRACE_MESSAGE_PROP,
+ TRACE_MESSAGE_DEFAULT)).booleanValue();
+
+ TRACE_DROP = new Boolean(props.getProperty(TRACE_DROP_PROP,
+ TRACE_DROP_DEFAULT)).booleanValue();
+
+ TRACE_REG = new Boolean(props.getProperty(TRACE_REG_PROP,
+ TRACE_REG_DEFAULT)).booleanValue();
+
+ MCAST_TTL = Integer.parseInt(props.getProperty(MCAST_TTL_PROP,
+ MCAST_TTL_DEFAULT));
+
+ MCAST_MAX_WAIT = Integer.parseInt(props.getProperty(
+ MCAST_MAX_WAIT_PROP, MCAST_MAX_WAIT_DEFAULT));
+
+ DATAGRAM_MAX_WAIT = Integer.parseInt(props.getProperty(
+ DATAGRAM_MAX_WAIT_PROP, DATAGRAM_MAX_WAIT_DEFAULT));
+
+ MCAST_TIMEOUTS = parseTimeouts(props.getProperty(MCAST_TIMEOUTS_PROP,
+ MCAST_TIMEOUTS_DEFAULT));
+
+ DATAGRAM_TIMEOUTS = parseTimeouts(props.getProperty(
+ DATAGRAM_TIMEOUTS_PROP, DATAGRAM_TIMEOUTS_DEFAULT));
+
+ MTU = Integer.parseInt(props.getProperty(MTU_PROP, MTU_DEFAULT));
+
+ SECURITY_ENABLED = new Boolean(props.getProperty(SECURITY_ENABLED_PROP,
+ SECURITY_ENABLED_DEFAULT)).booleanValue();
+
+ SPI = props.getProperty(SPI_PROP, SPI_DEFAULT);
+
+ WAIT_TIME = Integer.parseInt(props.getProperty(WAIT_TIME_PROP,
+ WAIT_TIME_DEFAULT));
+
+ CONVERGENCE_FAILERCOUNT = Integer.parseInt(props.getProperty(CONVERGENCE_FAILERCOUNT_PROP, DEFAULT_CONVERGENCE_FAILERCOUNT));
+
+ DEBUG_ENABLED = new Boolean(props.getProperty(DEBUG_ENABLED_PROP,
+ "false")).booleanValue();
+
+ if (SECURITY_ENABLED) {
+ PUBLIC_KEY_CACHE = new HashMap(0);
+ PRIVATE_KEY_CACHE = new HashMap(0);
+ }
+ }
+
+ /**
+ * returns the network interfaces.
+ *
+ * @return interfaces
+ */
+ String[] getInterfaces() {
+ return INTERFACES;
+ }
+
+ /**
+ * get the port.
+ *
+ * @return the port
+ */
+ int getPort() {
+ return PORT;
+ }
+
+ /**
+ * get the scopes.
+ *
+ * @return the scopes.
+ */
+ String getScopes() {
+ return SCOPES;
+ }
+
+ /**
+ * get the predefined DA addresses.
+ *
+ * @return the DA addresses.
+ */
+ String[] getDaAddresses() {
+ return DA_ADDRESSES;
+ }
+
+ /**
+ * get no DA discovery
+ *
+ * @return true, if DA discovery is disabled
+ */
+ boolean getNoDaDiscovery() {
+ return NO_DA_DISCOVERY;
+ }
+
+ /**
+ * trace DA traffic ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceDaTraffic() {
+ return TRACE_DA_TRAFFIC;
+ }
+
+ /**
+ * trace messages ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceMessage() {
+ return TRACE_MESSAGES;
+ }
+
+ /**
+ * trace dropped messages ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceDrop() {
+ return TRACE_DROP;
+ }
+
+ /**
+ * trace registrations ?
+ *
+ * @return true if trace is enabled.
+ */
+ boolean getTraceReg() {
+ return TRACE_REG;
+ }
+
+ /**
+ * get the multicast TTL.
+ *
+ * @return the multicast TTL.
+ */
+ int getMcastTTL() {
+ return MCAST_TTL;
+ }
+
+ /**
+ * get the multicast max wait time.
+ *
+ * @return the max wait time.
+ */
+ int getMcastMaxWait() {
+ return MCAST_MAX_WAIT;
+ }
+
+ /**
+ * get the datagram max wait time.
+ *
+ * @return the datagram max wait time.
+ */
+ int getDatagramMaxWait() {
+ return DATAGRAM_MAX_WAIT;
+ }
+
+ /**
+ * parse timeout lists.
+ *
+ * @param s
+ * a timeout list string.
+ * @return the timeout int array.
+ */
+ private static int[] parseTimeouts(final String s) {
+ StringTokenizer st = new StringTokenizer(s, ",");
+ int[] timeouts = new int[st.countTokens()];
+ for (int i = 0; i < timeouts.length; i++) {
+ timeouts[i] = Integer.parseInt(st.nextToken());
+ }
+ return timeouts;
+ }
+
+ /**
+ * get the multicast timeouts.
+ *
+ * @return the multicast timeouts.
+ */
+ int[] getMcastTimeouts() {
+ return MCAST_TIMEOUTS;
+ }
+
+ /**
+ * get the datagram timeouts.
+ *
+ * @return the datagram timeouts.
+ */
+ int[] getDatagramTimeouts() {
+ return DATAGRAM_TIMEOUTS;
+ }
+
+ /**
+ * get the MTU.
+ *
+ * @return the MTU.
+ */
+ int getMTU() {
+ return MTU;
+ }
+
+ /**
+ * is security enabled ?
+ *
+ * @return true if security is enabled.
+ */
+ boolean getSecurityEnabled() {
+ return SECURITY_ENABLED;
+ }
+
+ /**
+ * get the SPIs.
+ *
+ * @return the SPI string list.
+ */
+ String getSPI() {
+ return SPI;
+ }
+
+ /**
+ * get the public key for a certain SPI.
+ *
+ * @param spi
+ * the SPI.
+ * @return the location of the public key.
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ PublicKey getPublicKey(final String spi) throws IOException,
+ GeneralSecurityException {
+ PublicKey key = (PublicKey) PUBLIC_KEY_CACHE.get(spi);
+ if (key != null) {
+ return key;
+ }
+ FileInputStream keyfis = new FileInputStream(System
+ .getProperty(PUBLIC_KEY_PROP + spi));
+ byte[] encKey = new byte[keyfis.available()];
+ keyfis.read(encKey);
+ keyfis.close();
+ X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+ key = keyFactory.generatePublic(pubKeySpec);
+ PUBLIC_KEY_CACHE.put(spi, key);
+ return key;
+ }
+
+ /**
+ * get the private key for a certain SPI.
+ *
+ * @param spi
+ * the SPI.
+ * @return the location of the private key.
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ PrivateKey getPrivateKey(final String spi) throws IOException,
+ GeneralSecurityException {
+ PrivateKey key = (PrivateKey) PRIVATE_KEY_CACHE.get(spi);
+ if (key != null) {
+ return key;
+ }
+ FileInputStream keyfis = new FileInputStream(System
+ .getProperty(PRIVATE_KEY_PROP + spi));
+
+ byte[] encKey = new byte[keyfis.available()];
+ keyfis.read(encKey);
+ keyfis.close();
+
+ PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
+
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+ key = keyFactory.generatePrivate(privKeySpec);
+ PRIVATE_KEY_CACHE.put(spi, key);
+ return key;
+ }
+
+ /**
+ * get the default wait time.
+ *
+ * @return the default wait time.
+ */
+ int getWaitTime() {
+ return WAIT_TIME;
+ }
+
+ /**
+ * Defines after how many inconclusive multicastConvergence cycles the attempt is aborted.
+ * It indirectly defines how many multicast convergence {@link SLPMessage}.SRVTYPERQST get send during an attempt.
+ *
+ * This value can be seen as an heuristical optimization to stop multicast convergence early if inconclusive
+ * @return how many inconclusive cycles are allowed
+ */
+ int getConvergenceFailerCount() {
+ return CONVERGENCE_FAILERCOUNT;
+ }
+
+ public boolean getDebugEnabled() {
+ return DEBUG_ENABLED;
+ }
+
+ public int getTCPTimeout() {
+ // TODO wire this to the properties if necessary
+ return 5000; // 5sec
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPCore.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPCore.java
new file mode 100644
index 000000000..4df3743aa
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPCore.java
@@ -0,0 +1,997 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Institute for Pervasive Computing, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package ch.ethz.iks.slp.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.lang.reflect.Constructor;
+import java.net.BindException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.ProtocolException;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceType;
+
+/**
+ * the core class of the jSLP implementation.
+ * <code>ch.ethz.iks.slp.ServiceLocationManager</code> inherits from this
+ * class.
+ *
+ * @see ch.ethz.iks.slp.impl.ServiceLocationManager
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @since 0.6
+ */
+public abstract class SLPCore {
+ private static volatile boolean isMulticastSocketInitialized = false;
+ private static volatile boolean isInitialized = false;
+
+ protected static PlatformAbstraction platform;
+
+ /**
+ * the default empty locale. Used for messages that don't specify a locale.
+ */
+ static final Locale DEFAULT_LOCALE = Locale.getDefault();
+
+ /**
+ * the port for SLP communication.
+ */
+ static final int SLP_PORT;
+
+ /**
+ * the reserved (standard) port.
+ */
+ static final int SLP_RESERVED_PORT = 427;
+
+ /**
+ * the standard SLP multicast address.
+ */
+ static final String SLP_MCAST_ADDRESS = "239.255.255.253";
+
+ /**
+ *
+ */
+ static final InetAddress MCAST_ADDRESS;
+
+ /**
+ * the SLP configuration.
+ */
+ static final SLPConfiguration CONFIG;
+
+ /**
+ * currently only for debugging.
+ */
+ static final boolean TCP_ONLY = false;
+
+ /**
+ * the standard service type for DAs.
+ */
+ static final String SLP_DA_TYPE = "service:directory-agent";
+
+ /**
+ * my own ip. Used to check if this peer is already in the previous
+ * responder list.
+ */
+ static String[] myIPs;
+
+ /**
+ * configured to perform no DA discovery ?
+ */
+ static final boolean noDiscovery;
+
+ /**
+ * the constructor for <code>Advertiser</code> instances, if an
+ * implementation exists.
+ */
+ protected static final Constructor advertiser;
+
+ /**
+ * the constructor for <code>Locator</code> instances, if an
+ * implementation exists.
+ */
+ protected static final Constructor locator;
+
+ /**
+ * the constructor for <code>SLPDaemon</code> instances, if an
+ * implementation exists.
+ */
+ private static final Constructor daemonConstr;
+
+ /**
+ * the daemon instance, if the implementation exists and no other daemon is
+ * already running on the machine.
+ */
+ private static SLPDaemon daemon;
+
+ /**
+ * the multicast server thread.
+ */
+ private static Thread multicastThread;
+
+ /**
+ * the multicast socket.
+ */
+ private static MulticastSocket mtcSocket;
+
+ /**
+ * the next free XID.
+ */
+ private static short nextXid;
+
+ /**
+ * used to asynchronously receive replies. query XID -> reply queue (List)
+ */
+ private static Map replyListeners = new HashMap();
+
+ /**
+ * Map of DAs:
+ *
+ * String scope -> list of Strings of DA URLs.
+ */
+ static Map dAs = new HashMap();
+
+ /**
+ * Map of DA SPIs:
+ *
+ * String DA URL -> String String.
+ */
+ static Map dASPIs = new HashMap(); // DA URL -> List of SPIs
+
+ static InetAddress LOCALHOST;
+
+ /**
+ * initialize the core class.
+ */
+ static {
+ try {
+ LOCALHOST = InetAddress.getLocalHost();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ final Class[] locale = new Class[] { Locale.class };
+
+ // check, if an Advertiser implementation is available
+ Constructor constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.AdvertiserImpl")
+ .getConstructor(locale);
+ } catch (Exception e) {
+ }
+ advertiser = constr;
+
+ // check, if a Locator implementation is available
+ constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.LocatorImpl")
+ .getConstructor(locale);
+ } catch (Exception e) {
+ }
+ locator = constr;
+
+ // check, if a Daemon is available
+ constr = null;
+ try {
+ constr = Class.forName("ch.ethz.iks.slp.impl.SLPDaemonImpl")
+ .getConstructor(null);
+ } catch (Exception e) {
+ }
+ daemonConstr = constr;
+
+ // read in the property file, if it exists
+ File propFile = new File("jslp.properties");
+ SLPConfiguration config;
+ try {
+ config = propFile.exists() ? new SLPConfiguration(propFile)
+ : new SLPConfiguration();
+ } catch (IOException e1) {
+ System.out.println("Could not parse the property file" + propFile.toString());
+ e1.printStackTrace();
+ config = new SLPConfiguration();
+ }
+ CONFIG = config;
+
+ noDiscovery = CONFIG.getNoDaDiscovery();
+
+ // determine the interfaces on which jSLP runs on
+ String[] IPs = CONFIG.getInterfaces();
+ if (IPs == null) {
+ InetAddress[] addresses = null;
+ try {
+ addresses = InetAddress.getAllByName(InetAddress.getLocalHost()
+ .getHostName());
+ IPs = new String[addresses.length];
+ for (int i = 0; i < addresses.length; i++) {
+ IPs[i] = addresses[i].getHostAddress();
+ }
+ } catch (UnknownHostException e) {
+ System.err
+ .println("Reverse lookup of host name failed. Running service discovery on localloop.");
+ try {
+ addresses = new InetAddress[] { InetAddress.getLocalHost() };
+ } catch (UnknownHostException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ myIPs = IPs;
+ SLP_PORT = CONFIG.getPort();
+
+ // initialize the XID with a random number
+ nextXid = (short) Math.round(Math.random() * Short.MAX_VALUE);
+
+ InetAddress mcast = null;
+ try {
+ mcast = InetAddress.getByName(SLPCore.SLP_MCAST_ADDRESS);
+ } catch (UnknownHostException e1) {
+ e1.printStackTrace();
+ }
+
+ MCAST_ADDRESS = mcast;
+ }
+
+ protected static void init() {
+ if(isInitialized) {
+ return;
+ }
+ isInitialized = true;
+
+ platform.logDebug("jSLP is running on the following interfaces: "
+ + java.util.Arrays.asList(myIPs));
+ platform.logDebug("jSLP is using port: " + SLP_PORT);
+
+ String[] daAddresses = CONFIG.getDaAddresses();
+ if (daAddresses == null) {
+ if (noDiscovery) {
+ throw new IllegalArgumentException(
+ "Configuration 'net.slp.noDaDiscovery=true' requires a non-empty list of preconfigured DAs");
+ }
+ } else {
+ try {
+ // process the preconfigured DAs
+ final ServiceRequest req = new ServiceRequest(new ServiceType(
+ SLP_DA_TYPE), null, null, null);
+ req.port = SLP_PORT;
+ for (int i = 0; i < daAddresses.length; i++) {
+ try {
+ req.address = InetAddress.getByName(daAddresses[i]);
+ DAAdvertisement daa = (DAAdvertisement) sendMessage(
+ req, true);
+ String[] scopes = (String[]) daa.scopeList
+ .toArray(new String[daa.scopeList.size()]);
+ for (int j = 0; j < scopes.length; j++) {
+ platform.logDebug("jSLP is adding DA, "
+ + daAddresses[i] + " for the Scope, "
+ + scopes[j]);
+ SLPUtils.addValue(dAs, scopes[i].toLowerCase(), daAddresses[i]);
+ }
+ } catch (ServiceLocationException e) {
+ platform.logWarning("Error communitcating with " + daAddresses[i], e);
+ } catch (UnknownHostException e) {
+ platform.logWarning("Unknown net.slp.DAAddresses address: " + daAddresses[i], e);
+ }
+ }
+ } catch (IllegalArgumentException ise) {
+ platform.logDebug("May never happen", ise);
+ }
+ }
+
+ if (!noDiscovery) {
+ // perform an initial lookup
+ try {
+ List scopes = new ArrayList();
+ scopes.add("default");
+ daLookup(scopes);
+ } catch (Exception e) {
+ platform.logError("Exception in initial DA lookup", e);
+ }
+ }
+
+ }
+
+ // a pure UA doesn't need a multicast listener which is only required by a SA or DA
+ protected static void initMulticastSocket() {
+ if(isMulticastSocketInitialized) {
+ return;
+ }
+ isMulticastSocketInitialized = true;
+
+ try {
+ mtcSocket = new MulticastSocket(SLP_PORT);
+ mtcSocket.setTimeToLive(CONFIG.getMcastTTL());
+ if (CONFIG.getInterfaces() != null) {
+ try {
+ mtcSocket.setInterface(InetAddress.getByName(myIPs[0]));
+ } catch (Throwable t) {
+ platform.logDebug("Setting multicast socket interface to " + myIPs[0] + " failed.",t);
+ }
+ }
+ mtcSocket.joinGroup(MCAST_ADDRESS);
+ } catch (BindException be) {
+ platform.logError(be.getMessage(), be);
+ throw new RuntimeException("You have to be root to open port "
+ + SLP_PORT);
+ } catch (Exception e) {
+ platform.logError(e.getMessage(), e);
+ }
+
+ // setup and start the multicast thread
+ multicastThread = new Thread() {
+ public void run() {
+ DatagramPacket packet;
+ byte[] bytes = new byte[SLPCore.CONFIG.getMTU()];
+ while (true) {
+ try {
+ packet = new DatagramPacket(bytes, bytes.length);
+ mtcSocket.receive(packet);
+ final SLPMessage reply = handleMessage(SLPMessage
+ .parse(packet.getAddress(), packet.getPort(),
+ new DataInputStream(
+ new ByteArrayInputStream(packet
+ .getData())), false));
+ if (reply != null) {
+ final byte[] repbytes = reply.getBytes();
+ DatagramPacket datagramPacket = new DatagramPacket(
+ repbytes, repbytes.length, reply.address,
+ reply.port);
+ mtcSocket.send(datagramPacket);
+ platform.logDebug("SEND (" + reply.address
+ + ":" + reply.port + ") "
+ + reply.toString());
+ }
+ } catch (Exception e) {
+ platform
+ .logError(
+ "Exception in Multicast Receiver Thread",
+ e);
+ }
+ }
+ }
+ };
+ multicastThread.start();
+
+ // check, if there is already a SLP daemon runnung on port 427
+ // that can be either a jSLP daemon, or an OpenSLP daemon or something
+ // else. If not, try to start a new daemon instance.
+ if (daemonConstr != null) {
+ try {
+ daemon = (SLPDaemon) daemonConstr.newInstance(null);
+ } catch (Exception e) {
+ daemon = null;
+ }
+ }
+ }
+
+ /**
+ * get my own IP.
+ *
+ * @return the own IP.
+ */
+ static InetAddress getMyIP() {
+ try {
+ return InetAddress.getByName(myIPs[0]);
+ } catch (UnknownHostException e) {
+ platform.logError("Unknown net.slp.interfaces address: " + myIPs[0], e);
+ return null;
+ }
+ }
+
+ /**
+ * get the list of all available scopes.
+ *
+ * @return a List of all available scopes. RFC 2614 proposes
+ * <code>Vector</code> but jSLP returns <code>List</code>.
+ * @throws ServiceLocationException
+ * in case of an exception in the underlying framework.
+ */
+ public static List findScopes() throws ServiceLocationException {
+ return new ArrayList(dAs.keySet());
+ }
+
+ /**
+ * handle incoming UDP messages.
+ *
+ * @param message
+ * the incoming message.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ */
+ private static SLPMessage handleMessage(final SLPMessage message)
+ throws ServiceLocationException {
+ if (message == null) {
+ return null;
+ }
+
+ platform.logTraceMessage("RECEIVED (" + message.address + ":"
+ + message.port + ") " + message);
+
+ switch (message.funcID) {
+ case SLPMessage.DAADVERT:
+ // drop message, if noDADiscovery is set
+ if (noDiscovery) {
+ platform.logTraceDrop("DROPPED (" + message.address + ":"
+ + message.port + ") " + message.toString()
+ + "(reason: noDADiscovery is set");
+ return null;
+ }
+
+ DAAdvertisement advert = (DAAdvertisement) message;
+
+ if (advert.errorCode != 0) {
+ platform.logTraceDrop("DROPPED DAADvertisement (" + advert.address + ":"
+ + advert.port + ") " + advert.toString()
+ + "(reason: " + advert.errorCode + " != 0");
+ return null;
+ }
+
+ if (advert.url != advert.address.getHostAddress()) {
+ advert.url = advert.address.getHostAddress();
+ }
+
+ // statelessBootTimestamp = 0 means DA is going down
+ if (advert.statelessBootTimestamp == 0) {
+ for (Iterator iter = advert.scopeList.iterator(); iter
+ .hasNext();) {
+ String scope = ((String) iter.next()).toLowerCase();
+ SLPUtils.removeValue(SLPCore.dAs, scope.toLowerCase(), advert.url);
+ dASPIs.remove(advert.url);
+ }
+ } else {
+ for (Iterator iter = advert.scopeList.iterator(); iter
+ .hasNext();) {
+ String scope = ((String) iter.next()).toLowerCase();
+
+ // 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
+ // not caring for the sBT at all.
+ SLPUtils.addValue(SLPCore.dAs, scope, advert.url);
+
+ if (CONFIG.getSecurityEnabled()) {
+ dASPIs.put(advert.url, SLPMessage.stringToList(
+ advert.spi, ","));
+ }
+
+ }
+
+ synchronized (dAs) {
+ dAs.notifyAll();
+ }
+
+ // if there is a daemon instance, inform it about the discovered
+ // DA
+ if (daemon != null) {
+ daemon.newDaDiscovered(advert);
+ }
+
+ }
+ platform.logDebug("NEW DA LIST: " + dAs);
+
+ return null;
+
+ // reply messages
+ case SLPMessage.ATTRRPLY:
+ case SLPMessage.SRVRPLY:
+ case SLPMessage.SRVTYPERPLY:
+ synchronized (replyListeners) {
+ List queue = (List) replyListeners
+ .get(new Integer(message.xid));
+
+ if (queue != null) {
+ synchronized (queue) {
+ queue.add(message);
+ queue.notifyAll();
+ }
+ return null;
+ } else {
+ platform.logTraceReg("SRVTYPEREPLY recieved ("
+ + message.address + ":" + message.port + ") "
+ + message.toString()
+ + " but not replyListeners present anymore");
+ }
+ }
+ return null;
+
+ // request messages
+ case SLPMessage.SRVRQST:
+ case SLPMessage.ATTRRQST:
+ case SLPMessage.SRVTYPERQST:
+ // silently drop messages where this peer is in the previous
+ // responder list
+ for (int i = 0; i < SLPCore.myIPs.length; i++) {
+ if (((RequestMessage) message).prevRespList
+ .contains(SLPCore.myIPs[i])) {
+ platform.logTraceDrop("DROPPED (" + message.address + ":"
+ + message.port + ") " + message.toString()
+ + "(udp multicast)");
+ return null;
+ }
+ }
+
+ // if we have a daemon instance, delegate the
+ // message to the daemon.
+ if (daemon != null) {
+ return daemon.handleMessage(message);
+ } else {
+ platform.logDebug("SRVTYPERQST recieved ("
+ + message.address + ":" + message.port + ") "
+ + message.toString()
+ + " but no SLPDaemon to handle the message present");
+ return null;
+ }
+ default:
+ // if we have a daemon instance, delegate all other
+ // messages to the daemon.
+ if (daemon != null) {
+ return daemon.handleMessage(message);
+ } else {
+ platform.logDebug("A message recieved ("
+ + message.address + ":" + message.port + ") "
+ + message.toString()
+ + " but no SLPDaemon to handle the message present");
+ return null;
+ }
+ }
+
+ }
+
+ /**
+ * get the next XID.
+ *
+ * @return the next XID.
+ */
+ static short nextXid() {
+ if (nextXid == 0) {
+ nextXid = 1;
+ }
+ return nextXid++;
+ }
+
+ /**
+ * find DAs for the scopes by sending a multicast service request for
+ * service <i>service:directory-agent</i>.
+ *
+ * @param scopes
+ * a <code>List</code> of scopes.
+ * @throws ServiceLocationException
+ * in case of network errors.
+ */
+ static void daLookup(final List scopes) throws ServiceLocationException {
+ int i = 0;
+ try {
+ // change by TomoTherapy Inc
+ // added loop for each IP for each interface
+ // used 1.4 SocketAddress
+ // altered by Jan to be backwards compatible with Java 2
+ for (; i < myIPs.length; i++) {
+ // create a socket bound to the next ip address
+ final InetAddress addr = InetAddress.getByName(myIPs[i]);
+ DatagramSocket socket = new DatagramSocket(0, addr);
+
+ ServiceRequest sreq = new ServiceRequest(new ServiceType(
+ SLP_DA_TYPE), scopes, null, SLPCore.DEFAULT_LOCALE);
+ sreq.xid = SLPCore.nextXid();
+ sreq.scopeList = scopes;
+ sreq.address = MCAST_ADDRESS;
+ sreq.multicast = true;
+ byte[] bytes = sreq.getBytes();
+ DatagramPacket d = new DatagramPacket(bytes, bytes.length,
+ MCAST_ADDRESS, SLP_PORT);
+ platform.logTraceMessage("SENT " + sreq + "(udp multicast)");
+ setupReceiverThread(socket, CONFIG.getWaitTime(), sreq);
+ try {
+ socket.send(d);
+ } catch (SocketException se) {
+ // blacklist address
+ final List remaining = new ArrayList(java.util.Arrays
+ .asList(myIPs));
+ final String faulty = myIPs[i];
+ remaining.remove(faulty);
+ myIPs = (String[]) remaining.toArray(new String[remaining
+ .size()]);
+ platform.logDebug("Blacklisting IP " + faulty);
+ }
+ }
+ } catch (IllegalArgumentException ise) {
+ platform.logDebug("May never happen, no filter set", ise);
+ } catch (UnknownHostException uhe) {
+ platform.logWarning("Unknown net.slp.interfaces address: " + myIPs[i], uhe);
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_ERROR, uhe.getMessage());
+ } catch (IOException e) {
+ platform.logWarning("Error connecting to: " + myIPs[i], e);
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_ERROR, e.getMessage());
+ }
+ }
+
+ /**
+ * send a unicast message over TCP.
+ *
+ * @param msg
+ * the message.
+ * @return the reply.
+ * @throws ServiceLocationException
+ * in case of network errors.
+ */
+ static ReplyMessage sendMessageTCP(final SLPMessage msg)
+ throws ServiceLocationException {
+ try {
+ if (msg.xid == 0) {
+ msg.xid = nextXid();
+ }
+ Socket socket = new Socket(msg.address, msg.port);
+ socket.setSoTimeout(CONFIG.getTCPTimeout());
+ DataOutputStream out = new DataOutputStream(socket
+ .getOutputStream());
+ DataInputStream in = new DataInputStream(socket.getInputStream());
+ msg.writeTo(out);
+ final ReplyMessage reply = (ReplyMessage) SLPMessage.parse(
+ msg.address, msg.port, in, true);
+ socket.close();
+ return reply;
+ } catch (Exception e) {
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_ERROR, e.getMessage());
+ }
+ }
+
+ /**
+ * send a unicast message over UDP.
+ *
+ * @param msg
+ * the message to be sent.
+ * @param expectReply
+ * waits for a reply if set to true.
+ * @return the reply.
+ * @throws ServiceLocationException
+ * in case of network errors etc.
+ */
+ static ReplyMessage sendMessage(final SLPMessage msg,
+ final boolean expectReply) throws ServiceLocationException {
+ if (msg.xid == 0) {
+ msg.xid = nextXid();
+ }
+ if (msg.getSize() > CONFIG.getMTU() || TCP_ONLY) {
+ return sendMessageTCP(msg);
+ }
+
+ try {
+ DatagramSocket dsocket = new DatagramSocket();
+ dsocket.setSoTimeout(CONFIG.getDatagramMaxWait());
+
+ byte[] bytes = msg.getBytes();
+
+ DatagramPacket packet = new DatagramPacket(bytes, bytes.length,
+ msg.address, msg.port);
+
+ byte[] receivedBytes = new byte[CONFIG.getMTU()];
+ DatagramPacket received = new DatagramPacket(receivedBytes,
+ receivedBytes.length);
+
+ dsocket.send(packet);
+
+ platform.logTraceMessage("SENT (" + msg.address + ":" + msg.port + ") "
+ + msg + " (via udp port " + dsocket.getLocalPort()
+ + ")");
+
+ // if no reply is expected, return
+ if (!expectReply) {
+ return null;
+ }
+
+ dsocket.receive(received);
+ dsocket.close();
+ final DataInputStream in = new DataInputStream(
+ new ByteArrayInputStream(received.getData()));
+ ReplyMessage reply = (ReplyMessage) SLPMessage.parse(received
+ .getAddress(), received.getPort(), in, false);
+ return reply;
+ } catch (SocketException se) {
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_INIT_FAILED, se
+ .getMessage());
+ } catch (ProtocolException pe) {
+ // Overflow, retry with TCP
+ return sendMessageTCP(msg);
+ } catch (IOException ioe) {
+ platform.logError("Exception during sending of " + msg);
+ platform.logError("to " + msg.address + ":" + msg.port);
+ platform.logError("Exception:", ioe);
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_ERROR, ioe.getMessage());
+ } catch (Throwable t) {
+ platform.logDebug(t.getMessage(), t);
+ throw new ServiceLocationException((short) 1, t.getMessage());
+ }
+ }
+
+ /**
+ * send a request via multicast convergence algorithm.
+ *
+ * @param msg
+ * the message.
+ * @return the collected reply messages.
+ * @throws ServiceLocationException
+ * in case of network errors.
+ */
+ static List multicastConvergence(final RequestMessage msg)
+ throws ServiceLocationException {
+ try {
+
+ long start = System.currentTimeMillis();
+
+ List replyQueue = new ArrayList();
+ List responders = new ArrayList();
+ List responses = new ArrayList();
+
+ if (msg.xid == 0) {
+ msg.xid = SLPCore.nextXid();
+ }
+
+ // register the reply queue as listener
+ Integer queryXID = new Integer(msg.xid);
+ synchronized (replyListeners) {
+ replyListeners.put(queryXID, replyQueue);
+ }
+
+ msg.port = SLPCore.SLP_PORT;
+ msg.prevRespList = new ArrayList();
+ msg.multicast = true;
+
+ // send to localhost, in case the OS does not support multicast over
+ // loopback which can fail if no SA is running locally
+ msg.address = LOCALHOST;
+ try {
+ replyQueue.add(sendMessageTCP(msg));
+ } catch (ServiceLocationException e) {
+ if(e.getErrorCode() != ServiceLocationException.NETWORK_ERROR) {
+ throw e;
+ }
+ }
+
+ msg.address = MCAST_ADDRESS;
+ ReplyMessage reply;
+
+ for (int i = 0; i < myIPs.length; i++) {
+ // create a socket bound to the next ip address
+ final InetAddress addr = InetAddress.getByName(myIPs[i]);
+ final MulticastSocket socket = new MulticastSocket();
+ socket.setInterface(addr);
+ socket.setTimeToLive(CONFIG.getMcastTTL());
+
+ setupReceiverThread(socket, CONFIG.getMcastMaxWait(), msg);
+
+ // the multicast convergence algorithm
+ long totalTimeout = System.currentTimeMillis()
+ + CONFIG.getMcastMaxWait();
+ int[] transmissionSchedule = SLPCore.CONFIG.getMcastTimeouts();
+ int retryCounter = 0;
+ long nextTimeout;
+ int failCounter = 0;
+ boolean seenNew = false;
+ boolean seenLocalResponse = false;
+
+ nextTimeout = System.currentTimeMillis()
+ + transmissionSchedule[retryCounter];
+
+ while (!Thread.currentThread().isInterrupted()
+ && totalTimeout > System.currentTimeMillis()
+ && nextTimeout > System.currentTimeMillis()
+ && retryCounter < transmissionSchedule.length
+ && failCounter < CONFIG.getConvergenceFailerCount()) {
+
+ msg.prevRespList = responders;
+ byte[] message = msg.getBytes();
+
+ // finish convergence in case of message size exeeds MTU
+ if (message.length > CONFIG.getMTU()) {
+ break;
+ }
+
+ // send the message
+ DatagramPacket p = new DatagramPacket(message,
+ message.length, InetAddress
+ .getByName(SLP_MCAST_ADDRESS), SLP_PORT);
+
+ try {
+ socket.send(p);
+ } catch (IOException ioe) {
+ break;
+ }
+
+ platform.logTraceMessage("SENT " + msg);
+
+ /**
+ * @fix: bug #1518729. Changed processing of the replyQueue.
+ * Thanks to Richard Reid for figuring out the problem
+ * with multicast replies and proposing the fix
+ */
+ try {
+ Thread.sleep(transmissionSchedule[retryCounter]);
+ } catch (InterruptedException dontcare) {
+ // Restore the interrupted status
+ Thread.currentThread().interrupt();
+ }
+
+ synchronized (replyQueue) {
+ // did something else wake us up ?
+ if (replyQueue.isEmpty()) {
+ failCounter++;
+ nextTimeout = System.currentTimeMillis()
+ + transmissionSchedule[retryCounter++];
+ continue;
+ }
+ while (!replyQueue.isEmpty()) {
+ reply = (ReplyMessage) replyQueue.remove(0);
+ // silently drop duplicate responses, process only
+ // new
+ // results
+ if (!responders.contains(reply.address
+ .getHostAddress())) {
+ if (isLocalResponder(reply.address)) {
+ if (seenLocalResponse) {
+ continue;
+ } else {
+ seenLocalResponse = true;
+ }
+ }
+ seenNew = true;
+ responders.add(reply.address.getHostAddress());
+ responses.addAll(reply.getResult());
+ }
+ }
+
+ if (!seenNew) {
+ failCounter++;
+ } else {
+ seenNew = false;
+ }
+ }
+ nextTimeout = System.currentTimeMillis()
+ + transmissionSchedule[retryCounter++];
+ }
+ }
+
+ // we are done, remove the listener queue
+ synchronized (replyListeners) {
+ replyListeners.remove(queryXID);
+ }
+
+ platform.logDebug("convergence for xid=" + msg.xid
+ + " finished after "
+ + (System.currentTimeMillis() - start)
+ + " ms, result: " + responses);
+ return responses;
+ } catch (IOException ioe) {
+ platform.logDebug(ioe.getMessage(), ioe);
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_ERROR, ioe.getMessage());
+ }
+ }
+
+ private static boolean isLocalResponder(InetAddress addr) {
+ for (int i = 0; i < SLPCore.myIPs.length; i++) {
+ if (addr.getHostAddress().equals(SLPCore.myIPs[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * setup a new receiver thread for a socket.
+ *
+ * @param socket
+ * the <code>DatagramSocket</code> for which the receiver
+ * thread is set up.
+ * @param minLifetime
+ * the minimum lifetime of the receiver thread.
+ */
+ private static void setupReceiverThread(final DatagramSocket socket,
+ final long minLifetime, final SLPMessage msg) {
+ new Thread() {
+ public void run() {
+
+ // prepare an empty datagram for receiving
+ DatagramPacket packet;
+ byte[] bytes = new byte[SLPCore.CONFIG.getMTU()];
+
+ // calculate the end of lifetime
+ long timeout = System.currentTimeMillis() + minLifetime + 1000;
+
+ // while lifetime is not expired
+ while (System.currentTimeMillis() < timeout) {
+ // set socket timeout
+ try {
+ long l = timeout - System.currentTimeMillis();
+ int soTimeout = (int) (l < 0 ? 1 : l);
+ socket.setSoTimeout(soTimeout);
+ } catch (SocketException e1) {
+ platform.logError(
+ "Exception in mcast receiver thread", e1);
+ return;
+ }
+
+ packet = new DatagramPacket(bytes, bytes.length);
+ try {
+ // try to receive a datagram packet
+ socket.receive(packet);
+ } catch (InterruptedIOException iioe) {
+ continue;
+ } catch (IOException e) {
+ platform.logDebug(e.getMessage(), e);
+ return;
+ }
+ final DataInputStream in = new DataInputStream(
+ new ByteArrayInputStream(packet.getData()));
+ try {
+ // and delegate it to the SLPCore
+ handleMessage(SLPMessage.parse(packet.getAddress(),
+ packet.getPort(), in, false));
+ } catch (ProtocolException pe) {
+ // Overflow, try to use TCP
+ try {
+ msg.address = packet.getAddress();
+ msg.port = packet.getPort();
+ msg.multicast = false;
+ handleMessage(sendMessageTCP(msg));
+ } catch (ServiceLocationException e) {
+ }
+ } catch (ServiceLocationException e) {
+ platform.logDebug(e.getMessage(), e);
+ }
+ }
+
+ // close the socket
+ socket.close();
+ }
+ }.start();
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemon.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemon.java
new file mode 100644
index 000000000..c5178d2a4
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemon.java
@@ -0,0 +1,61 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * the SLPDeaemon interface. Factored out to make the daemon part optional as
+ * part of the jSLP modularity.
+ *
+ * @author Jan S. Rellermeyer, ETH Zurich.
+ */
+public interface SLPDaemon {
+
+ /**
+ * called, when a new DA has been discovered.
+ *
+ * @param advert
+ * the <code>DAAdvertisement</code> received from the new DA.
+ */
+ void newDaDiscovered(DAAdvertisement advert);
+
+ /**
+ * handle a message dispatched by SLPCore.
+ *
+ * @param msg
+ * the message.
+ * @return the reply message or <code>null</code>.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ */
+ ReplyMessage handleMessage(final SLPMessage msg)
+ throws ServiceLocationException;
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemonImpl.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemonImpl.java
new file mode 100644
index 000000000..027dc2cfa
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPDaemonImpl.java
@@ -0,0 +1,606 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+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 ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceType;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * 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, IKS, ETH Zurich
+ * @since 0.6
+ */
+public final class SLPDaemonImpl implements SLPDaemon {
+
+ /**
+ * thread loop variable.
+ */
+ private boolean running = true;
+
+ /**
+ * Map of registered services:
+ *
+ * String scope -> List of ServiceURLs services.
+ */
+ private Map registeredServices = new HashMap();
+
+ /**
+ * Sorted set for disposal of services which lifetimes have expired:
+ *
+ * Long expirationTimestamp -> ServiceURL service.
+ */
+ private SortedMap serviceDisposalQueue = new TreeMap();
+
+ /**
+ * create a new SLPDaemon instance.
+ *
+ * @param tcpSocket
+ * the server socket.
+ * @throws Exception
+ * if something goes wrong.
+ */
+ public SLPDaemonImpl() throws Exception {
+ new TcpServerThread();
+ new ServiceDisposalThread();
+ SLPCore.platform.logDebug("jSLP daemon starting ...");
+ }
+
+ /**
+ * 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 ServiceRegistration reg) {
+
+ Service service = new Service(reg);
+
+ for (Iterator scopeIter = reg.scopeList.iterator(); scopeIter.hasNext();) {
+ String scope = (String) scopeIter.next();
+ scope = scope.toLowerCase();
+ synchronized (registeredServices) {
+ SLPUtils.addValue(registeredServices, scope, service);
+ }
+ if (reg.url.getLifetime() > ServiceURL.LIFETIME_PERMANENT) {
+ synchronized (serviceDisposalQueue) {
+ long next = System.currentTimeMillis()
+ + (reg.url.getLifetime() * 1000);
+ ArrayList keys = new ArrayList(serviceDisposalQueue
+ .keySet());
+ for (Iterator iter = keys.iterator(); iter.hasNext();) {
+ Object key = iter.next();
+ if (serviceDisposalQueue.get(key).equals(reg.url)) {
+ serviceDisposalQueue.remove(key);
+ }
+ }
+ serviceDisposalQueue.put(new Long(next), reg.url);
+ serviceDisposalQueue.notifyAll();
+ }
+ }
+
+ SLPCore.platform.logTraceReg("REGISTERED " + reg.url);
+
+ // register the service with all known DAs in the scopes
+ List daList = (List) SLPCore.dAs.get(scope);
+
+ // no DA for the scope known ?
+ // try to find one
+ if ((daList == null || daList.isEmpty()) && !SLPCore.noDiscovery) {
+ try {
+ SLPCore.daLookup(Arrays
+ .asList(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 = (List) 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()]);
+ final ServiceRegistration announcement = new ServiceRegistration(
+ reg.url, reg.serviceType, reg.scopeList, reg.attList,
+ reg.locale);
+ announcement.authBlocks = reg.authBlocks;
+ for (int i = 0; i < dAs.length; i++) {
+ try {
+ announceService(dAs[i], announcement);
+ SLPCore.platform.logTraceReg("ANNOUNCED "
+ + announcement.url + " to " + dAs[i]);
+ } catch (ServiceLocationException e) {
+ // remove DA from list
+ SLPUtils.removeValueFromAll(SLPCore.dAs, dAs[i]);
+ SLPCore.dASPIs.remove(dAs[i]);
+ SLPCore.platform.logError(e.getMessage(), e
+ .fillInStackTrace());
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * 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 ServiceDeregistration dereg)
+ throws ServiceLocationException {
+
+ final String[] scopes = (String[]) registeredServices.keySet().toArray(
+ new String[registeredServices.size()]);
+ for (int i = 0; i < scopes.length; i++) {
+ final List tmp = (List) registeredServices.get(scopes[i]);
+ final Service[] services = (Service[]) tmp.toArray(new Service[tmp
+ .size()]);
+
+ for (int j = 0; j < services.length; j++) {
+ if (dereg.url.matches(services[j].url)) {
+ List daList = (List) SLPCore.dAs.get(scopes[i].toLowerCase());
+ if (daList != null) {
+ for (Iterator daIter = daList.iterator(); daIter
+ .hasNext();) {
+ try {
+ String dA = (String) daIter.next();
+ dereg.address = InetAddress.getByName(dA);
+ dereg.port = SLPCore.SLP_RESERVED_PORT;
+ dereg.xid = SLPCore.nextXid();
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ List spiList = (List) SLPCore.dASPIs
+ .get(dA);
+ dereg.sign(spiList);
+ }
+ ReplyMessage reply = SLPCore.sendMessage(dereg,
+ true);
+ if (reply.errorCode != 0) {
+ throw new ServiceLocationException(
+ (short) reply.errorCode,
+ "Error during deregistration: "
+ + reply.errorCode);
+ }
+ } 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 ReplyMessage handleMessage(final SLPMessage msg)
+ throws ServiceLocationException {
+ if (msg == null) {
+ return null;
+ }
+
+ String via = msg.tcp ? " (tcp)" : " (udp)";
+
+ SLPCore.platform.logTraceMessage("RECEIVED (" + msg.address + ":"
+ + msg.port + ") " + msg.toString() + via);
+
+ ReplyMessage reply = null;
+
+ switch (msg.funcID) {
+ case SLPMessage.SRVRQST:
+ ServiceRequest req = (ServiceRequest) msg;
+
+ List results = new ArrayList();
+ for (Iterator scopes = req.scopeList.iterator(); scopes.hasNext();) {
+ List services = (List) registeredServices.get(scopes.next());
+ if (services == null) {
+ continue;
+ }
+
+ for (Iterator srvs = services.iterator(); srvs.hasNext();) {
+ Service service = (Service) srvs.next();
+ if (service.url.getServiceType().matches(req.serviceType)) {
+ if (req.predicate == null) {
+ results.add(service.url);
+ continue;
+ }
+ if (req.predicate.match(service.attributes)) {
+ results.add(service.url);
+ }
+ }
+ }
+ }
+
+ /*
+ * 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.multicast) {
+ return null;
+ }
+
+ reply = new ServiceReply(req, results);
+
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ ((ServiceReply) reply).sign(req.spi);
+ }
+
+ return reply;
+
+ case SLPMessage.ATTRRQST:
+ AttributeRequest attreq = (AttributeRequest) msg;
+
+ List attResult = new ArrayList();
+ for (Iterator scopes = attreq.scopeList.iterator(); scopes
+ .hasNext();) {
+ List services = (List) registeredServices.get(scopes.next());
+ if (services == null) {
+ continue;
+ }
+ // the request can either be for a ServiceURL or a ServiceType
+ Object reqService;
+ boolean fullurl = false;
+ if (attreq.url.indexOf("//") == -1) {
+ reqService = new ServiceType(attreq.url);
+ } else {
+ fullurl = true;
+ reqService = new ServiceURL(attreq.url, 0);
+ }
+
+ // if spi is sent, the request must be for a full url and
+ // the tag list has to be empty
+ if (attreq.spi.equals("")
+ || (fullurl && attreq.tagList.isEmpty())) {
+ for (Iterator srvs = services.iterator(); srvs.hasNext();) {
+ Service service = (Service) srvs.next();
+ if (service.url.matches(reqService)) {
+ attResult.addAll(SLPUtils.findMatches(
+ attreq.tagList, service.attributes));
+ }
+ }
+ }
+
+ }
+ reply = new AttributeReply(attreq, attResult);
+
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ ((AttributeReply) reply).sign(attreq.spi);
+ }
+
+ return reply;
+ case SLPMessage.SRVTYPERQST:
+ ServiceTypeRequest streq = (ServiceTypeRequest) msg;
+
+ ArrayList result = new ArrayList();
+
+ // iterate over scopes
+ for (Iterator scopeIter = streq.scopeList.iterator(); scopeIter
+ .hasNext();) {
+
+ // iterate over the registered services
+ List services = ((List) registeredServices
+ .get(scopeIter.next()));
+ if (services == null) {
+ continue;
+ }
+ for (Iterator iter = services.iterator(); iter.hasNext();) {
+ Service service = (Service) iter.next();
+ ServiceType type = service.url.getServiceType();
+ if (streq.namingAuthority.equals("*")
+ || streq.namingAuthority.equals("")
+ || type.getNamingAuthority().equals(
+ streq.namingAuthority)) {
+ if (!result.contains(type)) {
+ result.add(type);
+ }
+ }
+ }
+ }
+ reply = new ServiceTypeReply(streq, result);
+
+ return reply;
+
+ case SLPMessage.SRVREG:
+ registerService((ServiceRegistration) msg);
+ reply = new ServiceAcknowledgement(msg, 0);
+ return reply;
+
+ case SLPMessage.SRVDEREG:
+ deregisterService((ServiceDeregistration) msg);
+
+ reply = new ServiceAcknowledgement(msg, 0);
+
+ return reply;
+
+ case SLPMessage.SRVACK:
+ final ReplyMessage rep = (ReplyMessage) msg;
+ if (rep.errorCode != 0) {
+ SLPCore.platform.logWarning(msg.address
+ + " replied with error code " + rep.errorCode
+ + " (" + rep + ")");
+ }
+ return null;
+
+ default:
+ // this should never happen, message should already cause an
+ // exception during parsing
+ throw new ServiceLocationException(
+ ServiceLocationException.NOT_IMPLEMENTED,
+ "The message type " + SLPMessage.getType(msg.funcID)
+ + " 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 DAAdvertisement advert) {
+ // so find all services within the scopes of the new DA:
+ for (Iterator iter = advert.scopeList.iterator(); iter.hasNext();) {
+ String scope = (String) iter.next();
+ 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();
+ ServiceRegistration reg = new ServiceRegistration(
+ service.url, service.url.getServiceType(),
+ Arrays.asList(new Object[] { scope }), SLPUtils
+ .dictToAttrList(service.attributes),
+ SLPCore.DEFAULT_LOCALE);
+ SLPCore.platform.logDebug("Registering "
+ + service.url + " with new DA "
+ + advert.url);
+ announceService(advert.url, reg);
+ } catch (ServiceLocationException e) {
+ SLPCore.platform.logError(e.getMessage(), e
+ .fillInStackTrace());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 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 ServiceRegistration reg) throws ServiceLocationException {
+ try {
+ reg.address = InetAddress.getByName(dAAddress);
+ reg.port = SLPCore.SLP_RESERVED_PORT;
+ reg.xid = SLPCore.nextXid();
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ List spiList = (List) SLPCore.dASPIs.get(dAAddress);
+ reg.sign(spiList);
+ }
+ handleMessage(SLPCore.sendMessage(reg, true));
+ } catch (UnknownHostException e) {
+ SLPCore.platform.logError("Service announcement to "
+ + dAAddress + " failed. ", e.fillInStackTrace());
+ }
+ }
+
+ /**
+ * TCP server thread.
+ */
+ private final class TcpServerThread extends Thread {
+ private ServerSocket socket;
+
+ /**
+ * creates and starts a new TCP server thread.
+ *
+ * @throws IOException
+ * if socket creation fails.
+ */
+ private TcpServerThread() throws IOException {
+ socket = new ServerSocket(SLPCore.SLP_PORT);
+ start();
+ }
+
+ /**
+ * thread loop.
+ */
+ public void run() {
+ while (running) {
+ try {
+ Socket con = socket.accept();
+ DataInputStream in = new DataInputStream(
+ new BufferedInputStream(con.getInputStream()));
+ SLPMessage msg = SLPMessage.parse(con.getInetAddress(), con
+ .getPort(), in, true);
+
+ ReplyMessage reply = handleMessage(msg);
+ if (reply != null) {
+ SLPCore.platform.logTraceMessage("SEND REPLY ("
+ + reply.address + ":" + reply.port + ") "
+ + reply);
+
+ DataOutputStream out = new DataOutputStream(con
+ .getOutputStream());
+ reply.writeTo(out);
+ /*
+ * TODO the RFC encourages to keep the connection open
+ * to allow the other side to send multiple requests per
+ * connection. So start a server thread for every
+ * incoming connection instead of closing the connection
+ * after the first request
+ */
+ out.close();
+ }
+ in.close();
+ con.close();
+ } catch (Exception ioe) {
+ SLPCore.platform.logError(
+ "Exception in TCP receiver thread", ioe);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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);
+
+ ServiceDeregistration dereg = new ServiceDeregistration(
+ service, null, null,
+ 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.
+ }
+ }
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPMessage.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPMessage.java
new file mode 100644
index 000000000..92ded0749
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPMessage.java
@@ -0,0 +1,443 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ProtocolException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * base class for all messages that the SLP framework uses.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Z�rich
+ * @since 0.1
+ */
+public abstract class SLPMessage {
+
+ /**
+ * the <code>Locale</code> of the message.
+ */
+ Locale locale;
+
+ /**
+ * the funcID encodes the message type.
+ */
+ byte funcID;
+
+ /**
+ * the transaction ID.
+ */
+ short xid;
+
+ /**
+ * the sender or receiver address.
+ */
+ InetAddress address;
+
+ /**
+ * the sender or receiver port.
+ */
+ int port;
+
+ /**
+ * true if the message was processed or will be sent via TCP
+ */
+ boolean tcp;
+
+ /**
+ * true if the message came in or will go out by multicast.
+ */
+ boolean multicast;
+
+ /**
+ * the message funcID values according to RFC 2608, Service Request = 1.
+ */
+ public static final byte SRVRQST = 1;
+
+ /**
+ * the message funcID values according to RFC 2608, Service Reply = 2.
+ */
+ public static final byte SRVRPLY = 2;
+
+ /**
+ * the message funcID values according to RFC 2608, Service Registration =
+ * 3.
+ */
+ public static final byte SRVREG = 3;
+
+ /**
+ * the message funcID values according to RFC 2608, Service Deregistration =
+ * 4.
+ */
+ public static final byte SRVDEREG = 4;
+
+ /**
+ * the message funcID values according to RFC 2608, Service Acknowledgement =
+ * 5.
+ */
+ public static final byte SRVACK = 5;
+
+ /**
+ * the message funcID values according to RFC 2608, Attribute Request = 6.
+ */
+ public static final byte ATTRRQST = 6;
+
+ /**
+ * the message funcID values according to RFC 2608, Attribute Reply = 7.
+ */
+ public static final byte ATTRRPLY = 7;
+
+ /**
+ * the message funcID values according to RFC 2608, DA Advertisement = 8.
+ */
+ public static final byte DAADVERT = 8;
+
+ /**
+ * the message funcID values according to RFC 2608, Service Type Request =
+ * 9.
+ */
+ public static final byte SRVTYPERQST = 9;
+
+ /**
+ * the message funcID values according to RFC 2608, Service Type Reply = 10.
+ */
+ public static final byte SRVTYPERPLY = 10;
+
+ /**
+ * the message funcID values according to RFC 2608, SA Advertisement = 11.
+ */
+ public static final byte SAADVERT = 11;
+
+ /**
+ * used for reverse lookup of funcID values to have nicer debug messages.
+ */
+ private static final String[] TYPES = { "NULL", "SRVRQST", "SRVPLY",
+ "SRVREG", "SRVDEREG", "SRVACK", "ATTRRQST", "ATTRRPLY", "DAADVERT",
+ "SRVTYPERQST", "SRVTYPERPLY", "SAADVERT" };
+
+ /**
+ * get the bytes from a SLPMessage. Processes the header and then calls the
+ * getBody() method of the implementing subclass.
+ *
+ * @return an array of bytes encoding the SLPMessage.
+ * @throws IOException
+ * @throws ServiceLocationException
+ * in case of IOExceptions.
+ */
+ protected void writeHeader(final DataOutputStream out, int msgSize)
+ throws IOException {
+ byte flags = 0;
+ if (funcID == SRVREG) {
+ flags |= 0x40;
+ }
+ if (multicast) {
+ flags |= 0x20;
+ }
+ if (!tcp && msgSize > SLPCore.CONFIG.getMTU()) {
+ flags |= 0x80;
+ }
+ out.write(2);
+ out.write(funcID);
+ out.write((byte) ((msgSize) >> 16));
+ out.write((byte) (((msgSize) >> 8) & 0xFF));
+ out.write((byte) ((msgSize) & 0xFF));
+ out.write(flags);
+ out.write(0);
+ out.write(0);
+ out.write(0);
+ out.write(0);
+ out.writeShort(xid);
+ out.writeUTF(locale.getLanguage());
+ }
+
+ /**
+ *
+ */
+ abstract void writeTo(final DataOutputStream out) throws IOException;
+
+ /**
+ *
+ */
+ byte[] getBytes() throws IOException {
+ final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ final DataOutputStream out = new DataOutputStream(bytes);
+ writeTo(out);
+ return bytes.toByteArray();
+ }
+
+ /**
+ * The RFC 2608 SLP message header:
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Version | Function-ID | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length, contd.|O|F|R| reserved |Next Ext Offset|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Next Extension Offset, contd.| XID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Language Tag Length | Language Tag \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>
+ *
+ * This method parses the header and then delegates the creation of the
+ * corresponding SLPMessage to the subclass that matches the funcID.
+ *
+ * @param senderAddr
+ * the address of the message sender.
+ * @param senderPort
+ * the port of the message sender.
+ * @param data
+ * the raw bytes of the message
+ * @param len
+ * the length of the byte array.
+ * @param tcp
+ * true if the message was received via TCP, false otherwise.
+ * @return a SLPMessage of the matching subtype.
+ * @throws ServiceLocationException
+ * in case of any parsing errors.
+ */
+ static SLPMessage parse(final InetAddress senderAddr, final int senderPort,
+ final DataInputStream in, final boolean tcp)
+ throws ServiceLocationException, ProtocolException {
+ try {
+ final int version = in.readByte(); // version
+ if (version == 1) {
+ in.readByte(); // funcID
+ final int length = in.readShort();
+ byte[] drop = new byte[length - 4];
+ in.readFully(drop);
+ SLPCore.platform.logWarning("Dropped SLPv1 message from "
+ + senderAddr + ":" + senderPort);
+ }
+ final byte funcID = in.readByte(); // funcID
+ final int length = readInt(in, 3);
+
+ // slpFlags
+ final byte flags = (byte) (in.readShort() >> 8);
+
+ if (!tcp && (flags & 0x80) != 0) {
+ throw new ProtocolException();
+ }
+
+ // we don't process extensions, we simply ignore them
+ readInt(in, 3); // extOffset
+ final short xid = in.readShort(); // XID
+ final Locale locale = new Locale(in.readUTF(), ""); // Locale
+
+ final SLPMessage msg;
+
+ // decide on the type of the message
+ switch (funcID) {
+ case DAADVERT:
+ msg = new DAAdvertisement(in);
+ break;
+ case SRVRQST:
+ msg = new ServiceRequest(in);
+ break;
+ case SRVRPLY:
+ msg = new ServiceReply(in);
+ break;
+ case ATTRRQST:
+ msg = new AttributeRequest(in);
+ break;
+ case ATTRRPLY:
+ msg = new AttributeReply(in);
+ break;
+ case SRVREG:
+ msg = new ServiceRegistration(in);
+ break;
+ case SRVDEREG:
+ msg = new ServiceDeregistration(in);
+ break;
+ case SRVACK:
+ msg = new ServiceAcknowledgement(in);
+ break;
+ case SRVTYPERQST:
+ msg = new ServiceTypeRequest(in);
+ break;
+ case SRVTYPERPLY:
+ msg = new ServiceTypeReply(in);
+ break;
+ default:
+ throw new ServiceLocationException(
+ ServiceLocationException.PARSE_ERROR, "Message type "
+ + getType(funcID) + " not supported");
+ }
+
+ // set the fields
+ msg.address = senderAddr;
+ msg.port = senderPort;
+ msg.tcp = tcp;
+ msg.multicast = ((flags & 0x2000) >> 13) == 1 ? true : false;
+ msg.xid = xid;
+ msg.funcID = funcID;
+ msg.locale = locale;
+ if (msg.getSize() != length) {
+ SLPCore.platform.logError("Length of " + msg + " should be " + length + ", read "
+ + msg.getSize());
+// throw new ServiceLocationException(
+// ServiceLocationException.INTERNAL_SYSTEM_ERROR,
+// "Length of " + msg + " should be " + length + ", read "
+// + msg.getSize());
+ }
+ return msg;
+ } catch (ProtocolException pe) {
+ throw pe;
+ } catch (IOException ioe) {
+ SLPCore.platform.logError("Network Error", ioe);
+ throw new ServiceLocationException(
+ ServiceLocationException.NETWORK_ERROR, ioe.getMessage());
+ }
+ }
+
+ /**
+ *
+ * @return
+ */
+ int getHeaderSize() {
+ return 14 + locale.getLanguage().length();
+ }
+
+ /**
+ *
+ * @return
+ */
+ abstract int getSize();
+
+ /**
+ * Get a string representation of the message. Overridden by message
+ * subtypes.
+ *
+ * @return a String.
+ */
+ public String toString() {
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append(getType(funcID) + " - ");
+ buffer.append("xid=" + xid);
+ buffer.append(", locale=" + locale);
+ return buffer.toString();
+ }
+
+ /**
+ * returns the string value of the message type, catches the case where an
+ * unsupported message has been received.
+ *
+ * @param type
+ * the type.
+ * @return the type as String.
+ */
+ static String getType(final int type) {
+ if (type > -1 && type < 12) {
+ return TYPES[type];
+ }
+ return String.valueOf(type + " - UNSUPPORTED");
+ }
+
+ /**
+ * parse a numerical value that can be spanned over multiple bytes.
+ *
+ * @param input
+ * the data input stream.
+ * @param len
+ * the number of bytes to read.
+ * @return the int value.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ private static int readInt(final DataInputStream input, final int len)
+ throws ServiceLocationException {
+ try {
+ int value = 0;
+ for (int i = 0; i < len; i++) {
+ value <<= 8;
+ value += input.readByte() & 0xff;
+ }
+ return value;
+ } catch (IOException ioe) {
+ throw new ServiceLocationException(
+ ServiceLocationException.PARSE_ERROR, ioe.getMessage());
+ }
+ }
+
+ /**
+ * transforms a Java list to string list.
+ *
+ * @param list
+ * the list
+ * @param delim
+ * the delimiter
+ * @return the String list.
+ */
+ 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 list to Java List.
+ *
+ * @param str
+ * the String list
+ * @param delim
+ * the delimiter
+ * @return the List.
+ */
+ static List stringToList(final String str, final String delim) {
+ List result = new ArrayList();
+ StringTokenizer tokenizer = new StringTokenizer(str, delim);
+ while (tokenizer.hasMoreTokens()) {
+ result.add(tokenizer.nextToken());
+ }
+ return result;
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPUtils.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPUtils.java
new file mode 100644
index 000000000..9c6c63f59
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/SLPUtils.java
@@ -0,0 +1,262 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.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;
+
+/**
+ * Utility class.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+final class SLPUtils {
+
+ /**
+ * 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>.
+ */
+ static List dictToAttrList(final Dictionary attributes) {
+ List attList = new ArrayList();
+ if (attributes != null) {
+ for (Enumeration keys = attributes.keys(); keys.hasMoreElements();) {
+ Object key = keys.nextElement();
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("(");
+ buffer.append(key);
+ buffer.append("=");
+ buffer.append(attributes.get(key));
+ buffer.append(")");
+ attList.add(buffer.toString());
+ }
+ }
+ return attList;
+ }
+
+ /**
+ * 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 attrListToDict(final List attrList) {
+ Dictionary dict = new Hashtable();
+
+ 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;
+ }
+
+ /**
+ * 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();
+ }
+ 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.
+ */
+ 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.
+ */
+ static List findMatches(final List keyList, final Dictionary attributes) {
+ List results = new ArrayList();
+ Set caseInsensitiveKeyList = new HashSet();
+ List wildcards = new ArrayList();
+ 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);
+ }
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Service.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Service.java
new file mode 100644
index 000000000..840a39883
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/Service.java
@@ -0,0 +1,101 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.util.Dictionary;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * encapsulates the internal information about registered services.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zurich
+ * @since 0.6
+ */
+class Service {
+
+ /**
+ * the service URL.
+ */
+ ServiceURL url;
+
+ /**
+ * the service attributes.
+ */
+ Dictionary attributes;
+
+ /**
+ * creates a new Service instance.
+ *
+ * @param sreg
+ * the service registration message.
+ */
+ Service(final ServiceRegistration sreg) {
+
+ // TODO: support localized registrations ...
+ url = sreg.url;
+ attributes = SLPUtils.attrListToDict(sreg.attList);
+
+ }
+
+ /**
+ * @param obj
+ * Object to compare.
+ * @return <code>true</code> if the object is of type <code>Service</code>
+ * and the two services have a matching serviceURL and equal
+ * properties.
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(final Object obj) {
+ if (obj instanceof Service) {
+ Service service = (Service) obj;
+ return attributes.equals(service.attributes)
+ && url.equals(service.url);
+ }
+ return false;
+ }
+
+ /**
+ * get the hash code.
+ *
+ * @return the hash code.
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return url.hashCode();
+ }
+
+ /**
+ * get a string representation.
+ *
+ * @return a string.
+ */
+ public String toString() {
+ return url.toString();
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceAcknowledgement.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceAcknowledgement.java
new file mode 100644
index 000000000..16cb8fbcd
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceAcknowledgement.java
@@ -0,0 +1,130 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * a ServiceAcknowledgement is sent by a DA as reaction to a ServiceRegistration
+ * or ServiceDeregistration.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+class ServiceAcknowledgement extends ReplyMessage {
+ /**
+ * create a new ServiceAcknowledgement from a DataInput streaming the bytes
+ * of an ServiceAcknowledgement message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ * @throws IOException
+ */
+ ServiceAcknowledgement(final DataInput input) throws IOException {
+ errorCode = input.readShort();
+ }
+
+ /**
+ * create a new ServiceAcknowledgement.
+ *
+ * @param msg
+ * the SLPMessage to acknowledge.
+ * @param error
+ * the error code.
+ */
+ ServiceAcknowledgement(final SLPMessage msg, final int error) {
+ funcID = SRVACK;
+ xid = msg.xid;
+ locale = msg.locale;
+ address = msg.address;
+ port = msg.port;
+ errorCode = error;
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = SrvAck = 5) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Error Code |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeShort(errorCode);
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ return getHeaderSize() + 2;
+ }
+
+ /**
+ * get the result.
+ *
+ * @see ch.ethz.iks.slp.impl.ReplyMessage#getResult()
+ * @return the <code>List</code> of results.
+ */
+ List getResult() {
+ return null;
+ }
+
+ /**
+ * get a string representation of the ServiceAcknowledgement message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ return super.toString() + ", errorCode " + errorCode;
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceDeregistration.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceDeregistration.java
new file mode 100644
index 000000000..39746e2d1
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceDeregistration.java
@@ -0,0 +1,185 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * deregister a service from a DA.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+class ServiceDeregistration extends SLPMessage {
+
+ /**
+ * the service url.
+ */
+ ServiceURL url;
+
+ /**
+ * the scopes.
+ */
+ List scopeList;
+
+ /**
+ * the attributes.
+ */
+ List attList;
+
+ /**
+ * create a new ServiceDeregistration.
+ *
+ * @param serviceURL
+ * the ServiceURL.
+ * @param scopes
+ * a List of scopes.
+ * @param attributes
+ * the attributes.
+ * @param theLocale
+ * the locale.
+ */
+ ServiceDeregistration(final ServiceURL serviceURL, final List scopes,
+ final List attributes, final Locale theLocale) {
+ funcID = SRVDEREG;
+ locale = theLocale;
+ if (serviceURL == null) {
+ throw new IllegalArgumentException("serviceURL must not be null");
+ }
+ url = serviceURL;
+ scopeList = scopes;
+ if (scopeList == null) {
+ scopeList = Arrays.asList(new String[] { "default" });
+ }
+ attList = attributes;
+ if (attList == null) {
+ attList = new ArrayList();
+ }
+ }
+
+ /**
+ * parse a ServiceDeregistration from an input stream.
+ *
+ * @param input
+ * the stream.
+ * @throws ServiceLocationException
+ * if something goes wrong.
+ */
+ public ServiceDeregistration(final DataInputStream input)
+ throws ServiceLocationException, IOException {
+ scopeList = stringToList(input.readUTF(), ",");
+ url = ServiceURL.fromBytes(input);
+ attList = stringToList(input.readUTF(), ",");
+
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ if (!verify()) {
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED,
+ "Authentication failed for " + toString());
+ }
+ }
+ }
+
+ /**
+ * get the bytes from a ServiceDeregistration:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = SrvDeReg = 4) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length of &lt;scope-list&gt; | &lt;scope-list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | URL Entry \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length of &lt;tag-list&gt; | &lt;tag-list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return the bytes.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeUTF(listToString(scopeList, ","));
+ url.writeTo(out);
+ out.writeUTF(listToString(attList, ","));
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ return getHeaderSize() + 2 + listToString(scopeList, ",").length()
+ + url.getLength() + 2
+ + listToString(attList, ",").length();
+ }
+
+ /**
+ * sign this ServiceDeregistration.
+ *
+ * @param spiList
+ * a List of SPIs.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ void sign(final List spiList) throws ServiceLocationException {
+ url.sign(spiList);
+ }
+
+ /**
+ * verify the ServiceDeregistration.
+ *
+ * @return true if it could be verified.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ boolean verify() throws ServiceLocationException {
+ if (!url.verify()) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceLocationEnumerationImpl.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceLocationEnumerationImpl.java
new file mode 100644
index 000000000..bb0959356
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceLocationEnumerationImpl.java
@@ -0,0 +1,106 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import ch.ethz.iks.slp.ServiceLocationEnumeration;
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * the implementation of a ServiceLocationEnumeration.
+ *
+ * @see ch.ethz.iks.slp.ServiceLocationEnumeration
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+class ServiceLocationEnumerationImpl implements ServiceLocationEnumeration {
+ /**
+ * a list of results.
+ */
+ private List 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 resultList) {
+ list = resultList != null ? resultList : new ArrayList();
+ this.iterator = list.iterator();
+ }
+
+ /**
+ * returns the next element of the Enumeration.
+ *
+ * @return the next element.
+ * @throws ServiceLocationException
+ * if there is no more element.
+ * @see ch.ethz.iks.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;
+ }
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRegistration.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRegistration.java
new file mode 100644
index 000000000..e93c80f2e
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRegistration.java
@@ -0,0 +1,288 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceType;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * a ServiceRegistation message is sent to register a service with all DAs in
+ * the scopes.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+class ServiceRegistration extends SLPMessage {
+ /**
+ * the ServiceURL of the service.
+ */
+ ServiceURL url;
+
+ /**
+ * the ServiceType of the service.
+ */
+ ServiceType serviceType;
+
+ /**
+ * the List of scopes in which the service will be registered.
+ */
+ List scopeList;
+
+ /**
+ * the List of attributes to be registered with the service.
+ */
+ List attList;
+
+ /**
+ * an Array of AuthenticationBlocks.
+ */
+ AuthenticationBlock[] authBlocks;
+
+ /**
+ * creates a new ServiceRegistration message.
+ *
+ * @param serviceURL
+ * the ServiceURL of the service.
+ * @param type
+ * the ServiceType of the service.
+ * @param scopes
+ * a List of scopes.
+ * @param attributes
+ * a List of attributes in
+ *
+ * <pre>
+ * (key = value)
+ * </pre>
+ *
+ * format.
+ * @param theLocale
+ * the locale.
+ */
+ ServiceRegistration(final ServiceURL serviceURL, final ServiceType type,
+ final List scopes, final List attributes, final Locale theLocale) {
+ funcID = SRVREG;
+ locale = theLocale;
+ if (serviceURL == null) {
+ throw new IllegalArgumentException("serviceURL must not be null");
+ }
+ if (type == null) {
+ throw new IllegalArgumentException("serviceType must not be null");
+ }
+ url = serviceURL;
+ serviceType = type;
+ scopeList = scopes;
+ if (scopeList == null) {
+ scopeList = Arrays.asList(new String[] { "default" });
+ }
+ attList = attributes;
+ if (attList == null) {
+ attList = new ArrayList();
+ }
+ authBlocks = new AuthenticationBlock[0];
+ }
+
+ /**
+ * create a new ServiceRegistration from a DataInput streaming the bytes of
+ * an ServiceRegistration message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ * @throws IOException
+ */
+ ServiceRegistration(final DataInputStream input)
+ throws ServiceLocationException, IOException {
+ funcID = SRVREG;
+ locale = SLPCore.DEFAULT_LOCALE;
+ url = ServiceURL.fromBytes(input);
+ serviceType = new ServiceType(input.readUTF());
+ scopeList = stringToList(input.readUTF(), ",");
+ attList = stringToList(input.readUTF(), ",");
+ authBlocks = AuthenticationBlock.parse(input);
+
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ if (!verify()) {
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED,
+ "Authentication failed for " + toString());
+ }
+ }
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = SrvReg = 3) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | &lt;URL-Entry&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of service type string | &lt;service-type&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;scope-list&gt; | &lt;scope-list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of attr-list string | &lt;attr-list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |# of AttrAuths |(if present) Attribute Authentication Blocks...\
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ url.writeTo(out);
+ out.writeUTF(serviceType.toString());
+ out.writeUTF(listToString(scopeList, ","));
+ out.writeUTF(listToString(attList, ","));
+ out.write(authBlocks.length);
+ for (int i = 0; i < authBlocks.length; i++) {
+ authBlocks[i].write(out);
+ }
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ int len = getHeaderSize() + url.getLength() + 2
+ + serviceType.toString().length() + 2
+ + listToString(scopeList, ",").length() + 2
+ + listToString(attList, ",").length() + 1;
+ for (int i = 0; i < authBlocks.length; i++) {
+ len += authBlocks[i].getLength();
+ }
+ return len;
+ }
+
+ /**
+ * get a string representation of the AttributeReply message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", url: " + url);
+ buffer.append(", serviceType: " + serviceType);
+ buffer.append(", scopeList: " + scopeList);
+ buffer.append(", attList: " + attList);
+ return buffer.toString();
+ }
+
+ /**
+ * sign this ServiceRegistration.
+ *
+ * @param spiList
+ * the List of SPIs.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ void sign(final List spiList) throws ServiceLocationException {
+ url.sign(spiList);
+
+ authBlocks = new AuthenticationBlock[spiList.size()];
+ for (int k = 0; k < spiList.size(); k++) {
+ int timestamp = SLPUtils.getTimestamp();
+
+ String spi = (String) spiList.get(k);
+ byte[] data = getAuthData(spi, timestamp);
+ authBlocks[k] = new AuthenticationBlock(
+ AuthenticationBlock.BSD_DSA, spi, timestamp, data, null);
+
+ }
+ }
+
+ /**
+ * verify this ServiceRegistration.
+ *
+ * @return true if verification suceeds.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ boolean verify() throws ServiceLocationException {
+ for (int i = 0; i < authBlocks.length; i++) {
+ if (authBlocks[i].verify(getAuthData(authBlocks[i].getSPI(),
+ authBlocks[i].getTimestamp()))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * get the authentication data.
+ *
+ * @param spi
+ * the SPI.
+ * @param timestamp
+ * the timestamp.
+ * @return the auth data.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ private byte[] getAuthData(final String spi, final int timestamp)
+ throws ServiceLocationException {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+
+ dos.writeUTF(spi);
+ dos.writeUTF(listToString(attList, ","));
+ dos.writeInt(timestamp);
+ return bos.toByteArray();
+ } catch (IOException ioe) {
+ throw new ServiceLocationException(
+ ServiceLocationException.INTERNAL_SYSTEM_ERROR, ioe
+ .getMessage());
+ }
+ }
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceReply.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceReply.java
new file mode 100644
index 000000000..9026dc9c8
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceReply.java
@@ -0,0 +1,194 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceURL;
+
+/**
+ * a ServiceReply Message is sent as reaction to a ServiceRequest.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.1
+ */
+class ServiceReply extends ReplyMessage {
+ /**
+ * a List of ServiceURLs.
+ */
+ List urlList;
+
+ /**
+ * create a new ServiceReply from a list of ServiceURLs.
+ *
+ * @param req
+ * the ServiceRequest to reply to.
+ * @param urls
+ * the result URLs.
+ */
+ ServiceReply(final ServiceRequest req, final List urls) {
+ this.funcID = SRVRPLY;
+ this.xid = req.xid;
+ this.locale = req.locale;
+ this.address = req.address;
+ this.port = req.port;
+ this.errorCode = 0;
+ this.urlList = urls;
+ }
+
+ /**
+ * create a new ServiceReply from a DataInput streaming the bytes of an
+ * ServiceReply message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ * @throws IOException
+ */
+ ServiceReply(final DataInputStream input) throws ServiceLocationException,
+ IOException {
+ errorCode = input.readShort();
+ short entryCount = input.readShort();
+ urlList = new ArrayList();
+
+ for (int i = 0; i < entryCount; i++) {
+ urlList.add(ServiceURL.fromBytes(input));
+ }
+ if (SLPCore.CONFIG.getSecurityEnabled()) {
+ if (!verify())
+ throw new ServiceLocationException(
+ ServiceLocationException.AUTHENTICATION_FAILED,
+ toString());
+ }
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = SrvRply = 2) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Error Code | URL Entry count |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | &lt;URL Entry 1&gt; ... &lt;URL Entry N&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * </pre>
+ *
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeShort(errorCode);
+ out.writeShort(urlList.size());
+ for (int i = 0; i < urlList.size(); i++) {
+ ((ServiceURL) urlList.get(i)).writeTo(out);
+ }
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ int len = getHeaderSize() + 2 + 2;
+ for (int i = 0; i < urlList.size(); i++) {
+ len += ((ServiceURL) urlList.get(i)).getLength();
+ }
+ return len;
+ }
+
+ List getResult() {
+ return urlList;
+ }
+
+ /**
+ * get a string representation of the AttributeReply message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", errorCode " + errorCode);
+ buffer.append(", URLCount " + urlList.size());
+ buffer.append(", URLs " + urlList);
+ return buffer.toString();
+ }
+
+ /**
+ * sign the ServiceReply.
+ *
+ * @param spiStr
+ * the SPI String.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ void sign(final String spiStr) throws ServiceLocationException {
+ List spiList = stringToList(spiStr, ",");
+ for (Iterator urlIter = urlList.iterator(); urlIter.hasNext();) {
+ ServiceURL url = (ServiceURL) urlIter.next();
+ url.sign(spiList);
+ }
+ }
+
+ /**
+ * verify the ServiceReply.
+ *
+ * @return true if it could be verified.
+ * @throws ServiceLocationException
+ * in case of IO errors.
+ */
+ boolean verify() throws ServiceLocationException {
+ for (Iterator urlIter = urlList.iterator(); urlIter.hasNext();) {
+ ServiceURL url = (ServiceURL) urlIter.next();
+ if (!url.verify()) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRequest.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRequest.java
new file mode 100644
index 000000000..df6498b3a
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceRequest.java
@@ -0,0 +1,191 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+import ch.ethz.iks.slp.ServiceType;
+import ch.ethz.iks.slp.impl.filter.Filter;
+
+/**
+ * ServiceRequest message is used to find services in the network.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Z�rich
+ * @since 0.1
+ */
+class ServiceRequest extends RequestMessage {
+
+ /**
+ * the ServiceType.
+ */
+ ServiceType serviceType;
+
+ /**
+ * a RFC 1960 compliant filter predicate.
+ */
+ Filter predicate;
+
+ /**
+ * the spi String.
+ */
+ String spi;
+
+ /**
+ * creates a new ServiceRequest for a ServiceType.
+ *
+ * @param type
+ * the ServiceType.
+ * @param scopes
+ * a list of scopes to be included.
+ * @param filterStr
+ * a filter String, RFC 1960 compliant.
+ * @param theLocale
+ * the Locale of the message.
+ * @throws InvalidSyntaxException
+ * if the filter is not well-formed.
+ */
+ ServiceRequest(final ServiceType type, final List scopes, String filterStr,
+ final Locale theLocale) throws IllegalArgumentException {
+ funcID = SRVRQST;
+ prevRespList = new ArrayList();
+ serviceType = type;
+ predicate = filterStr == null ? null : SLPCore.platform
+ .createFilter(filterStr);
+ scopeList = scopes;
+ if (scopeList == null) {
+ scopeList = new ArrayList();
+ scopeList.add("default");
+ }
+
+ locale = theLocale == null ? SLPCore.DEFAULT_LOCALE : theLocale;
+ spi = SLPCore.CONFIG.getSecurityEnabled() ? SLPCore.CONFIG.getSPI()
+ : "";
+ }
+
+ /**
+ * create a new ServiceRequest from a DataInput streaming the bytes of a
+ * ServiceRequest message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ * @throws IOException
+ */
+ protected ServiceRequest(final DataInputStream input) throws IOException {
+ prevRespList = stringToList(input.readUTF(), ",");
+ serviceType = new ServiceType(input.readUTF());
+ scopeList = stringToList(input.readUTF(), ",");
+ try {
+ final String filterStr = input.readUTF();
+ predicate = "".equals(filterStr) ? null : SLPCore.platform
+ .createFilter(filterStr);
+ } catch (IllegalArgumentException ise) {
+ SLPCore.platform.logError("Invalid filter in incoming message "
+ + xid, ise);
+ }
+ spi = input.readUTF();
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = SrvRqst = 1) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;PRList&gt; | &lt;PRList&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;service-type&gt; | &lt;service-type&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;scope-list&gt; | &lt;scope-list&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of predicate string | Service Request &lt;predicate&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;SLP SPI&gt; string | &lt;SLP SPI&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeUTF(listToString(prevRespList, ","));
+ out.writeUTF(serviceType.toString());
+ out.writeUTF(listToString(scopeList, ","));
+ out.writeUTF(predicate == null ? "" : predicate.toString());
+ out.writeUTF(spi);
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ return getHeaderSize() + 2 + listToString(prevRespList, ",").length()
+ + 2 + serviceType.toString().length() + 2
+ + listToString(scopeList, ",").length() + 2
+ + (predicate == null ? 0 : predicate.toString().length()) + 2
+ + spi.length();
+ }
+
+ /**
+ * get a string representation of the AttributeReply message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", prevRespList: " + prevRespList);
+ buffer.append(", serviceType: " + serviceType);
+ buffer.append(", scopeList: " + scopeList);
+ buffer.append(", predicate: "
+ + (predicate == null ? "" : predicate.toString()));
+ buffer.append(", slpSpi: " + spi);
+ return buffer.toString();
+ }
+
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeReply.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeReply.java
new file mode 100644
index 000000000..c3952cf8c
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeReply.java
@@ -0,0 +1,143 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * a ServiceReply Message is sent as reaction of a ServiceRequest.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.6
+ */
+class ServiceTypeReply extends ReplyMessage {
+ /**
+ * a List of ServiceURLs.
+ */
+ List serviceTypes;
+
+ /**
+ * create a new ServiceTypeReply from a list of ServiceTypes.
+ *
+ * @param req
+ * the request to reply to.
+ * @param types
+ * the ServiceTypes.
+ */
+ ServiceTypeReply(final ServiceTypeRequest req, final List types) {
+ this.funcID = SRVTYPERPLY;
+ this.locale = req.locale;
+ this.xid = req.xid;
+ this.address = req.address;
+ this.port = req.port;
+ this.errorCode = 0;
+ this.serviceTypes = types;
+ }
+
+ /**
+ * create a new ServiceTypeReply from a DataInput streaming the bytes of an
+ * ServiceTypeReply message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ */
+ ServiceTypeReply(final DataInputStream input) throws IOException {
+ errorCode = input.readShort();
+ serviceTypes = stringToList(input.readUTF(), ",");
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = SrvTypeRply = 10) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Error Code | length of &lt;srvType-list&gt; |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | &lt;srvtype--list&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeShort(errorCode);
+ out.writeUTF(listToString(serviceTypes, ","));
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ return getHeaderSize() + 2 + 2
+ + listToString(serviceTypes, ",").length();
+ }
+
+ /**
+ * get the result of the reply message.
+ *
+ * @return the <code>List</code> of results.
+ * @see ch.ethz.iks.slp.impl.ReplyMessage#getResult()
+ */
+ List getResult() {
+ return serviceTypes;
+ }
+
+ /**
+ * get a string representation of the ServiceTypeReply message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", errorCode " + errorCode);
+ buffer.append(", ServiceTypeCount " + serviceTypes.size());
+ buffer.append(", ServiceTypes " + serviceTypes);
+ return buffer.toString();
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeRequest.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeRequest.java
new file mode 100644
index 000000000..5e2fb08c8
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/ServiceTypeRequest.java
@@ -0,0 +1,180 @@
+/* Copyright (c) 2005-2007 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Department of Computer Science, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package ch.ethz.iks.slp.impl;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import ch.ethz.iks.slp.ServiceLocationException;
+
+/**
+ * ServiceTypeRequest message is used to find existing service types.
+ *
+ * @author Jan S. Rellermeyer, IKS, ETH Zürich
+ * @since 0.6
+ */
+class ServiceTypeRequest extends RequestMessage {
+
+ /**
+ * the naming authority.
+ */
+ String namingAuthority;
+
+ private static final String NA_ALL = "*";
+ private static final String NA_DEFAULT = "";
+
+ /**
+ * creates a new ServiceTypeRequest.
+ *
+ * @param authority
+ * the naming authority.
+ * @param scopes
+ * a list of scopes to be included.
+ * @param theLocale
+ * the Locale of the message.
+ */
+ ServiceTypeRequest(final String authority, final List scopes,
+ final Locale theLocale) {
+ funcID = SRVTYPERQST;
+ prevRespList = new ArrayList();
+ namingAuthority = authority != null ? authority : NA_ALL;
+ scopeList = scopes;
+ if (scopeList == null) {
+ scopeList = new ArrayList();
+ scopeList.add("default");
+ }
+
+ locale = theLocale == null ? SLPCore.DEFAULT_LOCALE : theLocale;
+ }
+
+ /**
+ * create a new ServiceTypeRequest from a DataInput streaming the bytes of a
+ * ServiceTypeRequest message body.
+ *
+ * @param input
+ * stream of bytes forming the message body.
+ * @throws ServiceLocationException
+ * in case that the IO caused an exception.
+ */
+ ServiceTypeRequest(final DataInputStream input) throws IOException {
+ prevRespList = stringToList(input.readUTF(), ",");
+ final int authLen = input.readUnsignedShort();
+ if (authLen == 0xFFFF) {
+ namingAuthority = NA_ALL;
+ }else if(authLen == -1) {
+ namingAuthority = NA_DEFAULT;
+ } else {
+ byte[] buf = new byte[authLen];
+ input.readFully(buf);
+ namingAuthority = new String(buf);
+ }
+ scopeList = stringToList(input.readUTF(), ",");
+ }
+
+ /**
+ * get the bytes of the message body in the following RFC 2608 compliant
+ * format:
+ * <p>
+ *
+ * <pre>
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Service Location header (function = SrvTypeRqst = 9) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of PRList | &lt;PRList&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of Naming Authority | &lt;Naming Authority String&gt; \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | length of &lt;scope-list&gt; | &lt;scope-list&gt; String \
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * </pre>.
+ * </p>
+ *
+ * @return array of bytes.
+ * @throws IOException
+ * @throws ServiceLocationException
+ * @throws ServiceLocationException
+ * if an IO Exception occurs.
+ */
+ protected void writeTo(final DataOutputStream out) throws IOException {
+ super.writeHeader(out, getSize());
+ out.writeUTF(listToString(prevRespList, ","));
+ if (namingAuthority.equals(NA_ALL)) {
+ out.writeShort(0xFFFF);
+ } else if (namingAuthority.equals(NA_DEFAULT)) {
+ out.writeUTF("");
+ } else {
+ out.writeUTF(namingAuthority);
+ }
+ out.writeUTF(listToString(scopeList, ","));
+ }
+
+ /**
+ * get the length of the message.
+ *
+ * @return the length of the message.
+ * @see ch.ethz.iks.slp.impl.SLPMessage#getSize()
+ */
+ int getSize() {
+ int len = getHeaderSize() + 2
+ + listToString(prevRespList, ",").length();
+ if(namingAuthority.equals(NA_DEFAULT) || namingAuthority.equals(NA_ALL)) {
+ len += 2;
+ } else {
+ len += 2 + namingAuthority.length();
+ }
+ len += 2 + listToString(scopeList, ",").length();
+ return len;
+ }
+
+ /**
+ * get a string representation of the ServiceTypeRequest message.
+ *
+ * @return a String displaying the properties of this message instance.
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(super.toString());
+ buffer.append(", prevRespList: " + prevRespList);
+ if(namingAuthority.equals(NA_ALL)) {
+ buffer.append(", namingAuthority: ALL (NA_ALL)");
+ } else if (namingAuthority.equals(NA_DEFAULT)) {
+ buffer.append(", namingAuthority: IANA (NA_DEFAULT)");
+ } else {
+ buffer.append(", namingAuthority: " + namingAuthority);
+ }
+ buffer.append(", scopeList: " + scopeList);
+ return buffer.toString();
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/filter/Filter.java b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/filter/Filter.java
new file mode 100644
index 000000000..ab74fd5ea
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/filter/Filter.java
@@ -0,0 +1,54 @@
+/* Copyright (c) 2005,2006 Jan S. Rellermeyer
+ * Information and Communication Systems Research Group (IKS),
+ * Institute for Pervasive Computing, ETH Zurich.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ETH Zurich nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: Filter.java,v 1.1 2008/10/08 07:19:10 mkuppe Exp $
+ */
+
+package ch.ethz.iks.slp.impl.filter;
+
+import java.util.Dictionary;
+
+/**
+ * a generic LDAP filter.
+ * @author Jan S. Rellermeyer
+ *
+ */
+public interface Filter {
+ /**
+ * try to match a <code>Dictionary</code> of attributes.
+ * @param values a <code>Dictionary</code> of attributes.
+ * @return true if the filter evaluated to true;
+ */
+ boolean match(Dictionary values);
+
+ /**
+ * get a String representation of the filter.
+ * @return the String representation.
+ */
+ String toString();
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/package.html b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/package.html
new file mode 100644
index 000000000..f3b5b7000
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/impl/package.html
@@ -0,0 +1,3 @@
+<body>
+This package contains all the implementation classes of jSLP.
+</body> \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/package.html b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/package.html
new file mode 100644
index 000000000..d63f25091
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/java/ch/ethz/iks/slp/package.html
@@ -0,0 +1,3 @@
+<body>
+The user interface of the SLP framework. The ServiceLocationManager is used to retrieve a Advertiser instance for registering services or to get a Locator that allows to find services.
+</body> \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/main/resources/LICENSE.txt b/protocols/bundles/ch.ethz.iks.slp/src/main/resources/LICENSE.txt
new file mode 100644
index 000000000..553e542cb
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/main/resources/LICENSE.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2005-2007, Jan S. Rellermeyer
+ Information and Communication Research Group (IKS),
+ Swiss Federal Institute of Technology (ETH Zurich)
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ETH Zurich nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/resources/images/jSLP.jpg b/protocols/bundles/ch.ethz.iks.slp/src/site/resources/images/jSLP.jpg
new file mode 100644
index 000000000..b088769c3
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/resources/images/jSLP.jpg
Binary files differ
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/site.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/site.xml
new file mode 100644
index 000000000..5bff7ab22
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/site.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Maven">
+ <skin>
+ <groupId>ch.ethz.iks.skin</groupId>
+ <artifactId>maven_iks_skin</artifactId>
+ <version>1.0.0</version>
+ </skin>
+
+ <bannerLeft>
+ <src>images/eth_iks.jpg</src>
+ <href>http://www.iks.inf.ethz.ch</href>
+ </bannerLeft>
+ <bannerRight>
+ <src>images/jSLP.jpg</src>
+ <href>http://sourceforge.net/projects/jslp</href>
+ </bannerRight>
+
+ <body>
+ <links>
+ <item name="Sourceforge" href="http://sourceforge.net/projects/jslp" />
+ <item name="Concierge OSGi" href="http://concierge.sourceforge.net" />
+ <item name="R-OSGi" href="http://r-osgi.sourceforge.net" />
+ <item name="flowSGi" href="http://flowsgi.inf.ethz.ch" />
+ </links>
+
+ <menu name="Overview">
+ <item name="Home" href="/index.html" />
+ <item name="jSLP" collapse="false" href="/jSLP/index.html">
+ <item name="Getting Started" href="/jSLP/userguide.html" />
+ <item name="jSLP Modularity" href="/jSLP/modularity.html"/>
+ <item name="Download" href="http://sourceforge.net/project/showfiles.php?group_id=151721" />
+ </item>
+ <item name="jSLP-OSGi" collapse="false" href="/jSLP-OSGi/index.html">
+ <item name="Getting Started" href="/jSLP-OSGi/userguide.html" />
+ <item name="Download" href="http://sourceforge.net/project/showfiles.php?group_id=151721" />
+ </item>
+ <item name="JavaDocs" href="http://jslp.sourceforge.net/apidocs/index.html" />
+ <item name="jSLP Properties" href="/properties.html"/>
+ <item name="Enabling SLP Security" href="/security.html" />
+ <item name="Project License" href="/license.html" />
+ <item name="Projects Using jSLP" href="/using.html" />
+ </menu>
+
+ <menu name="Project">
+ <item name="Source Repository" href="/source-repository.html" />
+ <item name="Report a Bug" href="http://sourceforge.net/tracker/?group_id=151721&amp;atid=781930"/>
+ <item name="Request a Feature" href="http://sourceforge.net/tracker/?group_id=151721&amp;atid=781933" />
+ <item name="Forum" href="http://sourceforge.net/forum/?group_id=151721" />
+ <item name="Project Team" href="/team-list.html" />
+ </menu>
+
+ </body>
+</project>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/index.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/index.xml
new file mode 100644
index 000000000..1263c2340
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/index.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP - Java SLP (Service Location Protocol) Implementation. Java SLP</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+ <meta name="keyword" content="Java, SLP, slp, Service Location Protocol, jSLP, jslp, OpenSLP, OSGi, Goals, Overview"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative)."/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+<body>
+
+
+ <section name="Overview">
+ <p>
+ <b>Current Release: 1.0.0.RC5</b><br/>
+ <b>Current OSGi Release: 1.0.0.RC5</b><br/>
+ </p>
+ <p>
+ <i>jSLP</i> is a pure Java implementation of SLP, the Service Location Protocol, as specified in <a href="http://www.faqs.org/rfcs/rfc2608.html">RFC 2608</a>. The API is derived from <a href="http://www.faqs.org/rfcs/rfc2614.html">RFC 2614</a> with some <a href="jSLP/index.html">modifications</a>. The implementation runs on every Java2 VM, for instance, also on a J2ME CDC Profile. The footprint of less than 80 kBytes for the full version with SA, UA, and Daemon makes it very feasible for small and embedded devices.
+ </p>
+ <p>
+ So far, the only two existing possibilities to use SLP with Java were either to use the <a href="http://openslp.sourceforge.net">OpenSLP</a> Java API or make use of the SLP implementation that ships with Solaris. The former requires an slpd daemon to run on the machine, this is not always possible (e.g. on mobile or embedded devices). The latter has the same limitations and runs only on Solaris hosts. <a href="http://jcp.org/en/jsr/detail?id=140">JSP 140</a> was launched to develop a more usable API for Java but this request has been withdrawn.
+ </p>
+ <p>
+ <i>jSLP</i> fills this gap and provides both SLP User Agent (UA) and SLP Service Agent (SA) functionality. It supports peer to peer service discovery via multicast convergence and unicast client server discovery with a Directory Agent (DA) like <a href="http://www.openslp.org">OpenSLP</a> in the network. Since it is pure Java without any native code parts or system daemons, <i>jSLP</i> can run on mobile devices and might help to build service oriented middleware systems that do not rely on heavyweight XML-based discovery protocols.
+ </p>
+ <p>
+ There are two versions of <i>jSLP</i> available. The standalone distribution is designed to run with arbitrary Java programs. The OSGi version enables the <a href="http://www.osgi.org">OSGi framework</a> to locate services via SLP. The recent <a href="http://r-osgi.sourceforge.net">R-OSGi</a> project integrates <i>jSLP</i> to remotely access OSGi services from distributed OSGi platforms.
+ </p>
+ <p>
+ Java Management Extensions (JMX, <a href="http://www.jcp.org/en/jsr/detail?id=160">JSP 160</a>) defines the integration of JMX and SLP, the examples run with jSLP if the divergences between RFC 2614 and jSLP are regarded.
+ </p>
+ <br/>
+ <p>
+ <i>jSLP</i> was developed by Jan S. Rellermeyer for <a href="http://r-osgi.sourceforge.net">R-OSGi</a> (Remote OSGi), part of the <a href="http://flowsgi.inf.ethz.ch">flowSGi</a> project, which is an ongoing research project at <a href="http://pc.inf.ethz.ch">Institute for Pervasive Computing</a>, <a href="http://www.ethz.ch">ETH Zurich</a>.
+ </p>
+ </section>
+
+</body>
+</document>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/index.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/index.xml
new file mode 100644
index 000000000..603a8809c
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/index.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP-OSGi - Java SLP (Service Location Protocol) Implementation for OSGi. jSLP-OSGi Overview</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+
+ <meta name="keyword" content="Java, SLP, jSLP, Service Location Protocol, OSGi"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative)."/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+ <section name="jSLP-OSGi">
+ <p>
+ jSLP OSGi is designed to enable SLP service discovery on OSGi platforms. Bundles can get <code>Locator</code> and
+ <code>Advertiser</code> instances to find other services in the Network. The OSGi version has a smaller footprint
+ than the jSLP standalone version because it uses the framework <code>Filter</code> and instead of using commons-logging,
+ it makes use of the OSGi <code>org.osgi.service.log</code> logger. The OSGi version of jSLP registers the
+ <code>ServiceLocationManager</code> as a ServiceFactory for <code>ch.ethz.iks.slp.Advertiser</code> and
+ <code>ch.ethz.iks.slp.Locator</code> services. <br/>
+ Since OSGi does not provide any general way to parametrize ServiceFactories, both <code>Locator</code> and
+ <code>Advertiser</code> have an additional <code>void setLocale(Locale locale)</code> method to set the locale
+ after having retrieved the service object. <br/>
+ For details, see the <a href="userguide.html">Getting Started</a>.
+ </p>
+ </section>
+</body>
+</document>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/userguide.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/userguide.xml
new file mode 100644
index 000000000..6795801fc
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP-OSGi/userguide.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP-OSGi - Java SLP (Service Location Protocol) Implementation for OSGi. Getting started with jSLP-OSGi</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+
+ <meta name="keyword" content="Java, SLP, jSLP, Service Location Protocol, OSGi, Userguide"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative)."/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+
+ <section name="Getting started with jSLP-OSGi">
+ <p>
+ jSLP OSGi registers <code>ch.ethz.iks.slp.ServiceLocationManager</code> as <code>ServiceFactory</code>.
+ The registered services are <code>ch.ethz.iks.slp.Advertiser</code> and <code>ch.ethz.iks.slp.Locator</code>
+ and every bundle requesting one of the services will get their own instance. Since requests for
+ <code>ServiceReferences</code> cannot pass parameters to the <code>ServiceFactory</code>,
+ the <code>Advertiser</code> and <code>Locator</code> instances will be created with the empty default
+ <code>Locale</code> and both classes have a setter method <code>.setLocale(Locale locale)</code> to change
+ the locale at runtime (this differs from the jSLP standalone version).
+ </p>
+ <p>
+ The following example shows how to get <code>Advertiser</code> and <code>Locator</code> instances and use them:
+<source>
+public class SLPTestBundle implements BundleActivator {
+
+ public void start(BundleContext context) throws Exception {
+
+ ServiceReference advRef = context.getServiceReference("ch.ethz.iks.slp.Advertiser");
+ ServiceReference locRef = context.getServiceReference("ch.ethz.iks.slp.Locator");
+
+ if (advRef != null) {
+ System.out.println("Got reference for Advertiser");
+ Advertiser advertiser = (Advertiser) context.getService(advRef);
+
+ advertiser.register(new ServiceURL("service:osgi:test://192.168.24.118", 20), null);
+ }
+
+ if (locRef != null) {
+ System.out.println("Got reference for Locator");
+ Locator locator = (Locator) context.getService(locRef);
+
+ ServiceLocationEnumeration slenum = locator.findServices(new ServiceType("service:osgi"), null, null);
+ System.out.println("RESULT:");
+ while (slenum.hasMoreElements()) {
+ System.out.println(slenum.nextElement());
+ }
+ }
+ }
+
+
+ public void stop(BundleContext context) throws Exception {
+
+ }
+
+}
+</source>
+ </p>
+ <p>
+ jSLP OSGi does not require <code>org.osgi.service.log</code> to run but if a bundle is present that provides this service,
+ jSLP OSGi makes use of it. If the service is not present, trace options passed by properties have no effect. jSLP-OSGi has
+ been successfully tested with <a href="http://flowsgi.inf.ethz.ch/concierge.html">Concierge OSGi</a>,
+ <a href="http://www.knopflerfish.org">Knopflerfish</a>, <a href="http://oscar.objectweb.org">Oscar</a> and
+ <a href="http://www.eclipse.org/equinox/">Eclipse Equinox</a>.
+ </p>
+ <p>
+ For developing Eclipse Plugins, it is recommended to checkout the jSLP-OSGi project from the
+ <a href="source-repository.html">subversion repository</a>. This project is already an Eclipse Plugin and
+ can be used as dependency for your own project. Unfortunately, Eclipse does not show the exception that is thrown
+ when jSLP runs on a linux box as non-root user and it tries to open port 427. Instead, it will print a plain
+ <code>ExceptionInInitializer</code>. The result is a general unavailability of the requested Locator or Advertiser instance.
+ </p>
+ <p>
+ Furthermore, Eclipse uses a resolving and starting strategy which is different from traditional OSGi. jSLP has
+ <code>Eclipse-LazyStart</code> set so it is started whenever a class from the bundle is accessed. This somewhat collides
+ with the OSGi service model where bundles are completely decoupled. So in the above example, jSLP as a Plugin is never
+ started and no Advertiser or Locator instance can be retrieved. To prevent this, simple use
+<source>
+ ServiceReference advRef = context.getServiceReference(Advertiser.class.getName());
+</source>
+ The call to the static field <code>class</code> will force the resolving of <code>ch.ethz.slp.Advertiser</code>,
+ the Plugin will be started and thus the ServiceFactory registered with the OSGi registry. (The same indeed works
+ for the Locator)
+ </p>
+ <p>
+ For debugging, jSLP-OSGi features the <code>ch.ethz.iks.slp.debug</code> property. If set to <code>true</code>
+ and a LogService is present, jSLP-OSGi prints additional information about internal state changes which makes it
+ easier to debug applications.
+ </p>
+ </section>
+
+</body>
+</document>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/index.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/index.xml
new file mode 100644
index 000000000..05d4dcac8
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/index.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP - Java SLP (Service Location Protocol) Implementation. jSLP Overview</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+
+ <meta name="keyword" content="Java, SLP, slp, Service Location Protocol, jSLP, jslp, RFC 2608, RFC 2614"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative). It runs on small and embedded devices and can run under J2SE as well as J2ME CDC and Personal Profile."/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+
+ <section name="jSLP">
+ <p>
+ jSLP is the standalone version. It requires <a href="http://jakarta.apache.org/commons/logging/">commons-logging</a> to be in classpath. For example code and setup instructions, see <a href="userguide.html">Getting Started</a>.
+ </p>
+ </section>
+ <section name="jSLP Features">
+ <p>
+ jSLP implements all required features of RFC 2608 for SA and UA, that includes accepting incoming message both via TCP and UDP. Implemented optional features are Attribute Requests, Authentication Blocks and User Defined Scopes.
+ </p>
+ </section>
+
+ <section name="Divergence from RFC 2608">
+ <p>
+ The only divergence from RFC 2608 is the use of LDAP filters. RFC 2608 proposes RFC 2254 LDAP v3 filters whereas jSLP uses RFC 1960 LDAP filters. The difference between the two standards is the support for Extensible Matches that RFC 1960 does not provide. However, Extensible Matching is closely related to LDAP trees and does not really apply to systems like jSLP.
+ </p>
+ <p>
+ With version 0.7.x, jSLP allows an additional feature that is not directly intended by RFC 2608: The definition of a protocol for service access. RFC 2608 only allows to specify the transport. However, in some cases, it is required to also specify a protocol to allow for services that can be accessed by different protocols. jSLP allows service urls like:
+ <code>
+ service:test:myservice://http://myhost:8080
+ </code>
+ where http is the protocol to access the service. Since the OpenSLP DA does not check the URL part any further, this does not preserve full interoperability with existing SLP solutions.
+ </p>
+ </section>
+
+ <section name="Divergence from RFC 2614">
+ <p>
+ The major divergence from RFC 2614 is the use of Java Collection Framework by jSLP while RFC 2614 uses <code>Vector</code> elements for passing scope or tag lists.
+ <br/> Second, RFC 2614 proposes a class named <code>ServiceLocationAttribute</code> to store attributes and passes attributes as String lists of key/value pairs. jSLP has been designed to be close to OSGi in order to provide best integration, so it uses <code>Dictionary</code> instances for storing and passing attributes. There is a little inconsistency in using <code>Dictionary</code> instead of <code>Map</code> but OSGi uses this format.
+ <br/>jSLP adds support for User Defined Scopes to the API, additionally to the standard method for registering a service, it provides a method where a List of scopes can be passed to select the service scopes at runtime.
+ <br/>Currently, incremental service registration is not yet implemented.
+ </p>
+
+ </section>
+
+ <section name="Java VM requirements">
+ jSLP has been designed to run on servers or desktop machines as well as on small and embedded devices. It has a very small memory and storage
+ footprint and runs on Java 1.2 compatible virtual machine or above. <br/>
+ Successful tests have been performed on Sun J2SE 1.4.2 and J2SE 1.5, J2SE 1.6, Sun J2ME Personal Profile cvm on Sharp Zaurus, SableVM on iPAQ Linux Familiar, JamVM on iPAQ Linux Familiar, IBM J9 on iPAQ Windows PocketPC, IBM J9 on a Nokia 9300i smartphone, JamVM on a LinkSys NSLU2 (Slug) and an Intel iMote2 sensor network node with a blackdown VM.
+ </section>
+
+</body>
+</document>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/modularity.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/modularity.xml
new file mode 100644
index 000000000..5a09fd33d
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/modularity.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP - Java SLP (Service Location Protocol) Implementation. Modularity in jSLP > 0.6</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+
+ <meta name="keyword" content="Java, SLP, slp, Service Location Protocol, jSLP, jslp, Userguide, User Guide, OpenSLP, Modularity, SA, UA"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative). Modularity in jSLP 0.6:"/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+
+ <section name="jSLP Modularity">
+ <p>
+ jSLP can be used to build custom configurations for SLP peers. It is possible to use UA or SA functionalities only and leave out some classes to reduce the file footprint.
+ </p>
+ </section>
+
+ <section name="SA only configurations">
+ <p>
+ If the configuration has to support SA functionalities only, the <code>ch.ethz.iks.slp.impl.LocatorImpl</code> class is not required. Since the core has only dynamic dependencies to this class,
+ it can be omitted without any further modifications. Calls of <code>ch.ethz.iks.slp.ServiceLocationManager.getLocator</code> will throw a ServiceLocationException of type
+ <code>ServiceLocationException.NOT_IMPLEMENTED</code>. Depending on the setup, the <code>ch.ethz.iks.slp.impl.SLPDaemonImpl</code> class is also not required, see section below.
+ </p>
+ </section>
+
+ <section name="UA only configurations">
+ <p>
+ Configurations that only serve as a SLP client can omit the <code>ch.ethz.iks.slp.impl.AdvertiserImpl</code> class and the <code>ch.ethz.iks.slp.impl.SLPDaemon</code> class without further
+ implications. Calls of <code>ch.ethz.iks.slp.ServiceLocationManager.getAdvertiser</code> will throw a ServiceLocationException of type
+ <code>ServiceLocationException.NOT_IMPLEMENTED</code>.
+ </p>
+ </section>
+
+ <section name="Configurations without the SLPDaemon">
+ <p>
+ jSLP is able to run on different VMs on the same machine. Every separated instance of jSLP checks, if a SLP daemon is running on port 427 on the machine. If this is
+ the case, no new instance of SLPDaemon is created. Therefore, if it can be assured that another process has already started a deamon, the class <code>ch.ethz.iks.slp.impl.SLPDaemonImpl</code>
+ does not have to be provided by subsequent instances on different VMs. The same applies for the situation where a OpenSLP slpd is running on the machine. <br/>
+ The daemon is required for SA functionalities only. It contains a service registry for the case where no DA of the designated scope is available within the network and
+ answers requests that arrive by multicast. It should thus be assured that the instance running the daemon does not terminate prior to other existing SA-enabled instances running on different VMs.
+ </p>
+ </section>
+
+</body>
+</document>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/userguide.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/userguide.xml
new file mode 100644
index 000000000..1bfe0988b
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/jSLP/userguide.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP - Java SLP (Service Location Protocol) Implementation. Getting started with jSLP</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+
+ <meta name="keyword" content="Java, SLP, slp, Service Location Protocol, jSLP, jslp, Userguide, User Guide, OpenSLP, security, PEM, DER, private key, public key"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative). Getting started with jSLP:"/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+
+ <section name="Getting started with jSLP">
+ <p>
+ First, download the current 1.0_RC1 release of jSLP and a current release of commons-logging.
+ Similar to RFC 2614, jSLP separates the UA and SA functionalities into two different classes,
+ location of services is provided by <code>ch.ethz.iks.slp.Locator</code>, registration of services
+ by <code>ch.ethz.iks.slp.Advertiser</code>. The starting point of interacting with jSLP is to get
+ an instance of one of the classes (or both) via the static methods of
+ <code>ch.ethz.iks.slp.ServiceLocationManager</code>.
+ </p>
+ </section>
+
+
+ <section name="Understanding, what's going on">
+ <p>
+ jSLP can either operate stand-alone (in peer-to-peer mode), or with a dedicated SLP Directory
+ Agent in the network. In the first case, jSLP uses multicast convergence to query the local
+ subnet for peers that offer requested services. In the latter case, the central Directory Agent
+ maintains all registered services and answers requests.
+ </p>
+ <p>
+ The SLP protocol is self-adaptive in the sense that whenever a Directory Agent is present
+ (and matches the scope), it is exclusively used. Otherwise, multicast convergence is used.
+ jSLP fully complies to this behavior.
+ </p>
+ <p>
+ By default, the SLP protocol uses the standardized port 427 for communication. This, however,
+ requires to run jSLP as <i>root</i> on Linux/Unix platforms. In some situations, where a closed
+ world can be assumed and interoperability with other SLP peers is not relevant, it might be more
+ convenient to run jSLP on a port > 1024 to allow it to run from an ordinary user account. This is
+ possible from jSLP release 0.7.x by setting <i>net.slp.port</i> to a target port.
+ </p>
+ <p>
+ jSLP is designed to be accessible from multiple instances of Java running on the same machine.
+ Be aware, that always the first instance started holds the Java part that corresponds to the Deaemon.
+ If this instance is shut down, also the registrations are lost. To prevent this, use a DA in the
+ network of make sure that this first instance runs continously. (In general, this is the behavior of slpd).
+ </p>
+ </section>
+ <section name="Register a service">
+ <p>
+ The following example shows how to register a service with jSLP:
+
+<source>
+// get Advertiser instance
+Advertiser advertiser = ServiceLocationManager.getAdvertiser(new Locale("en"));
+
+// the service has lifetime 60, that means it will only persist for one minute
+ServiceURL myService = new ServiceURL("service:test:myService://my.host.ch", 60);
+
+// some attributes for the service
+Hashtable attributes = new Hashtable();
+attributes.put("persistent", Boolean.TRUE);
+attributes.put("cool", "yes");
+attributes.put("max-connections", new Integer(5));
+
+advertiser.register(myService, attributes);
+</source>
+
+ Please note that a service is always registered with a lifetime, that means the service registration will
+ expire after [lifetime] seconds unless set to ServiceURL.LIFETIME_PERMANENT. In this case, the service
+ will never expire but the registering applications should take care about unregistering the service
+ when it terminates to avoid stale service registrations.
+ </p>
+ </section>
+
+ <section name="Locate a service">
+ <p>
+ The next example shows how to locate a service in the network:
+
+<source>
+// get Locator instance
+Locator locator = ServiceLocationManager.getLocator(new Locale("en"));
+
+// find all services of type "test" that have attribute "cool=yes"
+ServiceLocationEnumeration sle = locator.findServices(new ServiceType("service:test")
+ , null, "(cool=yes)");
+
+// iterate over the results
+while (sle.hasMoreElements()) {
+ ServiceURL foundService = (ServiceURL) sle.nextElement();
+ System.out.println(foundService);
+}
+</source>
+
+ Services can also be found by ServiceURL. The attribute filter may be everything compliant to
+ <a href="http://www.faqs.org/rfcs/rfc1960.html">RFC 1960</a> (String Representation of LDAP Filters),
+ so a valid filter could also be:
+ <code>(&amp;(resolution>=600)(|(format=a4)(format=usLetter)))</code>.
+ jSLP supports service, attribute requests and service type requests (with revision 0.6).
+ </p>
+ </section>
+
+ <section name="See, what's going on">
+ <p>
+ The following lines added to your VM's command line can help to see and understand what is going on on the
+ level of messages and registrations:
+<code>
+ -Dorg.apache.commons.logging.log=org.apache.commons.logging.impl.SimpleLog
+ -Dorg.apache.commons.logging.simplelog.defaultlog=trace
+ -Dnet.slp.traceMsg=true
+ -Dnet.slp.traceReg=true
+</code>
+ </p>
+ </section>
+
+ <section name="Troubleshooting">
+ <p>
+ There are two common problems that might prevent jSLP from working correctly:
+ <ul>
+ <li><b>jSLP cannot open the port 427</b>: Either run jSLP as root, or change the port, if
+ this is acceptable for your setup.</li>
+ <li><b>jSLP cannot find your OpenSLP DA</b>: First, ensure that your OpenSLP DA is in the
+ same subnet as your jSLP client is and that it is actually running in DA mode. Check
+ <code>/var/log/slpd.log</code> for the agent URL, it should read something like
+ <code>service:directory-agent://URL</code>. If your OpenSLP DA is running as an SA although
+ you configured it to be a DA, it is a hostname lookup problem. OpenSLP will refuse to run
+ as a DA if it cannot find out your host name. Make sure that your /etc/hosts contains an
+ entry that maps your hostname to the actual IP address and that your machine has a hostname
+ set. As long as the result of OpenSLP's effort to find out the machines canonical host name
+ is 127.X, it will silently switch to SA mode (one could argue that this is not a nice behavior
+ but it is implemented this way).</li>
+ <li><b>jSLP cannot detect the local host address on Linux</b>: First, try to set your
+ <code>/etc/hosts</code>, etc. If you cannot do this, you can manually influence the interfaces
+ by setting <i>net.slp.interfaces</i>. The first entry will determine on which network interface
+ jSLP sends outgoing messages. See the properties for details.</li>
+ </ul>
+ </p>
+ </section>
+</body>
+</document>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/properties.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/properties.xml
new file mode 100644
index 000000000..b8ea663be
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/properties.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP - Java SLP (Service Location Protocol) Implementation. jSLP Properties</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+ <meta name="keyword" content="Java, SLP, slp, Service Location Protocol, jSLP, jslp, Properties, OpenSLP, security, PEM, DER, private key, public key"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative)."/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+ <section name="jSLP properties">
+ <p>
+ Currently, jSLP supports the following properties:
+ <table>
+ <tr>
+ <th>Attribute</th>
+ <th>Default</th>
+ <th>Comment</th>
+ </tr>
+ <tr>
+ <td><code>net.slp.interfaces</code></td>
+ <td><i>none</i></td>
+ <td>Comma separated list of IP addresses of the interfaces on which jSLP should listen for SLP messages. Currently, jSLP only listens to the first address. You might have to set this property on multi-homed machines and on linux if your JVM thinks your machine's IP is 127.0.0.1</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.port</code></td>
+ <td><i>none</i></td>
+ <td>number that denotes the (non-standard) port where jSLP is going to operate on. Note that this prevents interoperability with other SLP entities running on the standard port, if multicast convergence is used.</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.useScopes</code></td>
+ <td>default</td>
+ <td>predefined scopes for the SA</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.DAAddresses</code></td>
+ <td><i>none</i></td>
+ <td>predefined DA addresses</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.noDADiscovery</code></td>
+ <td><i>false</i></td>
+ <td>perform no active or passive DA discovery. Only valid if <i>net.slp.DAAddresses</i> are defined.</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.waitTime</code></td>
+ <td>1000</td>
+ <td>wait time for initial DA discovery etc.</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.traceDATraffic</code></td>
+ <td>false</td>
+ <td>trace traffic to DA</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.traceMsg</code></td>
+ <td>false</td>
+ <td>trace messages</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.traceDrop</code></td>
+ <td>false</td>
+ <td>trace dropped messages</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.traceReg</code></td>
+ <td>false</td>
+ <td>trace registrations / deregistrations</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.multicastTTL</code></td>
+ <td>255</td>
+ <td>TTL for multicast messages. <i>Note: decreasing this value will lead to localized query results and peers at different locations in the network might get different results</i></td>
+ </tr>
+ <tr>
+ <td><code>net.slp.multicastMaximumWait</code></td>
+ <td>15000</td>
+ <td>total timeout for multicast convergence in mSec.</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.multicastTimeouts</code></td>
+ <td>500,750,1000,1500,2000,3000</td>
+ <td>timeouts for the rounds during multicast convergence. <i>Note that the number of timeouts affects the maximum total number of rounds for multicast convergence.</i></td>
+ </tr>
+ <tr>
+ <td><code>net.slp.datagramMaximumWait</code></td>
+ <td>5000</td>
+ <td>Number of mSecs until jSLP stops waiting for a reply to a UDP request message and timeframe for retransmissions of failed UDP messages.</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.datagramTimeouts</code></td>
+ <td>3000,3000,3000,3000,3000</td>
+ <td>timeouts for the retransmissions of failed UDP messages. <i>Note that the number of timeouts does NOT affect the maximum number of retransmissions. This number is limited by <code>net.slp.datagramMaximumWait</code></i>.</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.MTU</code></td>
+ <td>1400</td>
+ <td>maximum size of a UDP datagram in Bytes</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.securityEnabled</code></td>
+ <td>false</td>
+ <td>enable security</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.spi</code></td>
+ <td><i>none</i></td>
+ <td>a comma separated list of SPIs to use if security is enabled.</td>
+ </tr>
+ <tr>
+ <td><code>net.slp.privateKey.<i>SPI</i></code></td>
+ <td><i>none</i></td>
+ <td>the location of the private key in DER format for SPI <i>SPI</i></td>
+ </tr>
+ <tr>
+ <td><code>net.slp.publicKey.<i>SPI</i></code></td>
+ <td><i>none</i></td>
+ <td>the location of the public key in DER format for SPI <i>SPI</i></td>
+ </tr>
+ </table>
+ </p>
+ <p>
+ jSLP expects the properties to be either passed by system environment (that means as -D<i>property</i>=<i>value</i> parameter for the VM) or in a file called jslp.properties. Please note that for tracing messages etc., you also have to configure your logger to output trace messages.
+ </p>
+ </section>
+</body>
+</document> \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/security.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/security.xml
new file mode 100644
index 000000000..c516141c6
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/security.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP - Java SLP (Service Location Protocol) Implementation. Enabling SLP Security</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+
+ <meta name="keyword" content="Java, SLP, slp, Service Location Protocol, jSLP, jslp, OpenSLP, security, PEM, DER, private key, public key"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative). The following example shows how to enable security and generate public and private key that can also be used for OpenSLP and for interaction with a Directory Agent (DA)."/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+ <section name="Enabling security">
+ <p>
+ jSLP uses the standard SLP security mechanism with SPIs and Authentication Blocks. To enable security, one has to create a public / private key pair to use with the jSLP peers. This can be done by using <a href="http://www.openssl.org">OpenSSL</a>. Generally, jSLP supports BSD 0x0002, DSA keys. Java requires the keys to be in <i>DER</i> format. In the Unix world, the <i>PEM</i> format is more common but every <i>PEM</i> encoded key can be transformed into a <i>DER</i> key by performing the last step of the example below. This is particularly required if there are already security enabled OpenSLP DAs in the network and jSLP peers need to access their services.
+<br/><br/>
+The following example creates a public / private key pair that can be used with jSLP and OpenSLP Directory Agents:
+<br/><br/>
+First, create a new private key in PEM format and remove the passphrase:
+<source>
+openssl dsaparam -out dsap.pem 1024
+openssl gendsa -des -out private_key_with_pw.pem dsap.pem
+openssl dsa -in private_key:with_pw.pem -out private_key.pem
+</source>
+<br/>
+Then, create a public key from the private key:
+<source>
+openssl dsa -in private_key.pem -pubout -out public_key.pem
+</source>
+<br/>
+These keys can be used with OpenSLP, for Java, we need to convert them to DER format:
+<source>
+openssl dsa -in public_key.pem -inform PEM -pubin -outform DER -out public_key.der
+openssl pkcs8 -nocrypt -in private_key.pem -inform PEM -topk8 -outform DER -out private_key.der
+</source>
+ <br/>
+ The DER format keys can be used with jSLP. One has to define an SPI which is in an identifier for a public/private key pair. <br/>
+ We set <code>net.slp.spi</code> to e.g., <i>mySlp</i> and register the keys by setting <code>net.slp.privateKey.mySlp</code> and <code>net.slp.publicKey.mySlp</code> to the files where your DER keys are stored. Don't forget to set <code>net.slp.securityEnabled</code> to true and the jSLP peer will use security. If OpenSLP DAs are used, register the PEM format keys with the DA or the jSLP peer will not be able to communicate with the DA.
+ </p>
+ </section>
+</body>
+</document> \ No newline at end of file
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/using.xml b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/using.xml
new file mode 100644
index 000000000..1f2d66446
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/site/xdoc/using.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+ <properties>
+ <title>jSLP - Java SLP (Service Location Protocol) Implementation. Projects Using jSLP</title>
+ <author email="rellermeyer_AT_inf.ethz.ch">Jan S. Rellermeyer</author>
+ </properties>
+
+ <meta name="keyword" content="Java, SLP, slp, Service Location Protocol, jSLP, jslp, OSGi, projects using, flowSGi, collaborative, middleware"/>
+ <meta name="description" content="jSLP is a pure Java implementation of RFC 2608 (SLP, Service Location Protocol, Version 2) with a RFC 2614 style API. It can be both SLP UserAgent (UA) and ServiceAgent (SA). jSLP-OSGi integrates SLP with OSGi (Open Service Gateway Initiative). The following projects are using jSLP:"/>
+ <meta http-equiv="cache-control" content="no-cache"/>
+ <meta http-equiv="pragma" content="no-cache"/>
+ <meta http-equiv="robots" content="index, follow"/>
+
+<body>
+ <section name="Projects using jSLP">
+ <p>
+ <table>
+ <tr>
+ <th>Project</th>
+ <th>Description</th>
+ <th>Link</th>
+ </tr>
+ <tr>
+ <td>Adaptec iSCSI Management</td>
+ <td>Adaptec is in the storage management business. We have a storage management configuration utility based on a client/server model which is implemented in Java. As such it is portable to all of the OS platforms we support. We are developing an auto discovery feature to clients to automatically discover servers. Since iSCSI already uses SLP and we support a great many iSCSI devices, it seemed like a good idea to at least explore the idea of basing the auto discovery feature on SLP using jslp. Presently the auto discovery feature (using jslp) is being exercised by a network of several dozen servers.</td>
+ <td><a href="http://www.adaptec.com">Adaptec</a></td>
+ </tr>
+ <tr>
+ <td>R-OSGi</td>
+ <td>Remote service extension for OSGi</td>
+ <td><a href="http://sourceforge.net/projects/r-osgi">R-OSGi website</a></td>
+ </tr>
+ <tr>
+ <td>flowSGi</td>
+ <td>Collaborative middleware for mobile devices based on OSGi</td>
+ <td><a href="http://flowsgi.inf.ethz.ch">flowSGi website</a></td>
+ </tr>
+ <tr>
+ <td>VoiceHoc</td>
+ <td>VoiceHoc is a platform for running out-of-the-box SIP-based VoIP applications transparently in Mobile Ad Hoc Networks (MANETs) and heterogneous Internet-connected MANETs. VoiceHoc adopts a fully decentralized SIP infrastructure which makes use of D-SLP, an efficient service discovery mechanism in MANETs. D-SLP provides a regular SLP interface over TCP and UDP for service discovery, but exploits the underlying MANET routing protocol to piggyback the service information during the route setup. Mostly, the problem with these systems is that they are routing dependent. The very benefit of D-SLP however, is that it allows handlers for specific MANET routing protocols to be loaded like plugins. <br/> (Current research project of Patrick Stuedi, ETH Zurich)</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>Eclipse ECF</td>
+ <td>The Eclipse Communication Framework (ECF) uses jSLP as a provider for the Discovery API.</td>
+ <td>http://www.eclipse.org/ecf</td>
+ </tr>
+ </table>
+ </p>
+
+ <p>
+ If you use jSLP in your project, please let us know and send an <a href="mailto:rjan@users.sourceforge.net">email</a>.
+ </p>
+ </section>
+</body>
+</document>
diff --git a/protocols/bundles/ch.ethz.iks.slp/src/test/java/ch/ethz/iks/slp/impl/ServiceURLTest.java b/protocols/bundles/ch.ethz.iks.slp/src/test/java/ch/ethz/iks/slp/impl/ServiceURLTest.java
new file mode 100644
index 000000000..f177d04ae
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/src/test/java/ch/ethz/iks/slp/impl/ServiceURLTest.java
@@ -0,0 +1,114 @@
+package ch.ethz.iks.slp.impl;
+
+import ch.ethz.iks.slp.ServiceURL;
+import junit.framework.TestCase;
+
+public class ServiceURLTest extends TestCase {
+
+ public ServiceURLTest() {
+ super("ServiceURLTest");
+ System.setProperty("net.slp.port", "10427");
+ }
+
+ public void testServiceURL1() throws Exception {
+ String urlString = "service:test:myservice://localhost";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test:myservice");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 0);
+ assertEquals(url.getURLPath(), "");
+ assertEquals(url.getProtocol(), null);
+ assertEquals(url.toString(), urlString);
+ }
+
+ public void testServiceURL2() throws Exception {
+ String urlString = "service:test:myservice://localhost:80";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test:myservice");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 80);
+ assertEquals(url.getURLPath(), "");
+ assertEquals(url.getProtocol(), null);
+ assertEquals(url.toString(), urlString);
+ }
+
+ public void testServiceURL3() throws Exception {
+ String urlString = "service:test:myservice://localhost:80/path";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test:myservice");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 80);
+ assertEquals(url.getURLPath(), "/path");
+ assertEquals(url.getProtocol(), null);
+ assertEquals(url.toString(), urlString);
+ }
+
+ public void testServiceURL4() throws Exception {
+ String urlString = "service:test:myservice://localhost/my/path";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test:myservice");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 0);
+ assertEquals(url.getURLPath(), "/my/path");
+ assertEquals(url.getProtocol(), null);
+ assertEquals(url.toString(), urlString);
+ }
+
+ public void testServiceURL5() throws Exception {
+ String urlString = "service:test:myservice://http://localhost:8080/my/path";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test:myservice");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 8080);
+ assertEquals(url.getURLPath(), "/my/path");
+ assertEquals(url.getProtocol(), "http");
+ assertEquals(url.toString(), urlString);
+ }
+
+ public void testServiceURL6() throws Exception {
+ String urlString = "service:test://http://localhost";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 0);
+ assertEquals(url.getURLPath(), "");
+ assertEquals(url.getProtocol(), "http");
+ assertEquals(url.toString(), urlString);
+ }
+
+ public void testServiceURLNamingAuthorityCustom() throws Exception {
+ String urlString = "service:test.foo://http://localhost";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test.foo");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 0);
+ assertEquals(url.getURLPath(), "");
+ assertEquals(url.getProtocol(), "http");
+ assertEquals(url.toString(), urlString);
+ assertTrue("foo".equals(url.getServiceType().getNamingAuthority()));
+ }
+
+ public void testServiceURLNamingAuthorityDefault() throws Exception {
+ String urlString = "service:test://http://localhost";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 0);
+ assertEquals(url.getURLPath(), "");
+ assertEquals(url.getProtocol(), "http");
+ assertEquals(url.toString(), urlString);
+ assertTrue("".equals(url.getServiceType().getNamingAuthority()));
+ }
+
+ public void testServiceURLNamingAuthorityIana() throws Exception {
+ String urlString = "service:test.iana://http://localhost";
+ ServiceURL url = new ServiceURL(urlString, 0);
+ assertEquals(url.getServiceType().toString(), "service:test");
+ assertEquals(url.getHost(), "localhost");
+ assertEquals(url.getPort(), 0);
+ assertEquals(url.getURLPath(), "");
+ assertEquals(url.getProtocol(), "http");
+ assertEquals(url.toString(), "service:test://http://localhost");
+ assertTrue("".equals(url.getServiceType().getNamingAuthority()));
+ }
+}
diff --git a/protocols/bundles/ch.ethz.iks.slp/test/init.xargs b/protocols/bundles/ch.ethz.iks.slp/test/init.xargs
new file mode 100644
index 000000000..f15f70cc3
--- /dev/null
+++ b/protocols/bundles/ch.ethz.iks.slp/test/init.xargs
@@ -0,0 +1,6 @@
+-Dorg.osgi.framework.system.packages=junit.framework,junit.textui
+
+-init
+
+-istart file:target/jslp-osgi-1.0.0.RC5.jar
+-istart file:runtimeTests/target/jslp-test-1.0.0.RC5.jar \ No newline at end of file

Back to the top