keycloak-uncached
Changes
dependencies/server-all/pom.xml 7(+6 -1)
distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh 31(+31 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml 1(+1 -0)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml 32(+32 -0)
federation/pom.xml 1(+1 -0)
federation/sssd/pom.xml 56(+56 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java 39(+39 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java 18(+18 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java 21(+21 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java 20(+20 -0)
federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java 20(+20 -0)
federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java 77(+77 -0)
federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProviderFactory.java 88(+29 -59)
federation/sssd/src/main/resources/DBUS-JAVA-LICENSE 680(+680 -0)
federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory 18(+18 -0)
pom.xml 12(+12 -0)
testsuite/integration/pom.xml 8(+8 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/DummyUserFederationProvider.java 150(+0 -150)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java 18(+14 -4)
testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory 1(+0 -1)
testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl 13(+13 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json 6(+6 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl 114(+114 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties 18(+18 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html 72(+72 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties 18(+18 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl 95(+95 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl 131(+131 -0)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties 18(+18 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java 20(+20 -0)
Details
diff --git a/adapters/oidc/js/src/main/resources/keycloak.js b/adapters/oidc/js/src/main/resources/keycloak.js
index c6adb9b..44a7e75 100755
--- a/adapters/oidc/js/src/main/resources/keycloak.js
+++ b/adapters/oidc/js/src/main/resources/keycloak.js
@@ -154,7 +154,7 @@
return;
} else if (initOptions) {
if (initOptions.token || initOptions.refreshToken) {
- setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken, false);
+ setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
kc.timeSkew = initOptions.timeSkew || 0;
if (loginIframe.enable) {
@@ -406,10 +406,10 @@
timeLocal = (timeLocal + new Date().getTime()) / 2;
var tokenResponse = JSON.parse(req.responseText);
- setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token'], true);
-
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
+ setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
+
kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
p.setSuccess(true);
@@ -444,7 +444,7 @@
kc.clearToken = function() {
if (kc.token) {
- setToken(null, null, null, true);
+ setToken(null, null, null);
kc.onAuthLogout && kc.onAuthLogout();
if (kc.loginRequired) {
kc.login();
@@ -525,7 +525,7 @@
function authSuccess(accessToken, refreshToken, idToken, fulfillPromise) {
timeLocal = (timeLocal + new Date().getTime()) / 2;
- setToken(accessToken, refreshToken, idToken, true);
+ setToken(accessToken, refreshToken, idToken);
if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
(kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
@@ -609,7 +609,7 @@
return promise.promise;
}
- function setToken(token, refreshToken, idToken, useTokenTime) {
+ function setToken(token, refreshToken, idToken) {
if (kc.tokenTimeoutHandle) {
clearTimeout(kc.tokenTimeoutHandle);
kc.tokenTimeoutHandle = null;
@@ -629,9 +629,12 @@
kc.resourceAccess = kc.tokenParsed.resource_access;
if (kc.onTokenExpired) {
- var start = useTokenTime ? kc.tokenParsed.iat : (new Date().getTime() / 1000);
- var expiresIn = kc.tokenParsed.exp - start;
- kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn * 1000);
+ var expiresIn = (kc.tokenParsed['exp'] - (new Date().getTime() / 1000) + kc.timeSkew) * 1000;
+ if (expiresIn <= 0) {
+ kc.onTokenExpired();
+ } else {
+ kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
+ }
}
} else {
dependencies/server-all/pom.xml 7(+6 -1)
diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index 809890a..8922532 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -83,7 +83,6 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-kerberos-federation</artifactId>
</dependency>
-
<!-- saml -->
<dependency>
<groupId>org.keycloak</groupId>
@@ -110,6 +109,12 @@
</exclusions>
</dependency>
+ <!-- Dependencies for RHEL IdM -->
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-sssd-federation</artifactId>
+ </dependency>
+
<!-- Built-in Authorization Policy Providers -->
<dependency>
<groupId>org.keycloak</groupId>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh
new file mode 100644
index 0000000..6a0eae2
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/bin/federation-sssd-setup.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+# Setup for SSSD
+SSSD_FILE="/etc/sssd/sssd.conf"
+
+if [ -f "$SSSD_FILE" ];
+then
+ sed -i '/ldap_tls_cacert/a ldap_user_extra_attrs = mail:mail, sn:sn, givenname:givenname, telephoneNumber:telephoneNumber' $SSSD_FILE
+ sed -i 's/nss, sudo, pam/nss, sudo, pam, ifp/' $SSSD_FILE
+ sed -i '/\[ifp\]/a allowed_uids = root\nuser_attributes = +mail, +telephoneNumber, +givenname, +sn' $SSSD_FILE
+ systemctl restart sssd
+else
+ echo "Please make sure you have $SSSD_FILE into your system! Aborting."
+ exit 1
+fi
+
+# Setup for PAM
+PAM_FILE="/etc/pam.d/keycloak"
+
+if [ ! -f "$PAM_FILE" ];
+then
+cat <<EOF > $PAM_FILE
+ auth required pam_sss.so
+ account required pam_sss.so
+EOF
+else
+ echo "$PAM_FILE already exists. Skipping it..."
+ exit 0
+fi
+
+
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index de03ed8..8cf1cde 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -35,6 +35,7 @@
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
+ <module name="org.keycloak.keycloak-sssd-federation" services="import"/>
<module name="org.keycloak.keycloak-server-spi" services="import"/>
<module name="org.keycloak.keycloak-model-jpa" services="import"/>
<module name="org.keycloak.keycloak-model-mongo" services="import"/>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
new file mode 100644
index 0000000..ad16f3c
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+ ~ and other contributors as indicated by the @author tags.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-sssd-federation">
+ <properties>
+ <property name="jboss.api" value="private"/>
+ </properties>
+
+ <resources>
+ <artifact name="${org.keycloak:keycloak-sssd-federation}"/>
+ </resources>
+
+ <dependencies>
+ <module name="org.jboss.logging"/>
+ <module name="org.keycloak.keycloak-core" />
+ <module name="org.keycloak.keycloak-server-spi" />
+ </dependencies>
+</module>
\ No newline at end of file
federation/pom.xml 1(+1 -0)
diff --git a/federation/pom.xml b/federation/pom.xml
index 663f857..dc702cc 100755
--- a/federation/pom.xml
+++ b/federation/pom.xml
@@ -35,6 +35,7 @@
<modules>
<module>ldap</module>
<module>kerberos</module>
+ <module>sssd</module>
</modules>
</project>
federation/sssd/pom.xml 56(+56 -0)
diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml
new file mode 100644
index 0000000..7d109e8
--- /dev/null
+++ b/federation/sssd/pom.xml
@@ -0,0 +1,56 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>2.2.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-sssd-federation</artifactId>
+ <name>Keycloak SSSD Federation</name>
+ <description/>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-server-spi</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/debug/Debug.java b/federation/sssd/src/main/java/cx/ath/matthew/debug/Debug.java
new file mode 100644
index 0000000..30c4d85
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/debug/Debug.java
@@ -0,0 +1,671 @@
+/* Copyright (C) 1991-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+/* This header is separate from features.h so that the compiler can
+ include it implicitly at the start of every compilation. It must
+ not itself include <features.h> or any other header that includes
+ <features.h> because the implicit include comes before any feature
+ test macros that may be defined in a source file before it first
+ explicitly includes a system header. GCC knows the name of this
+ header in order to preinclude it. */
+/* glibc's intent is to support the IEC 559 math functionality, real
+ and complex. If the GCC (4.9 and later) predefined macros
+ specifying compiler intent are available, use them to determine
+ whether the overall intent is to support these features; otherwise,
+ presume an older compiler has intent to support these features and
+ define these macros by default. */
+/* wchar_t uses Unicode 7.0.0. Version 7.0 of the Unicode Standard is
+ synchronized with ISO/IEC 10646:2012, plus Amendments 1 (published
+ on April, 2013) and 2 (not yet published as of February, 2015).
+ Additionally, it includes the accelerated publication of U+20BD
+ RUBLE SIGN. Therefore Unicode 7.0.0 is between 10646:2012 and
+ 10646:2014, and so we use the date ISO/IEC 10646:2012 Amd.1 was
+ published. */
+/* We do not support C11 <threads.h>. */
+/*
+ * Java Debug Library
+ *
+ * Copyright (c) Matthew Johnson 2005
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.debug;
+
+import cx.ath.matthew.utils.Hexdump;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Add debugging to your program, has support for large projects with multiple
+ * classes and debug levels per class. Supports optional enabling of debug
+ * per-level per-class and debug targets of files, Streams or stderr.
+ * Also supports timing between debug outputs, printing of stack traces for Throwables
+ * and files/line numbers on each message.
+ * <p>
+ * Debug now automatically figures out which class it was called from, so all
+ * methods passing in the calling class are deprecated.
+ * </p>
+ * <p>
+ * The defaults are to print all messages to stderr with class and method name.
+ * </p>
+ * <p>
+ * Should be called like this:
+ * </p>
+ * <pre>
+ * if (Debug.debug) Debug.print(Debug.INFO, "Debug Message");
+ * </pre>
+ */
+public class Debug {
+ /**
+ * This interface can be used to provide custom printing filters
+ * for certain classes.
+ */
+ public static interface FilterCommand {
+ /**
+ * Called to print debug messages with a custom filter.
+ *
+ * @param output The PrintStream to output to.
+ * @param level The debug level of this message.
+ * @param location The textual location of the message.
+ * @param extra Extra information such as timing details.
+ * @param message The debug message.
+ * @param lines Other lines of a multiple-line debug message.
+ */
+ public void filter(PrintStream output, int level, String location, String extra, String message, String[] lines);
+ }
+
+ /**
+ * Highest priority messages
+ */
+ public static final int CRIT = 1;
+ /**
+ * Error messages
+ */
+ public static final int ERR = 2;
+ /**
+ * Warnings
+ */
+ public static final int WARN = 3;
+ /**
+ * Information
+ */
+ public static final int INFO = 4;
+ /**
+ * Debug messages
+ */
+ public static final int DEBUG = 5;
+ /**
+ * Verbose debug messages
+ */
+ public static final int VERBOSE = 6;
+ /**
+ * Set this to false to disable compilation of Debug statements
+ */
+ public static final boolean debug = false;
+ /**
+ * The current output stream (defaults to System.err)
+ */
+ public static PrintStream debugout = System.err;
+ private static Properties prop = null;
+ private static boolean timing = false;
+ private static boolean ttrace = false;
+ private static boolean lines = false;
+ private static boolean hexdump = false;
+ private static long last = 0;
+ private static int balen = 36;
+ private static int bawidth = 80;
+ private static Class saveclass = null;
+ //TODO: 1.5 private static Map<Class<? extends Object>, FilterCommand> filterMap = new HashMap<Class<? extends Object>, FilterCommand>();
+ private static Map filterMap = new HashMap();
+
+ /**
+ * Set properties to configure debugging.
+ * Format of properties is class => level, e.g.
+ * <pre>
+ * cx.ath.matthew.io.TeeOutputStream = INFO
+ * cx.ath.matthew.io.DOMPrinter = DEBUG
+ * </pre>
+ * The debug level can be one of CRIT, ERR, WARN, INFO, DEBUG or VERBOSE which
+ * correspond to all messages up to that level. The special words YES, ALL and TRUE
+ * cause all messages to be printed regardless of level. All other terms disable
+ * messages for that class. CRIT and ERR messages are always printed if debugging is enabled
+ * unless explicitly disabled.
+ * The special class name ALL can be used to set the default level for all classes.
+ *
+ * @param prop Properties object to use.
+ */
+ public static void setProperties(Properties prop) {
+ Debug.prop = prop;
+ }
+
+ /**
+ * Read which class to debug on at which level from the given File.
+ * Syntax the same as Java Properties files:
+ * <pre>
+ * <class> = <debuglevel>
+ * </pre>
+ * E.G.
+ * <pre>
+ * cx.ath.matthew.io.TeeOutputStream = INFO
+ * cx.ath.matthew.io.DOMPrinter = DEBUG
+ * </pre>
+ * The debug level can be one of CRIT, ERR, WARN, INFO, DEBUG or VERBOSE which
+ * correspond to all messages up to that level. The special words YES, ALL and TRUE
+ * cause all messages to be printed regardless of level. All other terms disable
+ * messages for that class. CRIT and ERR messages are always printed if debugging is enabled
+ * unless explicitly disabled.
+ * The special class name ALL can be used to set the default level for all classes.
+ *
+ * @param f File to read from.
+ */
+ public static void loadConfig(File f) throws IOException {
+ prop = new Properties();
+ prop.load(new FileInputStream(f));
+ }
+
+ /**
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static boolean debugging(Class c, int loglevel) {
+ if (debug) {
+ if (null == c) return true;
+ return debugging(c.getName(), loglevel);
+ }
+ return false;
+ }
+
+ public static boolean debugging(String s, int loglevel) {
+ if (debug) {
+ try {
+ if (null == s) return true;
+ if (null == prop) return loglevel <= DEBUG;
+ String d = prop.getProperty(s);
+ if (null == d || "".equals(d)) d = prop.getProperty("ALL");
+ if (null == d) return loglevel <= ERR;
+ if ("".equals(d)) return loglevel <= ERR;
+ d = d.toLowerCase();
+ if ("true".equals(d)) return true;
+ if ("yes".equals(d)) return true;
+ if ("all".equals(d)) return true;
+ if ("verbose".equals(d)) return loglevel <= VERBOSE;
+ if ("debug".equals(d)) return loglevel <= DEBUG;
+ if ("info".equals(d)) return loglevel <= INFO;
+ if ("warn".equals(d)) return loglevel <= WARN;
+ if ("err".equals(d)) return loglevel <= ERR;
+ if ("crit".equals(d)) return loglevel <= CRIT;
+ int i = Integer.parseInt(d);
+ return i >= loglevel;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Output to the given Stream
+ */
+ public static void setOutput(PrintStream p) throws IOException {
+ debugout = p;
+ }
+
+ /**
+ * Output to the given file
+ */
+ public static void setOutput(String filename) throws IOException {
+ debugout = new PrintStream(new FileOutputStream(filename, true));
+ }
+
+ /**
+ * Output to the default debug.log
+ */
+ public static void setOutput() throws IOException {
+ setOutput("./debug.log");
+ }
+
+ /**
+ * Log at DEBUG
+ *
+ * @param d The object to log
+ */
+ public static void print(Object d) {
+ if (debug) {
+ if (d instanceof String)
+ print(DEBUG, (String) d);
+ else if (d instanceof Throwable)
+ print(DEBUG, (Throwable) d);
+ else if (d instanceof byte[])
+ print(DEBUG, (byte[]) d);
+ else if (d instanceof Map)
+ printMap(DEBUG, (Map) d);
+ else print(DEBUG, d);
+ }
+ }
+
+ /**
+ * Log at DEBUG
+ *
+ * @param o The object doing the logging
+ * @param d The object to log
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void print(Object o, Object d) {
+ if (debug) {
+ if (o instanceof Class)
+ saveclass = (Class) o;
+ else
+ saveclass = o.getClass();
+ print(d);
+ }
+ }
+
+ /**
+ * Log an Object
+ *
+ * @param o The object doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param d The object to log with d.toString()
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void print(Object o, int loglevel, Object d) {
+ if (debug) {
+ if (o instanceof Class)
+ saveclass = (Class) o;
+ else
+ saveclass = o.getClass();
+ print(loglevel, d);
+ }
+ }
+
+ /**
+ * Log a String
+ *
+ * @param o The object doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param s The log message
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void print(Object o, int loglevel, String s) {
+ if (debug) {
+ if (o instanceof Class)
+ saveclass = (Class) o;
+ else
+ saveclass = o.getClass();
+ print(loglevel, s);
+ }
+ }
+
+ /**
+ * Log a Throwable
+ *
+ * @param o The object doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param t The throwable to log with .toString and .printStackTrace
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void print(Object o, int loglevel, Throwable t) {
+ if (debug) {
+ if (o instanceof Class)
+ saveclass = (Class) o;
+ else
+ saveclass = o.getClass();
+ print(loglevel, t);
+ }
+ }
+
+ /**
+ * Log a Throwable
+ *
+ * @param c The class doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param t The throwable to log with .toString and .printStackTrace
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void print(Class c, int loglevel, Throwable t) {
+ if (debug) {
+ saveclass = c;
+ print(loglevel, t);
+ }
+ }
+
+ /**
+ * Log a Throwable
+ *
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param t The throwable to log with .toString and .printStackTrace
+ * @see #setThrowableTraces to turn on stack traces.
+ */
+ public static void print(int loglevel, Throwable t) {
+ if (debug) {
+ String timestr = "";
+ String[] data = getTraceElements();
+ if (debugging(data[0], loglevel)) {
+ if (timing) {
+ long now = System.currentTimeMillis();
+ timestr = "{" + (now - last) + "} ";
+ last = now;
+ }
+ String[] lines = null;
+ if (ttrace) {
+ StackTraceElement[] ste = t.getStackTrace();
+ lines = new String[ste.length];
+ for (int i = 0; i < ste.length; i++)
+ lines[i] = "\tat " + ste[i].toString();
+ }
+ _print(t.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, t.toString(), lines);
+ }
+ }
+ }
+
+ /**
+ * Log a byte array
+ *
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param b The byte array to print.
+ * @see #setHexDump to enable hex dumping.
+ * @see #setByteArrayCount to change how many bytes are printed.
+ * @see #setByteArrayWidth to change the formatting width of hex.
+ */
+ public static void print(int loglevel, byte[] b) {
+ if (debug) {
+ String timestr = "";
+ String[] data = getTraceElements();
+ if (debugging(data[0], loglevel)) {
+ if (timing) {
+ long now = System.currentTimeMillis();
+ timestr = "{" + (now - last) + "} ";
+ last = now;
+ }
+ String[] lines = null;
+ if (hexdump) {
+ if (balen >= b.length)
+ lines = Hexdump.format(b, bawidth).split("\n");
+ else {
+ byte[] buf = new byte[balen];
+ System.arraycopy(b, 0, buf, 0, balen);
+ lines = Hexdump.format(buf, bawidth).split("\n");
+ }
+ }
+ _print(b.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, b.length + " bytes", lines);
+ }
+ }
+ }
+
+ /**
+ * Log a String
+ *
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param s The string to log with d.toString()
+ */
+ public static void print(int loglevel, String s) {
+ if (debug)
+ print(loglevel, (Object) s);
+ }
+
+ /**
+ * Log an Object
+ *
+ * @param c The class doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param d The object to log with d.toString()
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void print(Class c, int loglevel, Object d) {
+ if (debug) {
+ saveclass = c;
+ print(loglevel, d);
+ }
+ }
+
+ /**
+ * Log a String
+ *
+ * @param c The class doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param s The log message
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void print(Class c, int loglevel, String s) {
+ if (debug) {
+ saveclass = c;
+ print(loglevel, s);
+ }
+ }
+
+ private static String[] getTraceElements() {
+ String[] data = new String[]{"", "", ""};
+ try {
+ Method m = Thread.class.getMethod("getStackTrace", new Class[0]);
+ StackTraceElement[] stes = (StackTraceElement[]) m.invoke(Thread.currentThread(), new Object[0]);
+ for (StackTraceElement ste : stes) {
+ if (Debug.class.getName().equals(ste.getClassName())) continue;
+ if (Thread.class.getName().equals(ste.getClassName())) continue;
+ if (Method.class.getName().equals(ste.getClassName())) continue;
+ if (ste.getClassName().startsWith("sun.reflect")) continue;
+ data[0] = ste.getClassName();
+ data[1] = ste.getMethodName();
+ if (lines)
+ data[2] = " " + ste.getFileName() + ":" + ste.getLineNumber();
+ break;
+ }
+ } catch (NoSuchMethodException NSMe) {
+ if (null != saveclass)
+ data[0] = saveclass.getName();
+ } catch (IllegalAccessException IAe) {
+ } catch (InvocationTargetException ITe) {
+ }
+ return data;
+ }
+
+ /**
+ * Log an Object
+ *
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param o The object to log
+ */
+ public static void print(int loglevel, Object o) {
+ if (debug) {
+ String timestr = "";
+ String[] data = getTraceElements();
+ if (debugging(data[0], loglevel)) {
+ if (timing) {
+ long now = System.currentTimeMillis();
+ timestr = "{" + (now - last) + "} ";
+ last = now;
+ }
+ _print(o.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, o.toString(), null);
+ }
+ }
+ }
+
+ /**
+ * Log a Map
+ *
+ * @param o The object doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param m The Map to print out
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void printMap(Object o, int loglevel, Map m) {
+ if (debug) {
+ if (o instanceof Class)
+ saveclass = (Class) o;
+ else
+ saveclass = o.getClass();
+ printMap(loglevel, m);
+ }
+ }
+
+ /**
+ * Log a Map
+ *
+ * @param c The class doing the logging
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param m The Map to print out
+ * @deprecated In Java 1.5 calling class is automatically identified, no need to pass it in.
+ */
+ //TODO: 1.5 @Deprecated()
+ public static void printMap(Class c, int loglevel, Map m) {
+ if (debug) {
+ saveclass = c;
+ printMap(loglevel, m);
+ }
+ }
+
+ /**
+ * Log a Map at DEBUG log level
+ *
+ * @param m The Map to print out
+ */
+ public static void printMap(Map m) {
+ printMap(DEBUG, m);
+ }
+
+ /**
+ * Log a Map
+ *
+ * @param loglevel The level to log at (DEBUG, WARN, etc)
+ * @param m The Map to print out
+ */
+ public static void printMap(int loglevel, Map m) {
+ if (debug) {
+ String timestr = "";
+ String[] data = getTraceElements();
+ if (debugging(data[0], loglevel)) {
+ if (timing) {
+ long now = System.currentTimeMillis();
+ timestr = "{" + (now - last) + "} ";
+ last = now;
+ }
+ Iterator i = m.keySet().iterator();
+ String[] lines = new String[m.size()];
+ int j = 0;
+ while (i.hasNext()) {
+ Object key = i.next();
+ lines[j++] = "\t\t- " + key + " => " + m.get(key);
+ }
+ _print(m.getClass(), loglevel, data[0] + "." + data[1] + "()" + data[2], timestr, "Map:", lines);
+ }
+ }
+ }
+
+ /**
+ * Enable or disable stack traces in Debuging throwables.
+ */
+ public static void setThrowableTraces(boolean ttrace) {
+ Debug.ttrace = ttrace;
+ }
+
+ /**
+ * Enable or disable timing in Debug messages.
+ */
+ public static void setTiming(boolean timing) {
+ Debug.timing = timing;
+ }
+
+ /**
+ * Enable or disable line numbers.
+ */
+ public static void setLineNos(boolean lines) {
+ Debug.lines = lines;
+ }
+
+ /**
+ * Enable or disable hexdumps.
+ */
+ public static void setHexDump(boolean hexdump) {
+ Debug.hexdump = hexdump;
+ }
+
+ /**
+ * Set the size of hexdumps.
+ * (Default: 36)
+ */
+ public static void setByteArrayCount(int count) {
+ Debug.balen = count;
+ }
+
+ /**
+ * Set the formatted width of hexdumps.
+ * (Default: 80 chars)
+ */
+ public static void setByteArrayWidth(int width) {
+ Debug.bawidth = width;
+ }
+
+ /**
+ * Add a filter command for a specific type.
+ * This command will be called with the output stream
+ * and the text to be sent. It should perform any
+ * changes necessary to the text and then print the
+ * result to the output stream.
+ */
+ public static void addFilterCommand(Class c, FilterCommand f)
+ //TODO 1.5: public static void addFilterCommand(Class<? extends Object> c, FilterCommand f)
+ {
+ filterMap.put(c, f);
+ }
+
+ private static void _print(Class c, int level, String loc, String extra, String message, String[] lines) {
+ //TODO 1.5: FilterCommand f = filterMap.get(c);
+ FilterCommand f = (FilterCommand) filterMap.get(c);
+ if (null == f) {
+ debugout.println("[" + loc + "] " + extra + message);
+ if (null != lines)
+ for (String s : lines)
+ debugout.println(s);
+ } else
+ f.filter(debugout, level, loc, extra, message, lines);
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
new file mode 100644
index 0000000..ffdf02d
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package cx.ath.matthew;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+public class LibraryLoader {
+
+ private static final Logger LOGGER = Logger.getLogger(LibraryLoader.class.getSimpleName());
+
+ private static final String[] PATHS = {"/usr/lib/", "/usr/lib64/", "/usr/local/lib/", "/opt/local/lib/"};
+ private static final String LIBRARY_NAME = "libunix_dbus_java";
+ private static final String VERSION = "0.0.8";
+ private static boolean loadSucceeded;
+
+ public static void load() {
+ for (String path : PATHS) {
+ try {
+ System.load(String.format("%s/%s.so.%s", path, LIBRARY_NAME, VERSION));
+ loadSucceeded = true;
+ break;
+ } catch (UnsatisfiedLinkError e) {
+ loadSucceeded = false;
+ }
+
+ }
+
+ if (!loadSucceeded) LOGGER.log(Level.WARNING, "libunix_dbus_java not found\n" +
+ "Please, make sure you have the package libunix-dbus-java installed.");
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/NotConnectedException.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/NotConnectedException.java
new file mode 100644
index 0000000..836f5d6
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/NotConnectedException.java
@@ -0,0 +1,35 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.net.SocketException;
+
+public class NotConnectedException extends SocketException {
+ public NotConnectedException() {
+ super("The Socket is Not Connected");
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java
new file mode 100644
index 0000000..24fd20c
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java
@@ -0,0 +1,43 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.io.IOException;
+
+/**
+ * An IO Exception which occurred during UNIX Socket IO
+ */
+public class UnixIOException extends IOException {
+ private int no;
+ private String message;
+
+ public UnixIOException(int no, String message) {
+ super(message);
+ this.message = message;
+ this.no = no;
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java
new file mode 100644
index 0000000..8851637
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java
@@ -0,0 +1,350 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import cx.ath.matthew.LibraryLoader;
+import cx.ath.matthew.debug.Debug;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents a UnixSocket.
+ */
+public class UnixSocket {
+ static {
+ LibraryLoader.load();
+ }
+
+ private native void native_set_pass_cred(int sock, boolean passcred) throws IOException;
+
+ private native int native_connect(String address, boolean abs) throws IOException;
+
+ private native void native_close(int sock) throws IOException;
+
+ private native int native_getPID(int sock);
+
+ private native int native_getUID(int sock);
+
+ private native int native_getGID(int sock);
+
+ private native void native_send_creds(int sock, byte data) throws IOException;
+
+ private native byte native_recv_creds(int sock, int[] creds) throws IOException;
+
+ private UnixSocketAddress address = null;
+ private USOutputStream os = null;
+ private USInputStream is = null;
+ private boolean closed = false;
+ private boolean connected = false;
+ private boolean passcred = false;
+ private int sock = 0;
+ private boolean blocking = true;
+ private int uid = -1;
+ private int pid = -1;
+ private int gid = -1;
+
+ UnixSocket(int sock, UnixSocketAddress address) {
+ this.sock = sock;
+ this.address = address;
+ this.connected = true;
+ this.os = new USOutputStream(sock, this);
+ this.is = new USInputStream(sock, this);
+ }
+
+ /**
+ * Create an unconnected socket.
+ */
+ public UnixSocket() {
+ }
+
+ /**
+ * Create a socket connected to the given address.
+ *
+ * @param address The Unix Socket address to connect to
+ */
+ public UnixSocket(UnixSocketAddress address) throws IOException {
+ connect(address);
+ }
+
+ /**
+ * Create a socket connected to the given address.
+ *
+ * @param address The Unix Socket address to connect to
+ */
+ public UnixSocket(String address) throws IOException {
+ this(new UnixSocketAddress(address));
+ }
+
+ /**
+ * Connect the socket to this address.
+ *
+ * @param address The Unix Socket address to connect to
+ */
+ public void connect(UnixSocketAddress address) throws IOException {
+ if (connected) close();
+ this.sock = native_connect(address.path, address.abs);
+ this.os = new USOutputStream(this.sock, this);
+ this.is = new USInputStream(this.sock, this);
+ this.address = address;
+ this.connected = true;
+ this.closed = false;
+ this.is.setBlocking(blocking);
+ }
+
+ /**
+ * Connect the socket to this address.
+ *
+ * @param address The Unix Socket address to connect to
+ */
+ public void connect(String address) throws IOException {
+ connect(new UnixSocketAddress(address));
+ }
+
+ public void finalize() {
+ try {
+ close();
+ } catch (IOException IOe) {
+ }
+ }
+
+ /**
+ * Closes the connection.
+ */
+ public synchronized void close() throws IOException {
+ if (Debug.debug) Debug.print(Debug.INFO, "Closing socket");
+ native_close(sock);
+ sock = 0;
+ this.closed = true;
+ this.connected = false;
+ os = null;
+ is = null;
+ }
+
+ /**
+ * Returns an InputStream for reading from the socket.
+ *
+ * @return An InputStream connected to this socket.
+ */
+ public InputStream getInputStream() {
+ return is;
+ }
+
+ /**
+ * Returns an OutputStream for writing to the socket.
+ *
+ * @return An OutputStream connected to this socket.
+ */
+ public OutputStream getOutputStream() {
+ return os;
+ }
+
+ /**
+ * Returns the address this socket is connected to.
+ * Returns null if the socket is unconnected.
+ *
+ * @return The UnixSocketAddress the socket is connected to
+ */
+ public UnixSocketAddress getAddress() {
+ return address;
+ }
+
+ /**
+ * Send a single byte of data with credentials.
+ * (Works on BSDs)
+ *
+ * @param data The byte of data to send.
+ */
+ public void sendCredentialByte(byte data) throws IOException {
+ if (!connected) throw new NotConnectedException();
+ native_send_creds(sock, data);
+ }
+
+ /**
+ * Receive a single byte of data, with credentials.
+ * (Works on BSDs)
+ *
+ * @param data The byte of data to send.
+ * @see getPeerUID
+ * @see getPeerPID
+ * @see getPeerGID
+ */
+ public byte recvCredentialByte() throws IOException {
+ if (!connected) throw new NotConnectedException();
+ int[] creds = new int[]{-1, -1, -1};
+ byte data = native_recv_creds(sock, creds);
+ pid = creds[0];
+ uid = creds[1];
+ gid = creds[2];
+ return data;
+ }
+
+ /**
+ * Get the credential passing status.
+ * (only effective on linux)
+ *
+ * @return The current status of credential passing.
+ * @see setPassCred
+ */
+ public boolean getPassCred() {
+ return passcred;
+ }
+
+ /**
+ * Return the uid of the remote process.
+ * Some data must have been received on the socket to do this.
+ * Either setPassCred must be called on Linux first, or recvCredentialByte
+ * on BSD.
+ *
+ * @return the UID or -1 if it is not available
+ */
+ public int getPeerUID() {
+ if (-1 == uid)
+ uid = native_getUID(sock);
+ return uid;
+ }
+
+ /**
+ * Return the gid of the remote process.
+ * Some data must have been received on the socket to do this.
+ * Either setPassCred must be called on Linux first, or recvCredentialByte
+ * on BSD.
+ *
+ * @return the GID or -1 if it is not available
+ */
+ public int getPeerGID() {
+ if (-1 == gid)
+ gid = native_getGID(sock);
+ return gid;
+ }
+
+ /**
+ * Return the pid of the remote process.
+ * Some data must have been received on the socket to do this.
+ * Either setPassCred must be called on Linux first, or recvCredentialByte
+ * on BSD.
+ *
+ * @return the PID or -1 if it is not available
+ */
+ public int getPeerPID() {
+ if (-1 == pid)
+ pid = native_getPID(sock);
+ return pid;
+ }
+
+ /**
+ * Set the credential passing status.
+ * (Only does anything on linux, for other OS, you need
+ * to use send/recv credentials)
+ *
+ * @param enable Set to true for credentials to be passed.
+ */
+ public void setPassCred(boolean enable) throws IOException {
+ native_set_pass_cred(sock, enable);
+ passcred = enable;
+ }
+
+ /**
+ * Get the blocking mode.
+ *
+ * @return true if reads are blocking.
+ * @see setBlocking
+ */
+ public boolean getBlocking() {
+ return blocking;
+ }
+
+ /**
+ * Set the blocking mode.
+ *
+ * @param enable Set to false for non-blocking reads.
+ */
+ public void setBlocking(boolean enable) {
+ blocking = enable;
+ if (null != is) is.setBlocking(enable);
+ }
+
+ /**
+ * Check the socket status.
+ *
+ * @return true if closed.
+ */
+ public boolean isClosed() {
+ return closed;
+ }
+
+ /**
+ * Check the socket status.
+ *
+ * @return true if connected.
+ */
+ public boolean isConnected() {
+ return connected;
+ }
+
+ /**
+ * Check the socket status.
+ *
+ * @return true if the input stream has been shutdown
+ */
+ public boolean isInputShutdown() {
+ return is.isClosed();
+ }
+
+ /**
+ * Check the socket status.
+ *
+ * @return true if the output stream has been shutdown
+ */
+ public boolean isOutputShutdown() {
+ return os.isClosed();
+ }
+
+ /**
+ * Shuts down the input stream.
+ * Subsequent reads on the associated InputStream will fail.
+ */
+ public void shutdownInput() {
+ is.closed = true;
+ }
+
+ /**
+ * Shuts down the output stream.
+ * Subsequent writes to the associated OutputStream will fail.
+ */
+ public void shutdownOutput() {
+ os.closed = true;
+ }
+
+ /**
+ * Set timeout of read requests.
+ */
+ public void setSoTimeout(int timeout) {
+ is.setSoTimeout(timeout);
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java
new file mode 100644
index 0000000..0baba47
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java
@@ -0,0 +1,86 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+/**
+ * Represents an address for a Unix Socket
+ */
+public class UnixSocketAddress {
+ String path;
+ boolean abs;
+
+ /**
+ * Create the address.
+ *
+ * @param path The path to the Unix Socket.
+ * @param abs True if this should be an abstract socket.
+ */
+ public UnixSocketAddress(String path, boolean abs) {
+ this.path = path;
+ this.abs = abs;
+ }
+
+ /**
+ * Create the address.
+ *
+ * @param path The path to the Unix Socket.
+ */
+ public UnixSocketAddress(String path) {
+ this.path = path;
+ this.abs = false;
+ }
+
+ /**
+ * Return the path.
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * Returns true if this an address for an abstract socket.
+ */
+ public boolean isAbstract() {
+ return abs;
+ }
+
+ /**
+ * Return the Address as a String.
+ */
+ public String toString() {
+ return "unix" + (abs ? ":abstract" : "") + ":path=" + path;
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof UnixSocketAddress)) return false;
+ return ((UnixSocketAddress) o).path.equals(this.path);
+ }
+
+ public int hashCode() {
+ return path.hashCode();
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java
new file mode 100644
index 0000000..eb143fe
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java
@@ -0,0 +1,94 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class USInputStream extends InputStream {
+ public static final int MSG_DONTWAIT = 0x40;
+
+ private native int native_recv(int sock, byte[] b, int off, int len, int flags, int timeout) throws IOException;
+
+ private int sock;
+ boolean closed = false;
+ private byte[] onebuf = new byte[1];
+ private UnixSocket us;
+ private boolean blocking = true;
+ private int flags = 0;
+ private int timeout = 0;
+
+ public USInputStream(int sock, UnixSocket us) {
+ this.sock = sock;
+ this.us = us;
+ }
+
+ public void close() throws IOException {
+ closed = true;
+ us.close();
+ }
+
+ public boolean markSupported() {
+ return false;
+ }
+
+ public int read() throws IOException {
+ int rv = 0;
+ while (0 >= rv) rv = read(onebuf);
+ if (-1 == rv) return -1;
+ return 0 > onebuf[0] ? -onebuf[0] : onebuf[0];
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (closed) throw new NotConnectedException();
+ int count = native_recv(sock, b, off, len, flags, timeout);
+ /* Yes, I really want to do this. Recv returns 0 for 'connection shut down'.
+ * read() returns -1 for 'end of stream.
+ * Recv returns -1 for 'EAGAIN' (all other errors cause an exception to be raised)
+ * whereas read() returns 0 for '0 bytes read', so yes, I really want to swap them here.
+ */
+ if (0 == count) return -1;
+ else if (-1 == count) return 0;
+ else return count;
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+
+ public UnixSocket getSocket() {
+ return us;
+ }
+
+ public void setBlocking(boolean enable) {
+ flags = enable ? 0 : MSG_DONTWAIT;
+ }
+
+ public void setSoTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java
new file mode 100644
index 0000000..d8c85a7
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java
@@ -0,0 +1,78 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class USOutputStream extends OutputStream {
+ private native int native_send(int sock, byte[] b, int off, int len) throws IOException;
+
+ private native int native_send(int sock, byte[][] b) throws IOException;
+
+ private int sock;
+ boolean closed = false;
+ private byte[] onebuf = new byte[1];
+ private UnixSocket us;
+
+ public USOutputStream(int sock, UnixSocket us) {
+ this.sock = sock;
+ this.us = us;
+ }
+
+ public void close() throws IOException {
+ closed = true;
+ us.close();
+ }
+
+ public void flush() {
+ } // no-op, we do not buffer
+
+ public void write(byte[][] b) throws IOException {
+ if (closed) throw new NotConnectedException();
+ native_send(sock, b);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (closed) throw new NotConnectedException();
+ native_send(sock, b, off, len);
+ }
+
+ public void write(int b) throws IOException {
+ onebuf[0] = (byte) (b % 0x7F);
+ if (1 == (b % 0x80)) onebuf[0] = (byte) -onebuf[0];
+ write(onebuf);
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+
+ public UnixSocket getSocket() {
+ return us;
+ }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/utils/Hexdump.java b/federation/sssd/src/main/java/cx/ath/matthew/utils/Hexdump.java
new file mode 100644
index 0000000..63f3719
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/utils/Hexdump.java
@@ -0,0 +1,147 @@
+/*
+ * Java Hexdump Library
+ *
+ * Copyright (c) Matthew Johnson 2005
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+
+package cx.ath.matthew.utils;
+
+import java.io.PrintStream;
+
+public class Hexdump {
+ public static final char[] hexchars = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ public static String toHex(byte[] buf) {
+ return toHex(buf, 0, buf.length);
+ }
+
+ public static String toHex(byte[] buf, int ofs, int len) {
+ StringBuffer sb = new StringBuffer();
+ int j = ofs + len;
+ for (int i = ofs; i < j; i++) {
+ if (i < buf.length) {
+ sb.append(hexchars[(buf[i] & 0xF0) >> 4]);
+ sb.append(hexchars[buf[i] & 0x0F]);
+ sb.append(' ');
+ } else {
+ sb.append(' ');
+ sb.append(' ');
+ sb.append(' ');
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String toAscii(byte[] buf) {
+ return toAscii(buf, 0, buf.length);
+ }
+
+ public static String toAscii(byte[] buf, int ofs, int len) {
+ StringBuffer sb = new StringBuffer();
+ int j = ofs + len;
+ for (int i = ofs; i < j; i++) {
+ if (i < buf.length) {
+ if (20 <= buf[i] && 126 >= buf[i])
+ sb.append((char) buf[i]);
+ else
+ sb.append('.');
+ } else
+ sb.append(' ');
+ }
+ return sb.toString();
+ }
+
+ public static String format(byte[] buf) {
+ return format(buf, 80);
+ }
+
+ public static String format(byte[] buf, int width) {
+ int bs = (width - 8) / 4;
+ int i = 0;
+ StringBuffer sb = new StringBuffer();
+ do {
+ for (int j = 0; j < 6; j++) {
+ sb.append(hexchars[(i << (j * 4) & 0xF00000) >> 20]);
+ }
+ sb.append('\t');
+ sb.append(toHex(buf, i, bs));
+ sb.append(' ');
+ sb.append(toAscii(buf, i, bs));
+ sb.append('\n');
+ i += bs;
+ } while (i < buf.length);
+ return sb.toString();
+ }
+
+ public static void print(byte[] buf) {
+ print(buf, System.err);
+ }
+
+ public static void print(byte[] buf, int width) {
+ print(buf, width, System.err);
+ }
+
+ public static void print(byte[] buf, int width, PrintStream out) {
+ out.print(format(buf, width));
+ }
+
+ public static void print(byte[] buf, PrintStream out) {
+ out.print(format(buf));
+ }
+
+ /**
+ * Returns a string which can be written to a Java source file as part
+ * of a static initializer for a byte array.
+ * Returns data in the format 0xAB, 0xCD, ....
+ * use like:
+ * javafile.print("byte[] data = {")
+ * javafile.print(Hexdump.toByteArray(data));
+ * javafile.println("};");
+ */
+ public static String toByteArray(byte[] buf) {
+ return toByteArray(buf, 0, buf.length);
+ }
+
+ /**
+ * Returns a string which can be written to a Java source file as part
+ * of a static initializer for a byte array.
+ * Returns data in the format 0xAB, 0xCD, ....
+ * use like:
+ * javafile.print("byte[] data = {")
+ * javafile.print(Hexdump.toByteArray(data));
+ * javafile.println("};");
+ */
+ public static String toByteArray(byte[] buf, int ofs, int len) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = ofs; i < len && i < buf.length; i++) {
+ sb.append('0');
+ sb.append('x');
+ sb.append(hexchars[(buf[i] & 0xF0) >> 4]);
+ sb.append(hexchars[buf[i] & 0x0F]);
+ if ((i + 1) < len && (i + 1) < buf.length)
+ sb.append(',');
+ }
+ return sb.toString();
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/DBus.java b/federation/sssd/src/main/java/org/freedesktop/DBus.java
new file mode 100644
index 0000000..1aa180a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/DBus.java
@@ -0,0 +1,530 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop;
+
+import org.freedesktop.dbus.DBusInterface;
+import org.freedesktop.dbus.DBusSignal;
+import org.freedesktop.dbus.Position;
+import org.freedesktop.dbus.Struct;
+import org.freedesktop.dbus.Tuple;
+import org.freedesktop.dbus.UInt16;
+import org.freedesktop.dbus.UInt32;
+import org.freedesktop.dbus.UInt64;
+import org.freedesktop.dbus.Variant;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.Map;
+
+public interface DBus extends DBusInterface {
+ public static final int DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x01;
+ public static final int DBUS_NAME_FLAG_REPLACE_EXISTING = 0x02;
+ public static final int DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x04;
+ public static final int DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1;
+ public static final int DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2;
+ public static final int DBUS_REQUEST_NAME_REPLY_EXISTS = 3;
+ public static final int DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4;
+ public static final int DBUS_RELEASE_NAME_REPLY_RELEASED = 1;
+ public static final int DBUS_RELEASE_NAME_REPLY_NON_EXISTANT = 2;
+ public static final int DBUS_RELEASE_NAME_REPLY_NOT_OWNER = 3;
+ public static final int DBUS_START_REPLY_SUCCESS = 1;
+ public static final int DBUS_START_REPLY_ALREADY_RUNNING = 2;
+
+ /**
+ * All DBus Applications should respond to the Ping method on this interface
+ */
+ public interface Peer extends DBusInterface {
+ public void Ping();
+ }
+
+ /**
+ * Objects can provide introspection data via this interface and method.
+ * See the <a href="http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format">Introspection Format</a>.
+ */
+ public interface Introspectable extends DBusInterface {
+ /**
+ * @return The XML introspection data for this object
+ */
+ public String Introspect();
+ }
+
+ /**
+ * A standard properties interface.
+ */
+ public interface Properties extends DBusInterface {
+ /**
+ * Get the value for the given property.
+ *
+ * @param interface_name The interface this property is associated with.
+ * @param property_name The name of the property.
+ * @return The value of the property (may be any valid DBus type).
+ */
+ public <A> A Get(String interface_name, String property_name);
+
+ /**
+ * Set the value for the given property.
+ *
+ * @param interface_name The interface this property is associated with.
+ * @param property_name The name of the property.
+ * @param value The new value of the property (may be any valid DBus type).
+ */
+ public <A> void Set(String interface_name, String property_name, A value);
+
+ /**
+ * Get all properties and values.
+ *
+ * @param interface_name The interface the properties is associated with.
+ * @return The properties mapped to their values.
+ */
+ public Map<String, Variant> GetAll(String interface_name);
+ }
+
+ /**
+ * Messages generated locally in the application.
+ */
+ public interface Local extends DBusInterface {
+ public class Disconnected extends DBusSignal {
+ public Disconnected(String path) throws DBusException {
+ super(path);
+ }
+ }
+ }
+
+ /**
+ * Initial message to register ourselves on the Bus.
+ *
+ * @return The unique name of this connection to the Bus.
+ */
+ public String Hello();
+
+ /**
+ * Lists all connected names on the Bus.
+ *
+ * @return An array of all connected names.
+ */
+ public String[] ListNames();
+
+ /**
+ * Determine if a name has an owner.
+ *
+ * @param name The name to query.
+ * @return true if the name has an owner.
+ */
+ public boolean NameHasOwner(String name);
+
+ /**
+ * Get the connection unique name that owns the given name.
+ *
+ * @param name The name to query.
+ * @return The connection which owns the name.
+ */
+ public String GetNameOwner(String name);
+
+ /**
+ * Get the Unix UID that owns a connection name.
+ *
+ * @param connection_name The connection name.
+ * @return The Unix UID that owns it.
+ */
+ public UInt32 GetConnectionUnixUser(String connection_name);
+
+ /**
+ * Start a service. If the given service is not provided
+ * by any application, it will be started according to the .service file
+ * for that service.
+ *
+ * @param name The service name to start.
+ * @param flags Unused.
+ * @return DBUS_START_REPLY constants.
+ */
+ public UInt32 StartServiceByName(String name, UInt32 flags);
+
+ /**
+ * Request a name on the bus.
+ *
+ * @param name The name to request.
+ * @param flags DBUS_NAME flags.
+ * @return DBUS_REQUEST_NAME_REPLY constants.
+ */
+ public UInt32 RequestName(String name, UInt32 flags);
+
+ /**
+ * Release a name on the bus.
+ *
+ * @param name The name to release.
+ * @return DBUS_RELEASE_NAME_REPLY constants.
+ */
+ public UInt32 ReleaseName(String name);
+
+ /**
+ * Add a match rule.
+ * Will cause you to receive messages that aren't directed to you which
+ * match this rule.
+ *
+ * @param matchrule The Match rule as a string. Format Undocumented.
+ */
+ public void AddMatch(String matchrule) throws Error.MatchRuleInvalid;
+
+ /**
+ * Remove a match rule.
+ * Will cause you to stop receiving messages that aren't directed to you which
+ * match this rule.
+ *
+ * @param matchrule The Match rule as a string. Format Undocumented.
+ */
+ public void RemoveMatch(String matchrule) throws Error.MatchRuleInvalid;
+
+ /**
+ * List the connections currently queued for a name.
+ *
+ * @param name The name to query
+ * @return A list of unique connection IDs.
+ */
+ public String[] ListQueuedOwners(String name);
+
+ /**
+ * Returns the proccess ID associated with a connection.
+ *
+ * @param connection_name The name of the connection
+ * @return The PID of the connection.
+ */
+ public UInt32 GetConnectionUnixProcessID(String connection_name);
+
+ /**
+ * Does something undocumented.
+ */
+ public Byte[] GetConnectionSELinuxSecurityContext(String a);
+
+ /**
+ * Does something undocumented.
+ */
+ public void ReloadConfig();
+
+ /**
+ * Signal sent when the owner of a name changes
+ */
+ public class NameOwnerChanged extends DBusSignal {
+ public final String name;
+ public final String old_owner;
+ public final String new_owner;
+
+ public NameOwnerChanged(String path, String name, String old_owner, String new_owner) throws DBusException {
+ super(path, new Object[]{name, old_owner, new_owner});
+ this.name = name;
+ this.old_owner = old_owner;
+ this.new_owner = new_owner;
+ }
+ }
+
+ /**
+ * Signal sent to a connection when it loses a name
+ */
+ public class NameLost extends DBusSignal {
+ public final String name;
+
+ public NameLost(String path, String name) throws DBusException {
+ super(path, name);
+ this.name = name;
+ }
+ }
+
+ /**
+ * Signal sent to a connection when it aquires a name
+ */
+ public class NameAcquired extends DBusSignal {
+ public final String name;
+
+ public NameAcquired(String path, String name) throws DBusException {
+ super(path, name);
+ this.name = name;
+ }
+ }
+
+ /**
+ * Contains standard errors that can be thrown from methods.
+ */
+ public interface Error {
+ /**
+ * Thrown if the method called was unknown on the remote object
+ */
+ @SuppressWarnings("serial")
+ public class UnknownMethod extends DBusExecutionException {
+ public UnknownMethod(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Thrown if the object was unknown on a remote connection
+ */
+ @SuppressWarnings("serial")
+ public class UnknownObject extends DBusExecutionException {
+ public UnknownObject(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Thrown if the requested service was not available
+ */
+ @SuppressWarnings("serial")
+ public class ServiceUnknown extends DBusExecutionException {
+ public ServiceUnknown(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Thrown if the match rule is invalid
+ */
+ @SuppressWarnings("serial")
+ public class MatchRuleInvalid extends DBusExecutionException {
+ public MatchRuleInvalid(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Thrown if there is no reply to a method call
+ */
+ @SuppressWarnings("serial")
+ public class NoReply extends DBusExecutionException {
+ public NoReply(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Thrown if a message is denied due to a security policy
+ */
+ @SuppressWarnings("serial")
+ public class AccessDenied extends DBusExecutionException {
+ public AccessDenied(String message) {
+ super(message);
+ }
+ }
+ }
+
+ /**
+ * Description of the interface or method, returned in the introspection data
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Description {
+ String value();
+ }
+
+ /**
+ * Indicates that a DBus interface or method is deprecated
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Deprecated {
+ }
+
+ /**
+ * Contains method-specific annotations
+ */
+ public interface Method {
+ /**
+ * Methods annotated with this do not send a reply
+ */
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface NoReply {
+ }
+
+ /**
+ * Give an error that the method can return
+ */
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Error {
+ String value();
+ }
+ }
+
+ /**
+ * Contains GLib-specific annotations
+ */
+ public interface GLib {
+ /**
+ * Define a C symbol to map to this method. Used by GLib only
+ */
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface CSymbol {
+ String value();
+ }
+ }
+
+ /**
+ * Contains Binding-test interfaces
+ */
+ public interface Binding {
+ public interface SingleTests extends DBusInterface {
+ @Description("Returns the sum of the values in the input list")
+ public UInt32 Sum(byte[] a);
+ }
+
+ public interface TestClient extends DBusInterface {
+ @Description("when the trigger signal is received, this method should be called on the sending process/object.")
+ public void Response(UInt16 a, double b);
+
+ @Description("Causes a callback")
+ public static class Trigger extends DBusSignal {
+ public final UInt16 a;
+ public final double b;
+
+ public Trigger(String path, UInt16 a, double b) throws DBusException {
+ super(path, a, b);
+ this.a = a;
+ this.b = b;
+ }
+ }
+
+ }
+
+ public interface Tests extends DBusInterface {
+ @Description("Returns whatever it is passed")
+ public <T> Variant<T> Identity(Variant<T> input);
+
+ @Description("Returns whatever it is passed")
+ public byte IdentityByte(byte input);
+
+ @Description("Returns whatever it is passed")
+ public boolean IdentityBool(boolean input);
+
+ @Description("Returns whatever it is passed")
+ public short IdentityInt16(short input);
+
+ @Description("Returns whatever it is passed")
+ public UInt16 IdentityUInt16(UInt16 input);
+
+ @Description("Returns whatever it is passed")
+ public int IdentityInt32(int input);
+
+ @Description("Returns whatever it is passed")
+ public UInt32 IdentityUInt32(UInt32 input);
+
+ @Description("Returns whatever it is passed")
+ public long IdentityInt64(long input);
+
+ @Description("Returns whatever it is passed")
+ public UInt64 IdentityUInt64(UInt64 input);
+
+ @Description("Returns whatever it is passed")
+ public double IdentityDouble(double input);
+
+ @Description("Returns whatever it is passed")
+ public String IdentityString(String input);
+
+ @Description("Returns whatever it is passed")
+ public <T> Variant<T>[] IdentityArray(Variant<T>[] input);
+
+ @Description("Returns whatever it is passed")
+ public byte[] IdentityByteArray(byte[] input);
+
+ @Description("Returns whatever it is passed")
+ public boolean[] IdentityBoolArray(boolean[] input);
+
+ @Description("Returns whatever it is passed")
+ public short[] IdentityInt16Array(short[] input);
+
+ @Description("Returns whatever it is passed")
+ public UInt16[] IdentityUInt16Array(UInt16[] input);
+
+ @Description("Returns whatever it is passed")
+ public int[] IdentityInt32Array(int[] input);
+
+ @Description("Returns whatever it is passed")
+ public UInt32[] IdentityUInt32Array(UInt32[] input);
+
+ @Description("Returns whatever it is passed")
+ public long[] IdentityInt64Array(long[] input);
+
+ @Description("Returns whatever it is passed")
+ public UInt64[] IdentityUInt64Array(UInt64[] input);
+
+ @Description("Returns whatever it is passed")
+ public double[] IdentityDoubleArray(double[] input);
+
+ @Description("Returns whatever it is passed")
+ public String[] IdentityStringArray(String[] input);
+
+ @Description("Returns the sum of the values in the input list")
+ public long Sum(int[] a);
+
+ @Description("Given a map of A => B, should return a map of B => a list of all the As which mapped to B")
+ public Map<String, List<String>> InvertMapping(Map<String, String> a);
+
+ @Description("This method returns the contents of a struct as separate values")
+ public Triplet<String, UInt32, Short> DeStruct(TestStruct a);
+
+ @Description("Given any compound type as a variant, return all the primitive types recursively contained within as an array of variants")
+ public List<Variant<Object>> Primitize(Variant<Object> a);
+
+ @Description("inverts it's input")
+ public boolean Invert(boolean a);
+
+ @Description("triggers sending of a signal from the supplied object with the given parameter")
+ public void Trigger(String a, UInt64 b);
+
+ @Description("Causes the server to exit")
+ public void Exit();
+ }
+
+ public interface TestSignals extends DBusInterface {
+ @Description("Sent in response to a method call")
+ public static class Triggered extends DBusSignal {
+ public final UInt64 a;
+
+ public Triggered(String path, UInt64 a) throws DBusException {
+ super(path, a);
+ this.a = a;
+ }
+ }
+ }
+
+ public final class Triplet<A, B, C> extends Tuple {
+ @Position(0)
+ public final A a;
+ @Position(1)
+ public final B b;
+ @Position(2)
+ public final C c;
+
+ public Triplet(A a, B b, C c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+ }
+
+ public final class TestStruct extends Struct {
+ @Position(0)
+ public final String a;
+ @Position(1)
+ public final UInt32 b;
+ @Position(2)
+ public final Short c;
+
+ public TestStruct(String a, UInt32 b, Short c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+ }
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/AbstractConnection.java b/federation/sssd/src/main/java/org/freedesktop/dbus/AbstractConnection.java
new file mode 100644
index 0000000..d1d7f51
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/AbstractConnection.java
@@ -0,0 +1,1059 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.FatalDBusException;
+import org.freedesktop.dbus.exceptions.FatalException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+import java.util.regex.Pattern;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+
+/**
+ * Handles a connection to DBus.
+ */
+public abstract class AbstractConnection {
+ protected class FallbackContainer {
+ private Map<String[], ExportedObject> fallbacks = new HashMap<String[], ExportedObject>();
+
+ public synchronized void add(String path, ExportedObject eo) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Adding fallback on " + path + " of " + eo);
+ fallbacks.put(path.split("/"), eo);
+ }
+
+ public synchronized void remove(String path) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Removing fallback on " + path);
+ fallbacks.remove(path.split("/"));
+ }
+
+ public synchronized ExportedObject get(String path) {
+ int best = 0;
+ int i = 0;
+ ExportedObject bestobject = null;
+ String[] pathel = path.split("/");
+ for (String[] fbpath : fallbacks.keySet()) {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Trying fallback path " + Arrays.deepToString(fbpath) + " to match " + Arrays.deepToString(pathel));
+ for (i = 0; i < pathel.length && i < fbpath.length; i++)
+ if (!pathel[i].equals(fbpath[i])) break;
+ if (i > 0 && i == fbpath.length && i > best)
+ bestobject = fallbacks.get(fbpath);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Matches " + i + " bestobject now " + bestobject);
+ }
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Found fallback for " + path + " of " + bestobject);
+ return bestobject;
+ }
+ }
+
+ protected class _thread extends Thread {
+ public _thread() {
+ setName("DBusConnection");
+ }
+
+ public void run() {
+ try {
+ Message m = null;
+ while (_run) {
+ m = null;
+
+ // read from the wire
+ try {
+ // this blocks on outgoing being non-empty or a message being available.
+ m = readIncoming();
+ if (m != null) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Got Incoming Message: " + m);
+ synchronized (this) {
+ notifyAll();
+ }
+
+ if (m instanceof DBusSignal)
+ handleMessage((DBusSignal) m);
+ else if (m instanceof MethodCall)
+ handleMessage((MethodCall) m);
+ else if (m instanceof MethodReturn)
+ handleMessage((MethodReturn) m);
+ else if (m instanceof Error)
+ handleMessage((Error) m);
+
+ m = null;
+ }
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ if (e instanceof FatalException) {
+ disconnect();
+ }
+ }
+
+ }
+ synchronized (this) {
+ notifyAll();
+ }
+ } catch (Exception e) {
+ if (Debug.debug && EXCEPTION_DEBUG) Debug.print(Debug.ERR, e);
+ }
+ }
+ }
+
+ private class _globalhandler implements org.freedesktop.DBus.Peer, org.freedesktop.DBus.Introspectable {
+ private String objectpath;
+
+ public _globalhandler() {
+ this.objectpath = null;
+ }
+
+ public _globalhandler(String objectpath) {
+ this.objectpath = objectpath;
+ }
+
+ public boolean isRemote() {
+ return false;
+ }
+
+ public void Ping() {
+ return;
+ }
+
+ public String Introspect() {
+ String intro = objectTree.Introspect(objectpath);
+ if (null == intro) {
+ ExportedObject eo = fallbackcontainer.get(objectpath);
+ if (null != eo) intro = eo.introspectiondata;
+ }
+ if (null == intro)
+ throw new DBus.Error.UnknownObject("Introspecting on non-existant object");
+ else return
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" " +
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" + intro;
+ }
+ }
+
+ protected class _workerthread extends Thread {
+ private boolean _run = true;
+
+ public void halt() {
+ _run = false;
+ }
+
+ public void run() {
+ while (_run) {
+ Runnable r = null;
+ synchronized (runnables) {
+ while (runnables.size() == 0 && _run)
+ try {
+ runnables.wait();
+ } catch (InterruptedException Ie) {
+ }
+ if (runnables.size() > 0)
+ r = runnables.removeFirst();
+ }
+ if (null != r) r.run();
+ }
+ }
+ }
+
+ private class _sender extends Thread {
+ public _sender() {
+ setName("Sender");
+ }
+
+ public void run() {
+ Message m = null;
+
+ if (Debug.debug) Debug.print(Debug.INFO, "Monitoring outbound queue");
+ // block on the outbound queue and send from it
+ while (_run) {
+ if (null != outgoing) synchronized (outgoing) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking");
+ while (outgoing.size() == 0 && _run)
+ try {
+ outgoing.wait();
+ } catch (InterruptedException Ie) {
+ }
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Notified");
+ if (outgoing.size() > 0)
+ m = outgoing.remove();
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Got message: " + m);
+ }
+ if (null != m)
+ sendMessage(m);
+ m = null;
+ }
+
+ if (Debug.debug) Debug.print(Debug.INFO, "Flushing outbound queue and quitting");
+ // flush the outbound queue before disconnect.
+ if (null != outgoing) do {
+ EfficientQueue ogq = outgoing;
+ synchronized (ogq) {
+ outgoing = null;
+ }
+ if (!ogq.isEmpty())
+ m = ogq.remove();
+ else m = null;
+ sendMessage(m);
+ } while (null != m);
+
+ // close the underlying streams
+ }
+ }
+
+ /**
+ * Timeout in us on checking the BUS for incoming messages and sending outgoing messages
+ */
+ protected static final int TIMEOUT = 100000;
+ /**
+ * Initial size of the pending calls map
+ */
+ private static final int PENDING_MAP_INITIAL_SIZE = 10;
+ static final String BUSNAME_REGEX = "^[-_a-zA-Z][-_a-zA-Z0-9]*(\\.[-_a-zA-Z][-_a-zA-Z0-9]*)*$";
+ static final String CONNID_REGEX = "^:[0-9]*\\.[0-9]*$";
+ static final String OBJECT_REGEX = "^/([-_a-zA-Z0-9]+(/[-_a-zA-Z0-9]+)*)?$";
+ static final byte THREADCOUNT = 4;
+ static final int MAX_ARRAY_LENGTH = 67108864;
+ static final int MAX_NAME_LENGTH = 255;
+ protected Map<String, ExportedObject> exportedObjects;
+ private ObjectTree objectTree;
+ private _globalhandler _globalhandlerreference;
+ protected Map<DBusInterface, RemoteObject> importedObjects;
+ protected Map<SignalTuple, Vector<DBusSigHandler<? extends DBusSignal>>> handledSignals;
+ protected EfficientMap pendingCalls;
+ protected Map<MethodCall, CallbackHandler<? extends Object>> pendingCallbacks;
+ protected Map<MethodCall, DBusAsyncReply<? extends Object>> pendingCallbackReplys;
+ protected LinkedList<Runnable> runnables;
+ protected LinkedList<_workerthread> workers;
+ protected FallbackContainer fallbackcontainer;
+ protected boolean _run;
+ EfficientQueue outgoing;
+ LinkedList<Error> pendingErrors;
+ private static final Map<Thread, DBusCallInfo> infomap = new HashMap<Thread, DBusCallInfo>();
+ protected _thread thread;
+ protected _sender sender;
+ protected Transport transport;
+ protected String addr;
+ protected boolean weakreferences = false;
+ static final Pattern dollar_pattern = Pattern.compile("[$]");
+ public static final boolean EXCEPTION_DEBUG;
+ static final boolean FLOAT_SUPPORT;
+ protected boolean connected = false;
+
+ static {
+ FLOAT_SUPPORT = (null != System.getenv("DBUS_JAVA_FLOATS"));
+ EXCEPTION_DEBUG = (null != System.getenv("DBUS_JAVA_EXCEPTION_DEBUG"));
+ if (EXCEPTION_DEBUG) {
+ Debug.print("Debugging of internal exceptions enabled");
+ Debug.setThrowableTraces(true);
+ }
+ if (Debug.debug) {
+ File f = new File("debug.conf");
+ if (f.exists()) {
+ Debug.print("Loading debug config file: " + f);
+ try {
+ Debug.loadConfig(f);
+ } catch (IOException IOe) {
+ }
+ } else {
+ Properties p = new Properties();
+ p.setProperty("ALL", "INFO");
+ Debug.print("debug config file " + f + " does not exist, not loading.");
+ }
+ Debug.setHexDump(true);
+ }
+ }
+
+ protected AbstractConnection(String address) throws DBusException {
+ exportedObjects = new HashMap<String, ExportedObject>();
+ importedObjects = new HashMap<DBusInterface, RemoteObject>();
+ _globalhandlerreference = new _globalhandler();
+ synchronized (exportedObjects) {
+ exportedObjects.put(null, new ExportedObject(_globalhandlerreference, weakreferences));
+ }
+ handledSignals = new HashMap<SignalTuple, Vector<DBusSigHandler<? extends DBusSignal>>>();
+ pendingCalls = new EfficientMap(PENDING_MAP_INITIAL_SIZE);
+ outgoing = new EfficientQueue(PENDING_MAP_INITIAL_SIZE);
+ pendingCallbacks = new HashMap<MethodCall, CallbackHandler<? extends Object>>();
+ pendingCallbackReplys = new HashMap<MethodCall, DBusAsyncReply<? extends Object>>();
+ pendingErrors = new LinkedList<Error>();
+ runnables = new LinkedList<Runnable>();
+ workers = new LinkedList<_workerthread>();
+ objectTree = new ObjectTree();
+ fallbackcontainer = new FallbackContainer();
+ synchronized (workers) {
+ for (int i = 0; i < THREADCOUNT; i++) {
+ _workerthread t = new _workerthread();
+ t.start();
+ workers.add(t);
+ }
+ }
+ _run = true;
+ addr = address;
+ }
+
+ protected void listen() {
+ // start listening
+ thread = new _thread();
+ thread.start();
+ sender = new _sender();
+ sender.start();
+ }
+
+ /**
+ * Change the number of worker threads to receive method calls and handle signals.
+ * Default is 4 threads
+ *
+ * @param newcount The new number of worker Threads to use.
+ */
+ public void changeThreadCount(byte newcount) {
+ synchronized (workers) {
+ if (workers.size() > newcount) {
+ int n = workers.size() - newcount;
+ for (int i = 0; i < n; i++) {
+ _workerthread t = workers.removeFirst();
+ t.halt();
+ }
+ } else if (workers.size() < newcount) {
+ int n = newcount - workers.size();
+ for (int i = 0; i < n; i++) {
+ _workerthread t = new _workerthread();
+ t.start();
+ workers.add(t);
+ }
+ }
+ }
+ }
+
+ private void addRunnable(Runnable r) {
+ synchronized (runnables) {
+ runnables.add(r);
+ runnables.notifyAll();
+ }
+ }
+
+ String getExportedObject(DBusInterface i) throws DBusException {
+ synchronized (exportedObjects) {
+ for (String s : exportedObjects.keySet())
+ if (i.equals(exportedObjects.get(s).object.get()))
+ return s;
+ }
+
+ String s = importedObjects.get(i).objectpath;
+ if (null != s) return s;
+
+ throw new DBusException("Not an object exported or imported by this connection");
+ }
+
+ abstract DBusInterface getExportedObject(String source, String path) throws DBusException;
+
+ /**
+ * Returns a structure with information on the current method call.
+ *
+ * @return the DBusCallInfo for this method call, or null if we are not in a method call.
+ */
+ public static DBusCallInfo getCallInfo() {
+ DBusCallInfo info;
+ synchronized (infomap) {
+ info = infomap.get(Thread.currentThread());
+ }
+ return info;
+ }
+
+ /**
+ * If set to true the bus will not hold a strong reference to exported objects.
+ * If they go out of scope they will automatically be unexported from the bus.
+ * The default is to hold a strong reference, which means objects must be
+ * explicitly unexported before they will be garbage collected.
+ */
+ public void setWeakReferences(boolean weakreferences) {
+ this.weakreferences = weakreferences;
+ }
+
+ /**
+ * Export an object so that its methods can be called on DBus.
+ *
+ * @param objectpath The path to the object we are exposing. MUST be in slash-notation, like "/org/freedesktop/Local",
+ * and SHOULD end with a capitalised term. Only one object may be exposed on each path at any one time, but an object
+ * may be exposed on several paths at once.
+ * @param object The object to export.
+ * @throws DBusException If the objectpath is already exporting an object.
+ * or if objectpath is incorrectly formatted,
+ */
+ public void exportObject(String objectpath, DBusInterface object) throws DBusException {
+ if (null == objectpath || "".equals(objectpath))
+ throw new DBusException(getString("missingObjectPath"));
+ if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+ synchronized (exportedObjects) {
+ if (null != exportedObjects.get(objectpath))
+ throw new DBusException(getString("objectAlreadyExported"));
+ ExportedObject eo = new ExportedObject(object, weakreferences);
+ exportedObjects.put(objectpath, eo);
+ objectTree.add(objectpath, eo, eo.introspectiondata);
+ }
+ }
+
+ /**
+ * Export an object as a fallback object.
+ * This object will have it's methods invoked for all paths starting
+ * with this object path.
+ *
+ * @param objectprefix The path below which the fallback handles calls.
+ * MUST be in slash-notation, like "/org/freedesktop/Local",
+ * @param object The object to export.
+ * @throws DBusException If the objectpath is incorrectly formatted,
+ */
+ public void addFallback(String objectprefix, DBusInterface object) throws DBusException {
+ if (null == objectprefix || "".equals(objectprefix))
+ throw new DBusException(getString("missingObjectPath"));
+ if (!objectprefix.matches(OBJECT_REGEX) || objectprefix.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectprefix);
+ ExportedObject eo = new ExportedObject(object, weakreferences);
+ fallbackcontainer.add(objectprefix, eo);
+ }
+
+ /**
+ * Remove a fallback
+ *
+ * @param objectprefix The prefix to remove the fallback for.
+ */
+ public void removeFallback(String objectprefix) {
+ fallbackcontainer.remove(objectprefix);
+ }
+
+ /**
+ * Stop Exporting an object
+ *
+ * @param objectpath The objectpath to stop exporting.
+ */
+ public void unExportObject(String objectpath) {
+ synchronized (exportedObjects) {
+ exportedObjects.remove(objectpath);
+ objectTree.remove(objectpath);
+ }
+ }
+ /**
+ * Return a reference to a remote object.
+ * This method will resolve the well known name (if given) to a unique bus name when you call it.
+ * This means that if a well known name is released by one process and acquired by another calls to
+ * objects gained from this method will continue to operate on the original process.
+ * @param busname The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
+ * or may be a DBus address such as ":1-16".
+ * @param objectpath The path on which the process is exporting the object.$
+ * @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+ * as the interface the remote object is exporting.
+ * @return A reference to a remote object.
+ * @throws ClassCastException If type is not a sub-type of DBusInterface
+ * @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
+ */
+ /**
+ * Send a signal.
+ *
+ * @param signal The signal to send.
+ */
+ public void sendSignal(DBusSignal signal) {
+ queueOutgoing(signal);
+ }
+
+ void queueOutgoing(Message m) {
+ synchronized (outgoing) {
+ if (null == outgoing) return;
+ outgoing.add(m);
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Notifying outgoing thread");
+ outgoing.notifyAll();
+ }
+ }
+
+ /**
+ * Remove a Signal Handler.
+ * Stops listening for this signal.
+ *
+ * @param type The signal to watch for.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ public <T extends DBusSignal> void removeSigHandler(Class<T> type, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ removeSigHandler(new DBusMatchRule(type), handler);
+ }
+
+ /**
+ * Remove a Signal Handler.
+ * Stops listening for this signal.
+ *
+ * @param type The signal to watch for.
+ * @param object The object emitting the signal.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ public <T extends DBusSignal> void removeSigHandler(Class<T> type, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ String objectpath = importedObjects.get(object).objectpath;
+ if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+ removeSigHandler(new DBusMatchRule(type, null, objectpath), handler);
+ }
+
+ protected abstract <T extends DBusSignal> void removeSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException;
+
+ /**
+ * Add a Signal Handler.
+ * Adds a signal handler to call when a signal is received which matches the specified type and name.
+ *
+ * @param type The signal to watch for.
+ * @param handler The handler to call when a signal is received.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends DBusSignal> void addSigHandler(Class<T> type, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ addSigHandler(new DBusMatchRule(type), (DBusSigHandler<? extends DBusSignal>) handler);
+ }
+
+ /**
+ * Add a Signal Handler.
+ * Adds a signal handler to call when a signal is received which matches the specified type, name and object.
+ *
+ * @param type The signal to watch for.
+ * @param object The object from which the signal will be emitted
+ * @param handler The handler to call when a signal is received.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends DBusSignal> void addSigHandler(Class<T> type, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ String objectpath = importedObjects.get(object).objectpath;
+ if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+ addSigHandler(new DBusMatchRule(type, null, objectpath), (DBusSigHandler<? extends DBusSignal>) handler);
+ }
+
+ protected abstract <T extends DBusSignal> void addSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException;
+
+ protected <T extends DBusSignal> void addSigHandlerWithoutMatch(Class<? extends DBusSignal> signal, DBusSigHandler<T> handler) throws DBusException {
+ DBusMatchRule rule = new DBusMatchRule(signal);
+ SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
+ synchronized (handledSignals) {
+ Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
+ if (null == v) {
+ v = new Vector<DBusSigHandler<? extends DBusSignal>>();
+ v.add(handler);
+ handledSignals.put(key, v);
+ } else
+ v.add(handler);
+ }
+ }
+
+ /**
+ * Disconnect from the Bus.
+ */
+ public void disconnect() {
+ connected = false;
+ if (Debug.debug) Debug.print(Debug.INFO, "Sending disconnected signal");
+ try {
+ handleMessage(new org.freedesktop.DBus.Local.Disconnected("/"));
+ } catch (Exception ee) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, ee);
+ }
+
+ if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting Abstract Connection");
+ // run all pending tasks.
+ while (runnables.size() > 0)
+ synchronized (runnables) {
+ runnables.notifyAll();
+ }
+
+ // stop the main thread
+ _run = false;
+
+ // unblock the sending thread.
+ synchronized (outgoing) {
+ outgoing.notifyAll();
+ }
+
+ // disconnect from the trasport layer
+ try {
+ if (null != transport) {
+ transport.disconnect();
+ transport = null;
+ }
+ } catch (IOException IOe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOe);
+ }
+
+ // stop all the workers
+ synchronized (workers) {
+ for (_workerthread t : workers)
+ t.halt();
+ }
+
+ // make sure none are blocking on the runnables queue still
+ synchronized (runnables) {
+ runnables.notifyAll();
+ }
+ }
+
+ public void finalize() {
+ disconnect();
+ }
+
+ /**
+ * Return any DBus error which has been received.
+ *
+ * @return A DBusExecutionException, or null if no error is pending.
+ */
+ public DBusExecutionException getError() {
+ synchronized (pendingErrors) {
+ if (pendingErrors.size() == 0) return null;
+ else
+ return pendingErrors.removeFirst().getException();
+ }
+ }
+
+ /**
+ * Call a method asynchronously and set a callback.
+ * This handler will be called in a separate thread.
+ *
+ * @param object The remote object on which to call the method.
+ * @param m The name of the method on the interface to call.
+ * @param callback The callback handler.
+ * @param parameters The parameters to call the method with.
+ */
+ @SuppressWarnings("unchecked")
+ public <A> void callWithCallback(DBusInterface object, String m, CallbackHandler<A> callback, Object... parameters) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "callWithCallback(" + object + "," + m + ", " + callback);
+ Class[] types = new Class[parameters.length];
+ for (int i = 0; i < parameters.length; i++)
+ types[i] = parameters[i].getClass();
+ RemoteObject ro = importedObjects.get(object);
+
+ try {
+ Method me;
+ if (null == ro.iface)
+ me = object.getClass().getMethod(m, types);
+ else
+ me = ro.iface.getMethod(m, types);
+ RemoteInvocationHandler.executeRemoteMethod(ro, me, this, RemoteInvocationHandler.CALL_TYPE_CALLBACK, callback, parameters);
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ throw DBEe;
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusExecutionException(e.getMessage());
+ }
+ }
+
+ /**
+ * Call a method asynchronously and get a handle with which to get the reply.
+ *
+ * @param object The remote object on which to call the method.
+ * @param m The name of the method on the interface to call.
+ * @param parameters The parameters to call the method with.
+ * @return A handle to the call.
+ */
+ @SuppressWarnings("unchecked")
+ public DBusAsyncReply callMethodAsync(DBusInterface object, String m, Object... parameters) {
+ Class<?>[] types = new Class[parameters.length];
+ for (int i = 0; i < parameters.length; i++)
+ types[i] = parameters[i].getClass();
+ RemoteObject ro = importedObjects.get(object);
+
+ try {
+ Method me;
+ if (null == ro.iface)
+ me = object.getClass().getMethod(m, types);
+ else
+ me = ro.iface.getMethod(m, types);
+ return (DBusAsyncReply) RemoteInvocationHandler.executeRemoteMethod(ro, me, this, RemoteInvocationHandler.CALL_TYPE_ASYNC, null, parameters);
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ throw DBEe;
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusExecutionException(e.getMessage());
+ }
+ }
+
+ private void handleMessage(final MethodCall m) throws DBusException {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming method call: " + m);
+
+ ExportedObject eo = null;
+ Method meth = null;
+ Object o = null;
+
+ if (null == m.getInterface() ||
+ m.getInterface().equals("org.freedesktop.DBus.Peer") ||
+ m.getInterface().equals("org.freedesktop.DBus.Introspectable")) {
+ synchronized (exportedObjects) {
+ eo = exportedObjects.get(null);
+ }
+ if (null != eo && null == eo.object.get()) {
+ unExportObject(null);
+ eo = null;
+ }
+ if (null != eo) {
+ meth = eo.methods.get(new MethodTuple(m.getName(), m.getSig()));
+ }
+ if (null != meth)
+ o = new _globalhandler(m.getPath());
+ else
+ eo = null;
+ }
+ if (null == o) {
+ // now check for specific exported functions
+
+ synchronized (exportedObjects) {
+ eo = exportedObjects.get(m.getPath());
+ }
+ if (null != eo && null == eo.object.get()) {
+ if (Debug.debug) Debug.print(Debug.INFO, "Unexporting " + m.getPath() + " implicitly");
+ unExportObject(m.getPath());
+ eo = null;
+ }
+
+ if (null == eo) {
+ eo = fallbackcontainer.get(m.getPath());
+ }
+
+ if (null == eo) {
+ try {
+ queueOutgoing(new Error(m, new DBus.Error.UnknownObject(m.getPath() + getString("notObjectProvidedByProcess"))));
+ } catch (DBusException DBe) {
+ }
+ return;
+ }
+ if (Debug.debug) {
+ Debug.print(Debug.VERBOSE, "Searching for method " + m.getName() + " with signature " + m.getSig());
+ Debug.print(Debug.VERBOSE, "List of methods on " + eo + ":");
+ for (MethodTuple mt : eo.methods.keySet())
+ Debug.print(Debug.VERBOSE, " " + mt + " => " + eo.methods.get(mt));
+ }
+ meth = eo.methods.get(new MethodTuple(m.getName(), m.getSig()));
+ if (null == meth) {
+ try {
+ queueOutgoing(new Error(m, new DBus.Error.UnknownMethod(MessageFormat.format(getString("methodDoesNotExist"), new Object[]{m.getInterface(), m.getName()}))));
+ } catch (DBusException DBe) {
+ }
+ return;
+ }
+ o = eo.object.get();
+ }
+
+ // now execute it
+ final Method me = meth;
+ final Object ob = o;
+ final boolean noreply = (1 == (m.getFlags() & Message.Flags.NO_REPLY_EXPECTED));
+ final DBusCallInfo info = new DBusCallInfo(m);
+ final AbstractConnection conn = this;
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Adding Runnable for method " + meth);
+ addRunnable(new Runnable() {
+ private boolean run = false;
+
+ public synchronized void run() {
+ if (run) return;
+ run = true;
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Running method " + me + " for remote call");
+ try {
+ Type[] ts = me.getGenericParameterTypes();
+ m.setArgs(Marshalling.deSerializeParameters(m.getParameters(), ts, conn));
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Deserialised " + Arrays.deepToString(m.getParameters()) + " to types " + Arrays.deepToString(ts));
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ try {
+ conn.queueOutgoing(new Error(m, new DBus.Error.UnknownMethod(getString("deSerializationFailure") + e)));
+ } catch (DBusException DBe) {
+ }
+ return;
+ }
+
+ try {
+ synchronized (infomap) {
+ infomap.put(Thread.currentThread(), info);
+ }
+ Object result;
+ try {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Invoking Method: " + me + " on " + ob + " with parameters " + Arrays.deepToString(m.getParameters()));
+ result = me.invoke(ob, m.getParameters());
+ } catch (InvocationTargetException ITe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, ITe.getCause());
+ throw ITe.getCause();
+ }
+ synchronized (infomap) {
+ infomap.remove(Thread.currentThread());
+ }
+ if (!noreply) {
+ MethodReturn reply;
+ if (Void.TYPE.equals(me.getReturnType()))
+ reply = new MethodReturn(m, null);
+ else {
+ StringBuffer sb = new StringBuffer();
+ for (String s : Marshalling.getDBusType(me.getGenericReturnType()))
+ sb.append(s);
+ Object[] nr = Marshalling.convertParameters(new Object[]{result}, new Type[]{me.getGenericReturnType()}, conn);
+
+ reply = new MethodReturn(m, sb.toString(), nr);
+ }
+ conn.queueOutgoing(reply);
+ }
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ try {
+ conn.queueOutgoing(new Error(m, DBEe));
+ } catch (DBusException DBe) {
+ }
+ } catch (Throwable e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ try {
+ conn.queueOutgoing(new Error(m, new DBusExecutionException(MessageFormat.format(getString("errorExecutingMethod"), new Object[]{m.getInterface(), m.getName(), e.getMessage()}))));
+ } catch (DBusException DBe) {
+ }
+ }
+ }
+ });
+ }
+
+ @SuppressWarnings({"unchecked", "deprecation"})
+ private void handleMessage(final DBusSignal s) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming signal: " + s);
+ Vector<DBusSigHandler<? extends DBusSignal>> v = new Vector<DBusSigHandler<? extends DBusSignal>>();
+ synchronized (handledSignals) {
+ Vector<DBusSigHandler<? extends DBusSignal>> t;
+ t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), null, null));
+ if (null != t) v.addAll(t);
+ t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), s.getPath(), null));
+ if (null != t) v.addAll(t);
+ t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), null, s.getSource()));
+ if (null != t) v.addAll(t);
+ t = handledSignals.get(new SignalTuple(s.getInterface(), s.getName(), s.getPath(), s.getSource()));
+ if (null != t) v.addAll(t);
+ }
+ if (0 == v.size()) return;
+ final AbstractConnection conn = this;
+ for (final DBusSigHandler<? extends DBusSignal> h : v) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Adding Runnable for signal " + s + " with handler " + h);
+ addRunnable(new Runnable() {
+ private boolean run = false;
+
+ public synchronized void run() {
+ if (run) return;
+ run = true;
+ try {
+ DBusSignal rs;
+ if (s instanceof DBusSignal.internalsig || s.getClass().equals(DBusSignal.class))
+ rs = s.createReal(conn);
+ else
+ rs = s;
+ ((DBusSigHandler<DBusSignal>) h).handle(rs);
+ } catch (DBusException DBe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ try {
+ conn.queueOutgoing(new Error(s, new DBusExecutionException("Error handling signal " + s.getInterface() + "." + s.getName() + ": " + DBe.getMessage())));
+ } catch (DBusException DBe2) {
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private void handleMessage(final Error err) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming error: " + err);
+ MethodCall m = null;
+ if (null == pendingCalls) return;
+ synchronized (pendingCalls) {
+ if (pendingCalls.contains(err.getReplySerial()))
+ m = pendingCalls.remove(err.getReplySerial());
+ }
+ if (null != m) {
+ m.setReply(err);
+ CallbackHandler cbh = null;
+ DBusAsyncReply asr = null;
+ synchronized (pendingCallbacks) {
+ cbh = pendingCallbacks.remove(m);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, cbh + " = pendingCallbacks.remove(" + m + ")");
+ asr = pendingCallbackReplys.remove(m);
+ }
+ // queue callback for execution
+ if (null != cbh) {
+ final CallbackHandler fcbh = cbh;
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Adding Error Runnable with callback handler " + fcbh);
+ addRunnable(new Runnable() {
+ private boolean run = false;
+
+ public synchronized void run() {
+ if (run) return;
+ run = true;
+ try {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Running Error Callback for " + err);
+ DBusCallInfo info = new DBusCallInfo(err);
+ synchronized (infomap) {
+ infomap.put(Thread.currentThread(), info);
+ }
+
+ fcbh.handleError(err.getException());
+ synchronized (infomap) {
+ infomap.remove(Thread.currentThread());
+ }
+
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ }
+ }
+ });
+ }
+
+ } else
+ synchronized (pendingErrors) {
+ pendingErrors.addLast(err);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void handleMessage(final MethodReturn mr) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Handling incoming method return: " + mr);
+ MethodCall m = null;
+ if (null == pendingCalls) return;
+ synchronized (pendingCalls) {
+ if (pendingCalls.contains(mr.getReplySerial()))
+ m = pendingCalls.remove(mr.getReplySerial());
+ }
+ if (null != m) {
+ m.setReply(mr);
+ mr.setCall(m);
+ CallbackHandler cbh = null;
+ DBusAsyncReply asr = null;
+ synchronized (pendingCallbacks) {
+ cbh = pendingCallbacks.remove(m);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, cbh + " = pendingCallbacks.remove(" + m + ")");
+ asr = pendingCallbackReplys.remove(m);
+ }
+ // queue callback for execution
+ if (null != cbh) {
+ final CallbackHandler fcbh = cbh;
+ final DBusAsyncReply fasr = asr;
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Adding Runnable for method " + fasr.getMethod() + " with callback handler " + fcbh);
+ addRunnable(new Runnable() {
+ private boolean run = false;
+
+ public synchronized void run() {
+ if (run) return;
+ run = true;
+ try {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Running Callback for " + mr);
+ DBusCallInfo info = new DBusCallInfo(mr);
+ synchronized (infomap) {
+ infomap.put(Thread.currentThread(), info);
+ }
+
+ fcbh.handle(RemoteInvocationHandler.convertRV(mr.getSig(), mr.getParameters(), fasr.getMethod(), fasr.getConnection()));
+ synchronized (infomap) {
+ infomap.remove(Thread.currentThread());
+ }
+
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ }
+ }
+ });
+ }
+
+ } else
+ try {
+ queueOutgoing(new Error(mr, new DBusExecutionException(getString("spuriousReply"))));
+ } catch (DBusException DBe) {
+ }
+ }
+
+ protected void sendMessage(Message m) {
+ try {
+ if (!connected) throw new NotConnected(getString("disconnected"));
+ if (m instanceof DBusSignal)
+ ((DBusSignal) m).appendbody(this);
+
+ if (m instanceof MethodCall) {
+ if (0 == (m.getFlags() & Message.Flags.NO_REPLY_EXPECTED))
+ if (null == pendingCalls)
+ ((MethodCall) m).setReply(new Error("org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")}));
+ else synchronized (pendingCalls) {
+ pendingCalls.put(m.getSerial(), (MethodCall) m);
+ }
+ }
+
+ transport.mout.writeMessage(m);
+
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ if (m instanceof MethodCall && e instanceof NotConnected)
+ try {
+ ((MethodCall) m).setReply(new Error("org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")}));
+ } catch (DBusException DBe) {
+ }
+ if (m instanceof MethodCall && e instanceof DBusExecutionException)
+ try {
+ ((MethodCall) m).setReply(new Error(m, e));
+ } catch (DBusException DBe) {
+ }
+ else if (m instanceof MethodCall)
+ try {
+ if (Debug.debug) Debug.print(Debug.INFO, "Setting reply to " + m + " as an error");
+ ((MethodCall) m).setReply(new Error(m, new DBusExecutionException(getString("messageFailedSend") + e.getMessage())));
+ } catch (DBusException DBe) {
+ }
+ else if (m instanceof MethodReturn)
+ try {
+ transport.mout.writeMessage(new Error(m, e));
+ } catch (IOException IOe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOe);
+ } catch (DBusException IOe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ }
+ if (e instanceof IOException) disconnect();
+ }
+ }
+
+ private Message readIncoming() throws DBusException {
+ if (!connected) throw new NotConnected(getString("missingTransport"));
+ Message m = null;
+ try {
+ m = transport.min.readMessage();
+ } catch (IOException IOe) {
+ throw new FatalDBusException(IOe.getMessage());
+ }
+ return m;
+ }
+
+ /**
+ * Returns the address this connection is connected to.
+ */
+ public BusAddress getAddress() throws ParseException {
+ return new BusAddress(addr);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ArrayFrob.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ArrayFrob.java
new file mode 100644
index 0000000..86dfa52
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ArrayFrob.java
@@ -0,0 +1,173 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+import java.lang.reflect.Array;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+class ArrayFrob {
+ static Hashtable<Class<? extends Object>, Class<? extends Object>> primitiveToWrapper = new Hashtable<Class<? extends Object>, Class<? extends Object>>();
+ static Hashtable<Class<? extends Object>, Class<? extends Object>> wrapperToPrimitive = new Hashtable<Class<? extends Object>, Class<? extends Object>>();
+
+ static {
+ primitiveToWrapper.put(Boolean.TYPE, Boolean.class);
+ primitiveToWrapper.put(Byte.TYPE, Byte.class);
+ primitiveToWrapper.put(Short.TYPE, Short.class);
+ primitiveToWrapper.put(Character.TYPE, Character.class);
+ primitiveToWrapper.put(Integer.TYPE, Integer.class);
+ primitiveToWrapper.put(Long.TYPE, Long.class);
+ primitiveToWrapper.put(Float.TYPE, Float.class);
+ primitiveToWrapper.put(Double.TYPE, Double.class);
+ wrapperToPrimitive.put(Boolean.class, Boolean.TYPE);
+ wrapperToPrimitive.put(Byte.class, Byte.TYPE);
+ wrapperToPrimitive.put(Short.class, Short.TYPE);
+ wrapperToPrimitive.put(Character.class, Character.TYPE);
+ wrapperToPrimitive.put(Integer.class, Integer.TYPE);
+ wrapperToPrimitive.put(Long.class, Long.TYPE);
+ wrapperToPrimitive.put(Float.class, Float.TYPE);
+ wrapperToPrimitive.put(Double.class, Double.TYPE);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T[] wrap(Object o) throws IllegalArgumentException {
+ Class<? extends Object> ac = o.getClass();
+ if (!ac.isArray()) throw new IllegalArgumentException(getString("invalidArray"));
+ Class<? extends Object> cc = ac.getComponentType();
+ Class<? extends Object> ncc = primitiveToWrapper.get(cc);
+ if (null == ncc) throw new IllegalArgumentException(getString("notPrimitiveType"));
+ T[] ns = (T[]) Array.newInstance(ncc, Array.getLength(o));
+ for (int i = 0; i < ns.length; i++)
+ ns[i] = (T) Array.get(o, i);
+ return ns;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> Object unwrap(T[] ns) throws IllegalArgumentException {
+ Class<? extends T[]> ac = (Class<? extends T[]>) ns.getClass();
+ Class<T> cc = (Class<T>) ac.getComponentType();
+ Class<? extends Object> ncc = wrapperToPrimitive.get(cc);
+ if (null == ncc) throw new IllegalArgumentException(getString("invalidWrapperType"));
+ Object o = Array.newInstance(ncc, ns.length);
+ for (int i = 0; i < ns.length; i++)
+ Array.set(o, i, ns[i]);
+ return o;
+ }
+
+ public static <T> List<T> listify(T[] ns) throws IllegalArgumentException {
+ return Arrays.asList(ns);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> List<T> listify(Object o) throws IllegalArgumentException {
+ if (o instanceof Object[]) return listify((T[]) o);
+ if (!o.getClass().isArray()) throw new IllegalArgumentException(getString("invalidArray"));
+ List<T> l = new ArrayList<T>(Array.getLength(o));
+ for (int i = 0; i < Array.getLength(o); i++)
+ l.add((T) Array.get(o, i));
+ return l;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T[] delist(List<T> l, Class<T> c) throws IllegalArgumentException {
+ return l.toArray((T[]) Array.newInstance(c, 0));
+ }
+
+ public static <T> Object delistprimitive(List<T> l, Class<T> c) throws IllegalArgumentException {
+ Object o = Array.newInstance(c, l.size());
+ for (int i = 0; i < l.size(); i++)
+ Array.set(o, i, l.get(i));
+ return o;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Object convert(Object o, Class<? extends Object> c) throws IllegalArgumentException {
+ /* Possible Conversions:
+ *
+ ** List<Integer> -> List<Integer>
+ ** List<Integer> -> int[]
+ ** List<Integer> -> Integer[]
+ ** int[] -> int[]
+ ** int[] -> List<Integer>
+ ** int[] -> Integer[]
+ ** Integer[] -> Integer[]
+ ** Integer[] -> int[]
+ ** Integer[] -> List<Integer>
+ */
+ try {
+ // List<Integer> -> List<Integer>
+ if (List.class.equals(c)
+ && o instanceof List)
+ return o;
+
+ // int[] -> List<Integer>
+ // Integer[] -> List<Integer>
+ if (List.class.equals(c)
+ && o.getClass().isArray())
+ return listify(o);
+
+ // int[] -> int[]
+ // Integer[] -> Integer[]
+ if (o.getClass().isArray()
+ && c.isArray()
+ && o.getClass().getComponentType().equals(c.getComponentType()))
+ return o;
+
+ // int[] -> Integer[]
+ if (o.getClass().isArray()
+ && c.isArray()
+ && o.getClass().getComponentType().isPrimitive())
+ return wrap(o);
+
+ // Integer[] -> int[]
+ if (o.getClass().isArray()
+ && c.isArray()
+ && c.getComponentType().isPrimitive())
+ return unwrap((Object[]) o);
+
+ // List<Integer> -> int[]
+ if (o instanceof List
+ && c.isArray()
+ && c.getComponentType().isPrimitive())
+ return delistprimitive((List<Object>) o, (Class<Object>) c.getComponentType());
+
+ // List<Integer> -> Integer[]
+ if (o instanceof List
+ && c.isArray())
+ return delist((List<Object>) o, (Class<Object>) c.getComponentType());
+
+ if (o.getClass().isArray()
+ && c.isArray())
+ return type((Object[]) o, (Class<Object>) c.getComponentType());
+
+ } catch (Exception e) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new IllegalArgumentException(e);
+ }
+
+ throw new IllegalArgumentException(MessageFormat.format(getString("convertionTypeNotExpected"), new Object[]{o.getClass(), c}));
+ }
+
+ public static Object[] type(Object[] old, Class<Object> c) {
+ Object[] ns = (Object[]) Array.newInstance(c, old.length);
+ for (int i = 0; i < ns.length; i++)
+ ns[i] = old[i];
+ return ns;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/BusAddress.java b/federation/sssd/src/main/java/org/freedesktop/dbus/BusAddress.java
new file mode 100644
index 0000000..3848951
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/BusAddress.java
@@ -0,0 +1,52 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class BusAddress {
+ private String type;
+ private Map<String, String> parameters;
+
+ public BusAddress(String address) throws ParseException {
+ if (null == address || "".equals(address)) throw new ParseException(getString("busAddressBlank"), 0);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Parsing bus address: " + address);
+ String[] ss = address.split(":", 2);
+ if (ss.length < 2) throw new ParseException(getString("busAddressInvalid") + address, 0);
+ type = ss[0];
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Transport type: " + type);
+ String[] ps = ss[1].split(",");
+ parameters = new HashMap<String, String>();
+ for (String p : ps) {
+ String[] kv = p.split("=", 2);
+ parameters.put(kv[0], kv[1]);
+ }
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Transport options: " + parameters);
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getParameter(String key) {
+ return parameters.get(key);
+ }
+
+ public String toString() {
+ return type + ": " + parameters;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/CallbackHandler.java b/federation/sssd/src/main/java/org/freedesktop/dbus/CallbackHandler.java
new file mode 100644
index 0000000..0e2a81e
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/CallbackHandler.java
@@ -0,0 +1,22 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+/**
+ * Interface for callbacks in async mode
+ */
+public interface CallbackHandler<ReturnType> {
+ public void handle(ReturnType r);
+
+ public void handleError(DBusExecutionException e);
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Container.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Container.java
new file mode 100644
index 0000000..39fd245
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Container.java
@@ -0,0 +1,93 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class is the super class of both Structs and Tuples
+ * and holds common methods.
+ */
+abstract class Container {
+ private static Map<Type, Type[]> typecache = new HashMap<Type, Type[]>();
+
+ static void putTypeCache(Type k, Type[] v) {
+ typecache.put(k, v);
+ }
+
+ static Type[] getTypeCache(Type k) {
+ return typecache.get(k);
+ }
+
+ private Object[] parameters = null;
+
+ public Container() {
+ }
+
+ private void setup() {
+ Field[] fs = getClass().getDeclaredFields();
+ Object[] args = new Object[fs.length];
+
+ int diff = 0;
+ for (Field f : fs) {
+ Position p = f.getAnnotation(Position.class);
+ if (null == p) {
+ diff++;
+ continue;
+ }
+ try {
+ args[p.value()] = f.get(this);
+ } catch (IllegalAccessException IAe) {
+ }
+ }
+
+ this.parameters = new Object[args.length - diff];
+ System.arraycopy(args, 0, parameters, 0, parameters.length);
+ }
+
+ /**
+ * Returns the struct contents in order.
+ *
+ * @throws DBusException If there is a problem doing this.
+ */
+ public final Object[] getParameters() {
+ if (null != parameters) return parameters;
+ setup();
+ return parameters;
+ }
+
+ /**
+ * Returns this struct as a string.
+ */
+ public final String toString() {
+ String s = getClass().getName() + "<";
+ if (null == parameters)
+ setup();
+ if (0 == parameters.length)
+ return s + ">";
+ for (Object o : parameters)
+ s += o + ", ";
+ return s.replaceAll(", $", ">");
+ }
+
+ public final boolean equals(Object other) {
+ if (other instanceof Container) {
+ Container that = (Container) other;
+ if (this.getClass().equals(that.getClass()))
+ return Arrays.equals(this.getParameters(), that.getParameters());
+ else return false;
+ } else return false;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusAsyncReply.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusAsyncReply.java
new file mode 100644
index 0000000..51c2bfd
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusAsyncReply.java
@@ -0,0 +1,117 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus.Error.NoReply;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * A handle to an asynchronous method call.
+ */
+public class DBusAsyncReply<ReturnType> {
+ /**
+ * Check if any of a set of asynchronous calls have had a reply.
+ *
+ * @param replies A Collection of handles to replies to check.
+ * @return A Collection only containing those calls which have had replies.
+ */
+ public static Collection<DBusAsyncReply<? extends Object>> hasReply(Collection<DBusAsyncReply<? extends Object>> replies) {
+ Collection<DBusAsyncReply<? extends Object>> c = new ArrayList<DBusAsyncReply<? extends Object>>(replies);
+ Iterator<DBusAsyncReply<? extends Object>> i = c.iterator();
+ while (i.hasNext())
+ if (!i.next().hasReply()) i.remove();
+ return c;
+ }
+
+ private ReturnType rval = null;
+ private DBusExecutionException error = null;
+ private MethodCall mc;
+ private Method me;
+ private AbstractConnection conn;
+
+ DBusAsyncReply(MethodCall mc, Method me, AbstractConnection conn) {
+ this.mc = mc;
+ this.me = me;
+ this.conn = conn;
+ }
+
+ @SuppressWarnings("unchecked")
+ private synchronized void checkReply() {
+ if (mc.hasReply()) {
+ Message m = mc.getReply();
+ if (m instanceof Error)
+ error = ((Error) m).getException();
+ else if (m instanceof MethodReturn) {
+ try {
+ rval = (ReturnType) RemoteInvocationHandler.convertRV(m.getSig(), m.getParameters(), me, conn);
+ } catch (DBusExecutionException DBEe) {
+ error = DBEe;
+ } catch (DBusException DBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ error = new DBusExecutionException(DBe.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if we've had a reply.
+ *
+ * @return True if we have a reply
+ */
+ public boolean hasReply() {
+ if (null != rval || null != error) return true;
+ checkReply();
+ return null != rval || null != error;
+ }
+
+ /**
+ * Get the reply.
+ *
+ * @return The return value from the method.
+ * @throws DBusExecutionException if the reply to the method was an error.
+ * @throws NoReply if the method hasn't had a reply yet
+ */
+ public ReturnType getReply() throws DBusExecutionException {
+ if (null != rval) return rval;
+ else if (null != error) throw error;
+ checkReply();
+ if (null != rval) return rval;
+ else if (null != error) throw error;
+ else throw new NoReply(getString("asyncCallNoReply"));
+ }
+
+ public String toString() {
+ return getString("waitingFor") + mc;
+ }
+
+ Method getMethod() {
+ return me;
+ }
+
+ AbstractConnection getConnection() {
+ return conn;
+ }
+
+ MethodCall getCall() {
+ return mc;
+ }
+}
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusCallInfo.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusCallInfo.java
new file mode 100644
index 0000000..1c9d143
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusCallInfo.java
@@ -0,0 +1,79 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Holds information on a method call
+ */
+public class DBusCallInfo {
+ /**
+ * Indicates the caller won't wait for a reply (and we won't send one).
+ */
+ public static final int NO_REPLY = Message.Flags.NO_REPLY_EXPECTED;
+ public static final int ASYNC = 0x100;
+ private String source;
+ private String destination;
+ private String objectpath;
+ private String iface;
+ private String method;
+ private int flags;
+
+ DBusCallInfo(Message m) {
+ this.source = m.getSource();
+ this.destination = m.getDestination();
+ this.objectpath = m.getPath();
+ this.iface = m.getInterface();
+ this.method = m.getName();
+ this.flags = m.getFlags();
+ }
+
+ /**
+ * Returns the BusID which called the method
+ */
+ public String getSource() {
+ return source;
+ }
+
+ /**
+ * Returns the name with which we were addressed on the Bus
+ */
+ public String getDestination() {
+ return destination;
+ }
+
+ /**
+ * Returns the object path used to call this method
+ */
+ public String getObjectPath() {
+ return objectpath;
+ }
+
+ /**
+ * Returns the interface this method was called with
+ */
+ public String getInterface() {
+ return iface;
+ }
+
+ /**
+ * Returns the method name used to call this method
+ */
+ public String getMethod() {
+ return method;
+ }
+
+ /**
+ * Returns any flags set on this method call
+ */
+ public int getFlags() {
+ return flags;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusConnection.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusConnection.java
new file mode 100644
index 0000000..45e33a4
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusConnection.java
@@ -0,0 +1,794 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Proxy;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Handles a connection to DBus.
+ * <p>
+ * This is a Singleton class, only 1 connection to the SYSTEM or SESSION busses can be made.
+ * Repeated calls to getConnection will return the same reference.
+ * </p>
+ * <p>
+ * Signal Handlers and method calls from remote objects are run in their own threads, you MUST handle the concurrency issues.
+ * </p>
+ */
+public class DBusConnection extends AbstractConnection {
+ /**
+ * Add addresses of peers to a set which will watch for them to
+ * disappear and automatically remove them from the set.
+ */
+ public class PeerSet implements Set<String>, DBusSigHandler<DBus.NameOwnerChanged> {
+ private Set<String> addresses;
+
+ public PeerSet() {
+ addresses = new TreeSet<String>();
+ try {
+ addSigHandler(new DBusMatchRule(DBus.NameOwnerChanged.class, null, null), this);
+ } catch (DBusException DBe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ }
+ }
+
+ public void handle(DBus.NameOwnerChanged noc) {
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Received NameOwnerChanged(" + noc.name + "," + noc.old_owner + "," + noc.new_owner + ")");
+ if ("".equals(noc.new_owner) && addresses.contains(noc.name))
+ remove(noc.name);
+ }
+
+ public boolean add(String address) {
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Adding " + address);
+ synchronized (addresses) {
+ return addresses.add(address);
+ }
+ }
+
+ public boolean addAll(Collection<? extends String> addresses) {
+ synchronized (this.addresses) {
+ return this.addresses.addAll(addresses);
+ }
+ }
+
+ public void clear() {
+ synchronized (addresses) {
+ addresses.clear();
+ }
+ }
+
+ public boolean contains(Object o) {
+ return addresses.contains(o);
+ }
+
+ public boolean containsAll(Collection<?> os) {
+ return addresses.containsAll(os);
+ }
+
+ public boolean equals(Object o) {
+ if (o instanceof PeerSet)
+ return ((PeerSet) o).addresses.equals(addresses);
+ else return false;
+ }
+
+ public int hashCode() {
+ return addresses.hashCode();
+ }
+
+ public boolean isEmpty() {
+ return addresses.isEmpty();
+ }
+
+ public Iterator<String> iterator() {
+ return addresses.iterator();
+ }
+
+ public boolean remove(Object o) {
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Removing " + o);
+ synchronized (addresses) {
+ return addresses.remove(o);
+ }
+ }
+
+ public boolean removeAll(Collection<?> os) {
+ synchronized (addresses) {
+ return addresses.removeAll(os);
+ }
+ }
+
+ public boolean retainAll(Collection<?> os) {
+ synchronized (addresses) {
+ return addresses.retainAll(os);
+ }
+ }
+
+ public int size() {
+ return addresses.size();
+ }
+
+ public Object[] toArray() {
+ synchronized (addresses) {
+ return addresses.toArray();
+ }
+ }
+
+ public <T> T[] toArray(T[] a) {
+ synchronized (addresses) {
+ return addresses.toArray(a);
+ }
+ }
+ }
+
+ private class _sighandler implements DBusSigHandler<DBusSignal> {
+ public void handle(DBusSignal s) {
+ if (s instanceof org.freedesktop.DBus.Local.Disconnected) {
+ if (Debug.debug) Debug.print(Debug.WARN, "Handling disconnected signal from bus");
+ try {
+ Error err = new Error(
+ "org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")});
+ if (null != pendingCalls) synchronized (pendingCalls) {
+ long[] set = pendingCalls.getKeys();
+ for (long l : set)
+ if (-1 != l) {
+ MethodCall m = pendingCalls.remove(l);
+ if (null != m)
+ m.setReply(err);
+ }
+ }
+ synchronized (pendingErrors) {
+ pendingErrors.add(err);
+ }
+ } catch (DBusException DBe) {
+ }
+ } else if (s instanceof org.freedesktop.DBus.NameAcquired) {
+ busnames.add(((org.freedesktop.DBus.NameAcquired) s).name);
+ }
+ }
+ }
+
+ /**
+ * System Bus
+ */
+ public static final int SYSTEM = 0;
+ /**
+ * Session Bus
+ */
+ public static final int SESSION = 1;
+
+ public static final String DEFAULT_SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket";
+
+ private List<String> busnames;
+
+ private static final Map<Object, DBusConnection> conn = new HashMap<Object, DBusConnection>();
+ private int _refcount = 0;
+ private Object _reflock = new Object();
+ private DBus _dbus;
+
+ /**
+ * Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
+ *
+ * @param address The address of the bus to connect to
+ * @throws DBusException If there is a problem connecting to the Bus.
+ */
+ public static DBusConnection getConnection(String address) throws DBusException {
+ synchronized (conn) {
+ DBusConnection c = conn.get(address);
+ if (null != c) {
+ synchronized (c._reflock) {
+ c._refcount++;
+ }
+ return c;
+ } else {
+ c = new DBusConnection(address);
+ conn.put(address, c);
+ return c;
+ }
+ }
+ }
+
+ /**
+ * Connect to the BUS. If a connection already exists to the specified Bus, a reference to it is returned.
+ *
+ * @param bustype The Bus to connect to.
+ * @throws DBusException If there is a problem connecting to the Bus.
+ * @see #SYSTEM
+ * @see #SESSION
+ */
+ public static DBusConnection getConnection(int bustype) throws DBusException {
+ synchronized (conn) {
+ String s = null;
+ switch (bustype) {
+ case SYSTEM:
+ s = System.getenv("DBUS_SYSTEM_BUS_ADDRESS");
+ if (null == s) s = DEFAULT_SYSTEM_BUS_ADDRESS;
+ break;
+ case SESSION:
+ s = System.getenv("DBUS_SESSION_BUS_ADDRESS");
+ if (null == s) {
+ // address gets stashed in $HOME/.dbus/session-bus/`dbus-uuidgen --get`-`sed 's/:\(.\)\..*/\1/' <<< $DISPLAY`
+ String display = System.getenv("DISPLAY");
+ if (null == display) throw new DBusException(getString("cannotResolveSessionBusAddress"));
+ File uuidfile = new File("/var/lib/dbus/machine-id");
+ if (!uuidfile.exists()) throw new DBusException(getString("cannotResolveSessionBusAddress"));
+ try {
+ BufferedReader r = new BufferedReader(new FileReader(uuidfile));
+ String uuid = r.readLine();
+ String homedir = System.getProperty("user.home");
+ File addressfile = new File(homedir + "/.dbus/session-bus",
+ uuid + "-" + display.replaceAll(":([0-9]*)\\..*", "$1"));
+ if (!addressfile.exists())
+ throw new DBusException(getString("cannotResolveSessionBusAddress"));
+ r = new BufferedReader(new FileReader(addressfile));
+ String l;
+ while (null != (l = r.readLine())) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Reading D-Bus session data: " + l);
+ if (l.matches("DBUS_SESSION_BUS_ADDRESS.*")) {
+ s = l.replaceAll("^[^=]*=", "");
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Parsing " + l + " to " + s);
+ }
+ }
+ if (null == s || "".equals(s))
+ throw new DBusException(getString("cannotResolveSessionBusAddress"));
+ if (Debug.debug)
+ Debug.print(Debug.INFO, "Read bus address " + s + " from file " + addressfile.toString());
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusException(getString("cannotResolveSessionBusAddress"));
+ }
+ }
+ break;
+ default:
+ throw new DBusException(getString("invalidBusType") + bustype);
+ }
+ DBusConnection c = conn.get(s);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Getting bus connection for " + s + ": " + c);
+ if (null != c) {
+ synchronized (c._reflock) {
+ c._refcount++;
+ }
+ return c;
+ } else {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Creating new bus connection to: " + s);
+ c = new DBusConnection(s);
+ conn.put(s, c);
+ return c;
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private DBusConnection(String address) throws DBusException {
+ super(address);
+ busnames = new Vector<String>();
+
+ synchronized (_reflock) {
+ _refcount = 1;
+ }
+
+ try {
+ transport = new Transport(addr, AbstractConnection.TIMEOUT);
+ connected = true;
+ } catch (IOException IOe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOe);
+ disconnect();
+ throw new DBusException(getString("connectionFailure") + IOe.getMessage());
+ } catch (ParseException Pe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, Pe);
+ disconnect();
+ throw new DBusException(getString("connectionFailure") + Pe.getMessage());
+ }
+
+ // start listening for calls
+ listen();
+
+ // register disconnect handlers
+ DBusSigHandler h = new _sighandler();
+ addSigHandlerWithoutMatch(org.freedesktop.DBus.Local.Disconnected.class, h);
+ addSigHandlerWithoutMatch(org.freedesktop.DBus.NameAcquired.class, h);
+
+ // register ourselves
+ _dbus = getRemoteObject("org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
+ try {
+ busnames.add(_dbus.Hello());
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ throw new DBusException(DBEe.getMessage());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ DBusInterface dynamicProxy(String source, String path) throws DBusException {
+ if (Debug.debug)
+ Debug.print(Debug.INFO, "Introspecting " + path + " on " + source + " for dynamic proxy creation");
+ try {
+ DBus.Introspectable intro = getRemoteObject(source, path, DBus.Introspectable.class);
+ String data = intro.Introspect();
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Got introspection data: " + data);
+ String[] tags = data.split("[<>]");
+ Vector<String> ifaces = new Vector<String>();
+ for (String tag : tags) {
+ if (tag.startsWith("interface")) {
+ ifaces.add(tag.replaceAll("^interface *name *= *['\"]([^'\"]*)['\"].*$", "$1"));
+ }
+ }
+ Vector<Class<? extends Object>> ifcs = new Vector<Class<? extends Object>>();
+ for (String iface : ifaces) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Trying interface " + iface);
+ int j = 0;
+ while (j >= 0) {
+ try {
+ Class ifclass = Class.forName(iface);
+ if (!ifcs.contains(ifclass))
+ ifcs.add(ifclass);
+ break;
+ } catch (Exception e) {
+ }
+ j = iface.lastIndexOf(".");
+ char[] cs = iface.toCharArray();
+ if (j >= 0) {
+ cs[j] = '$';
+ iface = String.valueOf(cs);
+ }
+ }
+ }
+
+ if (ifcs.size() == 0) throw new DBusException(getString("interfaceToCastNotFound"));
+
+ RemoteObject ro = new RemoteObject(source, path, null, false);
+ DBusInterface newi = (DBusInterface)
+ Proxy.newProxyInstance(ifcs.get(0).getClassLoader(),
+ ifcs.toArray(new Class[0]),
+ new RemoteInvocationHandler(this, ro));
+ importedObjects.put(newi, ro);
+ return newi;
+ } catch (Exception e) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusException(MessageFormat.format(getString("createProxyExportFailure"), new Object[]{path, source, e.getMessage()}));
+ }
+ }
+
+ DBusInterface getExportedObject(String source, String path) throws DBusException {
+ ExportedObject o = null;
+ synchronized (exportedObjects) {
+ o = exportedObjects.get(path);
+ }
+ if (null != o && null == o.object.get()) {
+ unExportObject(path);
+ o = null;
+ }
+ if (null != o) return o.object.get();
+ if (null == source) throw new DBusException(getString("objectNotExportedNoRemoteSpecified"));
+ return dynamicProxy(source, path);
+ }
+
+ /**
+ * Release a bus name.
+ * Releases the name so that other people can use it
+ *
+ * @param busname The name to release. MUST be in dot-notation like "org.freedesktop.local"
+ * @throws DBusException If the busname is incorrectly formatted.
+ */
+ public void releaseBusName(String busname) throws DBusException {
+ if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName"));
+ synchronized (this.busnames) {
+ UInt32 rv;
+ try {
+ rv = _dbus.ReleaseName(busname);
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ throw new DBusException(DBEe.getMessage());
+ }
+ this.busnames.remove(busname);
+ }
+ }
+
+ /**
+ * Request a bus name.
+ * Request the well known name that this should respond to on the Bus.
+ *
+ * @param busname The name to respond to. MUST be in dot-notation like "org.freedesktop.local"
+ * @throws DBusException If the register name failed, or our name already exists on the bus.
+ * or if busname is incorrectly formatted.
+ */
+ public void requestBusName(String busname) throws DBusException {
+ if (!busname.matches(BUSNAME_REGEX) || busname.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName"));
+ synchronized (this.busnames) {
+ UInt32 rv;
+ try {
+ rv = _dbus.RequestName(busname,
+ new UInt32(DBus.DBUS_NAME_FLAG_REPLACE_EXISTING |
+ DBus.DBUS_NAME_FLAG_DO_NOT_QUEUE));
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ throw new DBusException(DBEe.getMessage());
+ }
+ switch (rv.intValue()) {
+ case DBus.DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+ break;
+ case DBus.DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+ throw new DBusException(getString("dbusRegistrationFailure"));
+ case DBus.DBUS_REQUEST_NAME_REPLY_EXISTS:
+ throw new DBusException(getString("dbusRegistrationFailure"));
+ case DBus.DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+ break;
+ default:
+ break;
+ }
+ this.busnames.add(busname);
+ }
+ }
+
+ /**
+ * Returns the unique name of this connection.
+ */
+ public String getUniqueName() {
+ return busnames.get(0);
+ }
+
+ /**
+ * Returns all the names owned by this connection.
+ */
+ public String[] getNames() {
+ Set<String> names = new TreeSet<String>();
+ names.addAll(busnames);
+ return names.toArray(new String[0]);
+ }
+
+ public <I extends DBusInterface> I getPeerRemoteObject(String busname, String objectpath, Class<I> type) throws DBusException {
+ return getPeerRemoteObject(busname, objectpath, type, true);
+ }
+
+ /**
+ * Return a reference to a remote object.
+ * This method will resolve the well known name (if given) to a unique bus name when you call it.
+ * This means that if a well known name is released by one process and acquired by another calls to
+ * objects gained from this method will continue to operate on the original process.
+ * <p>
+ * This method will use bus introspection to determine the interfaces on a remote object and so
+ * <b>may block</b> and <b>may fail</b>. The resulting proxy object will, however, be castable
+ * to any interface it implements. It will also autostart the process if applicable. Also note
+ * that the resulting proxy may fail to execute the correct method with overloaded methods
+ * and that complex types may fail in interesting ways. Basically, if something odd happens,
+ * try specifying the interface explicitly.
+ *
+ * @param busname The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
+ * or may be a DBus address such as ":1-16".
+ * @param objectpath The path on which the process is exporting the object.$
+ * @return A reference to a remote object.
+ * @throws ClassCastException If type is not a sub-type of DBusInterface
+ * @throws DBusException If busname or objectpath are incorrectly formatted.
+ */
+ public DBusInterface getPeerRemoteObject(String busname, String objectpath) throws DBusException {
+ if (null == busname) throw new DBusException(getString("nullBusName"));
+
+ if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+ || busname.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + busname);
+
+ String unique = _dbus.GetNameOwner(busname);
+
+ return dynamicProxy(unique, objectpath);
+ }
+
+ /**
+ * Return a reference to a remote object.
+ * This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
+ * In particular this means that if a process providing the well known name disappears and is taken over by another process
+ * proxy objects gained by this method will make calls on the new proccess.
+ * <p>
+ * This method will use bus introspection to determine the interfaces on a remote object and so
+ * <b>may block</b> and <b>may fail</b>. The resulting proxy object will, however, be castable
+ * to any interface it implements. It will also autostart the process if applicable. Also note
+ * that the resulting proxy may fail to execute the correct method with overloaded methods
+ * and that complex types may fail in interesting ways. Basically, if something odd happens,
+ * try specifying the interface explicitly.
+ *
+ * @param busname The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
+ * or may be a DBus address such as ":1-16".
+ * @param objectpath The path on which the process is exporting the object.
+ * @return A reference to a remote object.
+ * @throws ClassCastException If type is not a sub-type of DBusInterface
+ * @throws DBusException If busname or objectpath are incorrectly formatted.
+ */
+ public DBusInterface getRemoteObject(String busname, String objectpath) throws DBusException {
+ if (null == busname) throw new DBusException(getString("nullBusName"));
+ if (null == objectpath) throw new DBusException(getString("nullObjectPath"));
+
+ if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+ || busname.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + busname);
+
+ if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+
+ return dynamicProxy(busname, objectpath);
+ }
+
+ /**
+ * Return a reference to a remote object.
+ * This method will resolve the well known name (if given) to a unique bus name when you call it.
+ * This means that if a well known name is released by one process and acquired by another calls to
+ * objects gained from this method will continue to operate on the original process.
+ *
+ * @param busname The bus name to connect to. Usually a well known bus name in dot-notation (such as "org.freedesktop.local")
+ * or may be a DBus address such as ":1-16".
+ * @param objectpath The path on which the process is exporting the object.$
+ * @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+ * as the interface the remote object is exporting.
+ * @param autostart Disable/Enable auto-starting of services in response to calls on this object.
+ * Default is enabled; when calling a method with auto-start enabled, if the destination is a well-known name
+ * and is not owned the bus will attempt to start a process to take the name. When disabled an error is
+ * returned immediately.
+ * @return A reference to a remote object.
+ * @throws ClassCastException If type is not a sub-type of DBusInterface
+ * @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
+ */
+ public <I extends DBusInterface> I getPeerRemoteObject(String busname, String objectpath, Class<I> type, boolean autostart) throws DBusException {
+ if (null == busname) throw new DBusException(getString("nullBusName"));
+
+ if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+ || busname.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + busname);
+
+ String unique = _dbus.GetNameOwner(busname);
+
+ return getRemoteObject(unique, objectpath, type, autostart);
+ }
+
+ /**
+ * Return a reference to a remote object.
+ * This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
+ * In particular this means that if a process providing the well known name disappears and is taken over by another process
+ * proxy objects gained by this method will make calls on the new proccess.
+ *
+ * @param busname The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
+ * or may be a DBus address such as ":1-16".
+ * @param objectpath The path on which the process is exporting the object.
+ * @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+ * as the interface the remote object is exporting.
+ * @return A reference to a remote object.
+ * @throws ClassCastException If type is not a sub-type of DBusInterface
+ * @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
+ */
+ public <I extends DBusInterface> I getRemoteObject(String busname, String objectpath, Class<I> type) throws DBusException {
+ return getRemoteObject(busname, objectpath, type, true);
+ }
+
+ /**
+ * Return a reference to a remote object.
+ * This method will always refer to the well known name (if given) rather than resolving it to a unique bus name.
+ * In particular this means that if a process providing the well known name disappears and is taken over by another process
+ * proxy objects gained by this method will make calls on the new proccess.
+ *
+ * @param busname The bus name to connect to. Usually a well known bus name name in dot-notation (such as "org.freedesktop.local")
+ * or may be a DBus address such as ":1-16".
+ * @param objectpath The path on which the process is exporting the object.
+ * @param type The interface they are exporting it on. This type must have the same full class name and exposed method signatures
+ * as the interface the remote object is exporting.
+ * @param autostart Disable/Enable auto-starting of services in response to calls on this object.
+ * Default is enabled; when calling a method with auto-start enabled, if the destination is a well-known name
+ * and is not owned the bus will attempt to start a process to take the name. When disabled an error is
+ * returned immediately.
+ * @return A reference to a remote object.
+ * @throws ClassCastException If type is not a sub-type of DBusInterface
+ * @throws DBusException If busname or objectpath are incorrectly formatted or type is not in a package.
+ */
+ @SuppressWarnings("unchecked")
+ public <I extends DBusInterface> I getRemoteObject(String busname, String objectpath, Class<I> type, boolean autostart) throws DBusException {
+ if (null == busname) throw new DBusException(getString("nullBusName"));
+ if (null == objectpath) throw new DBusException(getString("nullObjectPath"));
+ if (null == type) throw new ClassCastException(getString("notDBusInterface"));
+
+ if ((!busname.matches(BUSNAME_REGEX) && !busname.matches(CONNID_REGEX))
+ || busname.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + busname);
+
+ if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+
+ if (!DBusInterface.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusInterface"));
+
+ // don't let people import things which don't have a
+ // valid D-Bus interface name
+ if (type.getName().equals(type.getSimpleName()))
+ throw new DBusException(getString("interfaceNotAllowedOutsidePackage"));
+
+ RemoteObject ro = new RemoteObject(busname, objectpath, type, autostart);
+ I i = (I) Proxy.newProxyInstance(type.getClassLoader(),
+ new Class[]{type}, new RemoteInvocationHandler(this, ro));
+ importedObjects.put(i, ro);
+ return i;
+ }
+
+ /**
+ * Remove a Signal Handler.
+ * Stops listening for this signal.
+ *
+ * @param type The signal to watch for.
+ * @param source The source of the signal.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ public <T extends DBusSignal> void removeSigHandler(Class<T> type, String source, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+ if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + source);
+ removeSigHandler(new DBusMatchRule(type, source, null), handler);
+ }
+
+ /**
+ * Remove a Signal Handler.
+ * Stops listening for this signal.
+ *
+ * @param type The signal to watch for.
+ * @param source The source of the signal.
+ * @param object The object emitting the signal.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ public <T extends DBusSignal> void removeSigHandler(Class<T> type, String source, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+ if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + source);
+ String objectpath = importedObjects.get(object).objectpath;
+ if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+ removeSigHandler(new DBusMatchRule(type, source, objectpath), handler);
+ }
+
+ protected <T extends DBusSignal> void removeSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException {
+
+ SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
+ synchronized (handledSignals) {
+ Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
+ if (null != v) {
+ v.remove(handler);
+ if (0 == v.size()) {
+ handledSignals.remove(key);
+ try {
+ _dbus.RemoveMatch(rule.toString());
+ } catch (NotConnected NC) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, NC);
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ throw new DBusException(DBEe.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a Signal Handler.
+ * Adds a signal handler to call when a signal is received which matches the specified type, name and source.
+ *
+ * @param type The signal to watch for.
+ * @param source The process which will send the signal. This <b>MUST</b> be a unique bus name and not a well known name.
+ * @param handler The handler to call when a signal is received.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends DBusSignal> void addSigHandler(Class<T> type, String source, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+ if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + source);
+ addSigHandler(new DBusMatchRule(type, source, null), (DBusSigHandler<? extends DBusSignal>) handler);
+ }
+
+ /**
+ * Add a Signal Handler.
+ * Adds a signal handler to call when a signal is received which matches the specified type, name, source and object.
+ *
+ * @param type The signal to watch for.
+ * @param source The process which will send the signal. This <b>MUST</b> be a unique bus name and not a well known name.
+ * @param object The object from which the signal will be emitted
+ * @param handler The handler to call when a signal is received.
+ * @throws DBusException If listening for the signal on the bus failed.
+ * @throws ClassCastException If type is not a sub-type of DBusSignal.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends DBusSignal> void addSigHandler(Class<T> type, String source, DBusInterface object, DBusSigHandler<T> handler) throws DBusException {
+ if (!DBusSignal.class.isAssignableFrom(type)) throw new ClassCastException(getString("notDBusSignal"));
+ if (source.matches(BUSNAME_REGEX)) throw new DBusException(getString("cannotWatchSignalsWellKnownBussName"));
+ if (!source.matches(CONNID_REGEX) || source.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidBusName") + source);
+ String objectpath = importedObjects.get(object).objectpath;
+ if (!objectpath.matches(OBJECT_REGEX) || objectpath.length() > MAX_NAME_LENGTH)
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+ addSigHandler(new DBusMatchRule(type, source, objectpath), (DBusSigHandler<? extends DBusSignal>) handler);
+ }
+
+ protected <T extends DBusSignal> void addSigHandler(DBusMatchRule rule, DBusSigHandler<T> handler) throws DBusException {
+ try {
+ _dbus.AddMatch(rule.toString());
+ } catch (DBusExecutionException DBEe) {
+ if (EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBEe);
+ throw new DBusException(DBEe.getMessage());
+ }
+ SignalTuple key = new SignalTuple(rule.getInterface(), rule.getMember(), rule.getObject(), rule.getSource());
+ synchronized (handledSignals) {
+ Vector<DBusSigHandler<? extends DBusSignal>> v = handledSignals.get(key);
+ if (null == v) {
+ v = new Vector<DBusSigHandler<? extends DBusSignal>>();
+ v.add(handler);
+ handledSignals.put(key, v);
+ } else
+ v.add(handler);
+ }
+ }
+
+ /**
+ * Disconnect from the Bus.
+ * This only disconnects when the last reference to the bus has disconnect called on it
+ * or has been destroyed.
+ */
+ public void disconnect() {
+ synchronized (conn) {
+ synchronized (_reflock) {
+ if (0 == --_refcount) {
+ if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting DBusConnection");
+ // Set all pending messages to have an error.
+ try {
+ Error err = new Error(
+ "org.freedesktop.DBus.Local", "org.freedesktop.DBus.Local.disconnected", 0, "s", new Object[]{getString("disconnected")});
+ synchronized (pendingCalls) {
+ long[] set = pendingCalls.getKeys();
+ for (long l : set)
+ if (-1 != l) {
+ MethodCall m = pendingCalls.remove(l);
+ if (null != m)
+ m.setReply(err);
+ }
+ pendingCalls = null;
+ }
+ synchronized (pendingErrors) {
+ pendingErrors.add(err);
+ }
+ } catch (DBusException DBe) {
+ }
+
+ conn.remove(addr);
+ super.disconnect();
+ }
+ }
+ }
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterface.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterface.java
new file mode 100644
index 0000000..b9e404c
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterface.java
@@ -0,0 +1,31 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Denotes a class as exportable or a remote interface which can be called.
+ * <p>
+ * Any interface which should be exported or imported should extend this
+ * interface. All public methods from that interface are exported/imported
+ * with the given method signatures.
+ * </p>
+ * <p>
+ * All method calls on exported objects are run in their own threads.
+ * Application writers are responsible for any concurrency issues.
+ * </p>
+ */
+public interface DBusInterface {
+ /**
+ * Returns true on remote objects.
+ * Local objects implementing this interface MUST return false.
+ */
+ public boolean isRemote();
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterfaceName.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterfaceName.java
new file mode 100644
index 0000000..0fc7056
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusInterfaceName.java
@@ -0,0 +1,28 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Force the interface name to be different to the Java class name.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface DBusInterfaceName {
+ /**
+ * The replacement interface name.
+ */
+ String value();
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMap.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMap.java
new file mode 100644
index 0000000..6590e62
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMap.java
@@ -0,0 +1,150 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+class DBusMap<K, V> implements Map<K, V> {
+ Object[][] entries;
+
+ public DBusMap(Object[][] entries) {
+ this.entries = entries;
+ }
+
+ class Entry implements Map.Entry<K, V>, Comparable<Entry> {
+ private int entry;
+
+ public Entry(int i) {
+ this.entry = i;
+ }
+
+ public boolean equals(Object o) {
+ if (null == o) return false;
+ if (!(o instanceof DBusMap.Entry)) return false;
+ return this.entry == ((Entry) o).entry;
+ }
+
+ @SuppressWarnings("unchecked")
+ public K getKey() {
+ return (K) entries[entry][0];
+ }
+
+ @SuppressWarnings("unchecked")
+ public V getValue() {
+ return (V) entries[entry][1];
+ }
+
+ public int hashCode() {
+ return entries[entry][0].hashCode();
+ }
+
+ public V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int compareTo(Entry e) {
+ return entry - e.entry;
+ }
+ }
+
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean containsKey(Object key) {
+ for (int i = 0; i < entries.length; i++)
+ if (key == entries[i][0] || (key != null && key.equals(entries[i][0])))
+ return true;
+ return false;
+ }
+
+ public boolean containsValue(Object value) {
+ for (int i = 0; i < entries.length; i++)
+ if (value == entries[i][1] || (value != null && value.equals(entries[i][1])))
+ return true;
+ return false;
+ }
+
+ public Set<Map.Entry<K, V>> entrySet() {
+ Set<Map.Entry<K, V>> s = new TreeSet<Map.Entry<K, V>>();
+ for (int i = 0; i < entries.length; i++)
+ s.add(new Entry(i));
+ return s;
+ }
+
+ @SuppressWarnings("unchecked")
+ public V get(Object key) {
+ for (int i = 0; i < entries.length; i++)
+ if (key == entries[i][0] || (key != null && key.equals(entries[i][0])))
+ return (V) entries[i][1];
+ return null;
+ }
+
+ public boolean isEmpty() {
+ return entries.length == 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<K> keySet() {
+ Set<K> s = new TreeSet<K>();
+ for (Object[] entry : entries)
+ s.add((K) entry[0]);
+ return s;
+ }
+
+ public V put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void putAll(Map<? extends K, ? extends V> t) {
+ throw new UnsupportedOperationException();
+ }
+
+ public V remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int size() {
+ return entries.length;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection<V> values() {
+ List<V> l = new Vector<V>();
+ for (Object[] entry : entries)
+ l.add((V) entry[1]);
+ return l;
+ }
+
+ public int hashCode() {
+ return Arrays.deepHashCode(entries);
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean equals(Object o) {
+ if (null == o) return false;
+ if (!(o instanceof Map)) return false;
+ return ((Map<K, V>) o).entrySet().equals(entrySet());
+ }
+
+ public String toString() {
+ String s = "{ ";
+ for (int i = 0; i < entries.length; i++)
+ s += entries[i][0] + " => " + entries[i][1] + ",";
+ return s.replaceAll(".$", " }");
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMatchRule.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMatchRule.java
new file mode 100644
index 0000000..fa886c0
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMatchRule.java
@@ -0,0 +1,151 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.util.HashMap;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class DBusMatchRule {
+ /* signal, error, method_call, method_reply */
+ private String type;
+ private String iface;
+ private String member;
+ private String object;
+ private String source;
+ private static HashMap<String, Class<? extends DBusSignal>> signalTypeMap =
+ new HashMap<String, Class<? extends DBusSignal>>();
+
+ static Class<? extends DBusSignal> getCachedSignalType(String type) {
+ return signalTypeMap.get(type);
+ }
+
+ public DBusMatchRule(String type, String iface, String member) {
+ this.type = type;
+ this.iface = iface;
+ this.member = member;
+ }
+
+ public DBusMatchRule(DBusExecutionException e) throws DBusException {
+ this(e.getClass());
+ member = null;
+ type = "error";
+ }
+
+ public DBusMatchRule(Message m) {
+ iface = m.getInterface();
+ member = m.getName();
+ if (m instanceof DBusSignal)
+ type = "signal";
+ else if (m instanceof Error) {
+ type = "error";
+ member = null;
+ } else if (m instanceof MethodCall)
+ type = "method_call";
+ else if (m instanceof MethodReturn)
+ type = "method_reply";
+ }
+
+ public DBusMatchRule(Class<? extends DBusInterface> c, String method) throws DBusException {
+ this(c);
+ member = method;
+ type = "method_call";
+ }
+
+ public DBusMatchRule(Class<? extends Object> c, String source, String object) throws DBusException {
+ this(c);
+ this.source = source;
+ this.object = object;
+ }
+
+ @SuppressWarnings("unchecked")
+ public DBusMatchRule(Class<? extends Object> c) throws DBusException {
+ if (DBusInterface.class.isAssignableFrom(c)) {
+ if (null != c.getAnnotation(DBusInterfaceName.class))
+ iface = c.getAnnotation(DBusInterfaceName.class).value();
+ else
+ iface = AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".");
+ if (!iface.matches(".*\\..*"))
+ throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+ member = null;
+ type = null;
+ } else if (DBusSignal.class.isAssignableFrom(c)) {
+ if (null == c.getEnclosingClass())
+ throw new DBusException(getString("signalsMustBeMemberOfClass"));
+ else if (null != c.getEnclosingClass().getAnnotation(DBusInterfaceName.class))
+ iface = c.getEnclosingClass().getAnnotation(DBusInterfaceName.class).value();
+ else
+ iface = AbstractConnection.dollar_pattern.matcher(c.getEnclosingClass().getName()).replaceAll(".");
+ // Don't export things which are invalid D-Bus interfaces
+ if (!iface.matches(".*\\..*"))
+ throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+ if (c.isAnnotationPresent(DBusMemberName.class))
+ member = c.getAnnotation(DBusMemberName.class).value();
+ else
+ member = c.getSimpleName();
+ signalTypeMap.put(iface + '$' + member, (Class<? extends DBusSignal>) c);
+ type = "signal";
+ } else if (Error.class.isAssignableFrom(c)) {
+ if (null != c.getAnnotation(DBusInterfaceName.class))
+ iface = c.getAnnotation(DBusInterfaceName.class).value();
+ else
+ iface = AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".");
+ if (!iface.matches(".*\\..*"))
+ throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+ member = null;
+ type = "error";
+ } else if (DBusExecutionException.class.isAssignableFrom(c)) {
+ if (null != c.getClass().getAnnotation(DBusInterfaceName.class))
+ iface = c.getClass().getAnnotation(DBusInterfaceName.class).value();
+ else
+ iface = AbstractConnection.dollar_pattern.matcher(c.getClass().getName()).replaceAll(".");
+ if (!iface.matches(".*\\..*"))
+ throw new DBusException(getString("interfaceMustBeDefinedPackage"));
+ member = null;
+ type = "error";
+ } else
+ throw new DBusException(getString("invalidTypeMatchRule") + c);
+ }
+
+ public String toString() {
+ String s = null;
+ if (null != type) s = null == s ? "type='" + type + "'" : s + ",type='" + type + "'";
+ if (null != member) s = null == s ? "member='" + member + "'" : s + ",member='" + member + "'";
+ if (null != iface) s = null == s ? "interface='" + iface + "'" : s + ",interface='" + iface + "'";
+ if (null != source) s = null == s ? "sender='" + source + "'" : s + ",sender='" + source + "'";
+ if (null != object) s = null == s ? "path='" + object + "'" : s + ",path='" + object + "'";
+ return s;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getInterface() {
+ return iface;
+ }
+
+ public String getMember() {
+ return member;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public String getObject() {
+ return object;
+ }
+
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMemberName.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMemberName.java
new file mode 100644
index 0000000..25d30d7
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusMemberName.java
@@ -0,0 +1,29 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Force the member (method/signal) name on the bus to be different to the Java name.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface DBusMemberName {
+ /**
+ * The replacement member name.
+ */
+ String value();
+}
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSerializable.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSerializable.java
new file mode 100644
index 0000000..8d9fea5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSerializable.java
@@ -0,0 +1,39 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+/**
+ * Custom classes may be sent over DBus if they implement this interface.
+ * <p>
+ * In addition to the serialize method, classes <b>MUST</b> implement
+ * a deserialize method which returns null and takes as it's arguments
+ * all the DBus types the class will be serialied to <i>in order</i> and
+ * <i>with type parameterisation</i>. They <b>MUST</b> also provide a
+ * zero-argument constructor.
+ * </p>
+ * <p>
+ * The serialize method should return the class properties you wish to
+ * serialize, correctly formatted for the wire
+ * (DBusConnection.convertParameters() can help with this), in order in an
+ * Object array.
+ * </p>
+ * <p>
+ * The deserialize method will be called once after the zero-argument
+ * constructor. This should contain all the code to initialise the object
+ * from the types.
+ * </p>
+ */
+public interface DBusSerializable {
+ public Object[] serialize() throws DBusException;
+}
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSigHandler.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSigHandler.java
new file mode 100644
index 0000000..6e40a82
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSigHandler.java
@@ -0,0 +1,27 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Handle a signal on DBus.
+ * All Signal handlers are run in their own Thread.
+ * Application writers are responsible for managing any concurrency issues.
+ */
+public interface DBusSigHandler<T extends DBusSignal> {
+ /**
+ * Handle a signal.
+ *
+ * @param s The signal to handle. If such a class exists, the
+ * signal will be an instance of the class with the correct type signature.
+ * Otherwise it will be an instance of DBusSignal
+ */
+ public void handle(T s);
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSignal.java b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSignal.java
new file mode 100644
index 0000000..96ba6b3
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/DBusSignal.java
@@ -0,0 +1,259 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MessageFormatException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class DBusSignal extends Message {
+ DBusSignal() {
+ }
+
+ public DBusSignal(String source, String path, String iface, String member, String sig, Object... args) throws DBusException {
+ super(Message.Endian.BIG, Message.MessageType.SIGNAL, (byte) 0);
+
+ if (null == path || null == member || null == iface)
+ throw new MessageFormatException(getString("missingPathInterfaceSignal"));
+ headers.put(Message.HeaderField.PATH, path);
+ headers.put(Message.HeaderField.MEMBER, member);
+ headers.put(Message.HeaderField.INTERFACE, iface);
+
+ Vector<Object> hargs = new Vector<Object>();
+ hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, path}});
+ hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
+ hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
+
+ if (null != source) {
+ headers.put(Message.HeaderField.SENDER, source);
+ hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+ }
+
+ if (null != sig) {
+ hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+ headers.put(Message.HeaderField.SIGNATURE, sig);
+ setArgs(args);
+ }
+
+ blen = new byte[4];
+ appendBytes(blen);
+ append("ua(yv)", ++serial, hargs.toArray());
+ pad((byte) 8);
+
+ long c = bytecounter;
+ if (null != sig) append(sig, args);
+ marshallint(bytecounter - c, blen, 0, 4);
+ bodydone = true;
+ }
+
+ static class internalsig extends DBusSignal {
+ public internalsig(String source, String objectpath, String type, String name, String sig, Object[] parameters, long serial) throws DBusException {
+ super(source, objectpath, type, name, sig, parameters, serial);
+ }
+ }
+
+ private static Map<Class<? extends DBusSignal>, Type[]> typeCache = new HashMap<Class<? extends DBusSignal>, Type[]>();
+ private static Map<String, Class<? extends DBusSignal>> classCache = new HashMap<String, Class<? extends DBusSignal>>();
+ private static Map<Class<? extends DBusSignal>, Constructor<? extends DBusSignal>> conCache = new HashMap<Class<? extends DBusSignal>, Constructor<? extends DBusSignal>>();
+ private static Map<String, String> signames = new HashMap<String, String>();
+ private static Map<String, String> intnames = new HashMap<String, String>();
+ private Class<? extends DBusSignal> c;
+ private boolean bodydone = false;
+ private byte[] blen;
+
+ static void addInterfaceMap(String java, String dbus) {
+ intnames.put(dbus, java);
+ }
+
+ static void addSignalMap(String java, String dbus) {
+ signames.put(dbus, java);
+ }
+
+ static DBusSignal createSignal(Class<? extends DBusSignal> c, String source, String objectpath, String sig, long serial, Object... parameters) throws DBusException {
+ String type = "";
+ if (null != c.getEnclosingClass()) {
+ if (null != c.getEnclosingClass().getAnnotation(DBusInterfaceName.class))
+ type = c.getEnclosingClass().getAnnotation(DBusInterfaceName.class).value();
+ else
+ type = AbstractConnection.dollar_pattern.matcher(c.getEnclosingClass().getName()).replaceAll(".");
+
+ } else
+ throw new DBusException(getString("signalsMustBeMemberOfClass"));
+ DBusSignal s = new internalsig(source, objectpath, type, c.getSimpleName(), sig, parameters, serial);
+ s.c = c;
+ return s;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class<? extends DBusSignal> createSignalClass(String intname, String signame) throws DBusException {
+ String name = intname + '$' + signame;
+ Class<? extends DBusSignal> c = classCache.get(name);
+ if (null == c) c = DBusMatchRule.getCachedSignalType(name);
+ if (null != c) return c;
+ do {
+ try {
+ c = (Class<? extends DBusSignal>) Class.forName(name);
+ } catch (ClassNotFoundException CNFe) {
+ }
+ name = name.replaceAll("\\.([^\\.]*)$", "\\$$1");
+ } while (null == c && name.matches(".*\\..*"));
+ if (null == c)
+ throw new DBusException(getString("cannotCreateClassFromSignal") + intname + '.' + signame);
+ classCache.put(name, c);
+ return c;
+ }
+
+ @SuppressWarnings("unchecked")
+ DBusSignal createReal(AbstractConnection conn) throws DBusException {
+ String intname = intnames.get(getInterface());
+ String signame = signames.get(getName());
+ if (null == intname) intname = getInterface();
+ if (null == signame) signame = getName();
+ if (null == c)
+ c = createSignalClass(intname, signame);
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Converting signal to type: " + c);
+ Type[] types = typeCache.get(c);
+ Constructor<? extends DBusSignal> con = conCache.get(c);
+ if (null == types) {
+ con = (Constructor<? extends DBusSignal>) c.getDeclaredConstructors()[0];
+ conCache.put(c, con);
+ Type[] ts = con.getGenericParameterTypes();
+ types = new Type[ts.length - 1];
+ for (int i = 1; i < ts.length; i++)
+ if (ts[i] instanceof TypeVariable)
+ for (Type b : ((TypeVariable<GenericDeclaration>) ts[i]).getBounds())
+ types[i - 1] = b;
+ else
+ types[i - 1] = ts[i];
+ typeCache.put(c, types);
+ }
+
+ try {
+ DBusSignal s;
+ Object[] args = Marshalling.deSerializeParameters(getParameters(), types, conn);
+ if (null == args) s = (DBusSignal) con.newInstance(getPath());
+ else {
+ Object[] params = new Object[args.length + 1];
+ params[0] = getPath();
+ System.arraycopy(args, 0, params, 1, args.length);
+
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Creating signal of type " + c + " with parameters " + Arrays.deepToString(params));
+ s = (DBusSignal) con.newInstance(params);
+ }
+ s.headers = headers;
+ s.wiredata = wiredata;
+ s.bytecounter = wiredata.length;
+ return s;
+ } catch (Exception e) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusException(e.getMessage());
+ }
+ }
+
+ /**
+ * Create a new signal.
+ * This contructor MUST be called by all sub classes.
+ *
+ * @param objectpath The path to the object this is emitted from.
+ * @param args The parameters of the signal.
+ * @throws DBusException This is thrown if the subclass is incorrectly defined.
+ */
+ @SuppressWarnings("unchecked")
+ protected DBusSignal(String objectpath, Object... args) throws DBusException {
+ super(Message.Endian.BIG, Message.MessageType.SIGNAL, (byte) 0);
+
+ if (!objectpath.matches(AbstractConnection.OBJECT_REGEX))
+ throw new DBusException(getString("invalidObjectPath") + objectpath);
+
+ Class<? extends DBusSignal> tc = getClass();
+ String member;
+ if (tc.isAnnotationPresent(DBusMemberName.class))
+ member = tc.getAnnotation(DBusMemberName.class).value();
+ else
+ member = tc.getSimpleName();
+ String iface = null;
+ Class<? extends Object> enc = tc.getEnclosingClass();
+ if (null == enc ||
+ !DBusInterface.class.isAssignableFrom(enc) ||
+ enc.getName().equals(enc.getSimpleName()))
+ throw new DBusException(getString("signalsMustBeMemberOfClass"));
+ else if (null != enc.getAnnotation(DBusInterfaceName.class))
+ iface = enc.getAnnotation(DBusInterfaceName.class).value();
+ else
+ iface = AbstractConnection.dollar_pattern.matcher(enc.getName()).replaceAll(".");
+
+ headers.put(Message.HeaderField.PATH, objectpath);
+ headers.put(Message.HeaderField.MEMBER, member);
+ headers.put(Message.HeaderField.INTERFACE, iface);
+
+ Vector<Object> hargs = new Vector<Object>();
+ hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, objectpath}});
+ hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
+ hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
+
+ String sig = null;
+ if (0 < args.length) {
+ try {
+ Type[] types = typeCache.get(tc);
+ if (null == types) {
+ Constructor<? extends DBusSignal> con = (Constructor<? extends DBusSignal>) tc.getDeclaredConstructors()[0];
+ conCache.put(tc, con);
+ Type[] ts = con.getGenericParameterTypes();
+ types = new Type[ts.length - 1];
+ for (int i = 1; i <= types.length; i++)
+ if (ts[i] instanceof TypeVariable)
+ types[i - 1] = ((TypeVariable<GenericDeclaration>) ts[i]).getBounds()[0];
+ else
+ types[i - 1] = ts[i];
+ typeCache.put(tc, types);
+ }
+ sig = Marshalling.getDBusType(types);
+ hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+ headers.put(Message.HeaderField.SIGNATURE, sig);
+ setArgs(args);
+ } catch (Exception e) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusException(getString("errorAddSignalParameters") + e.getMessage());
+ }
+ }
+
+ blen = new byte[4];
+ appendBytes(blen);
+ append("ua(yv)", ++serial, hargs.toArray());
+ pad((byte) 8);
+ }
+
+ void appendbody(AbstractConnection conn) throws DBusException {
+ if (bodydone) return;
+
+ Type[] types = typeCache.get(getClass());
+ Object[] args = Marshalling.convertParameters(getParameters(), types, conn);
+ setArgs(args);
+ String sig = getSig();
+
+ long c = bytecounter;
+ if (null != args && 0 < args.length) append(sig, args);
+ marshallint(bytecounter - c, blen, 0, 4);
+ bodydone = true;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientMap.java b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientMap.java
new file mode 100644
index 0000000..32cc7bb
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientMap.java
@@ -0,0 +1,122 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * Provides a long => MethodCall map which doesn't allocate objects
+ * on insertion/removal. Keys must be inserted in ascending order.
+ */
+class EfficientMap {
+ private long[] kv;
+ private MethodCall[] vv;
+ private int start;
+ private int end;
+ private int init_size;
+
+ public EfficientMap(int initial_size) {
+ init_size = initial_size;
+ shrink();
+ }
+
+ private void grow() {
+ // create new vectors twice as long
+ long[] oldkv = kv;
+ kv = new long[oldkv.length * 2];
+ MethodCall[] oldvv = vv;
+ vv = new MethodCall[oldvv.length * 2];
+
+ // copy start->length to the start of the new vector
+ System.arraycopy(oldkv, start, kv, 0, oldkv.length - start);
+ System.arraycopy(oldvv, start, vv, 0, oldvv.length - start);
+ // copy 0->end to the next part of the new vector
+ if (end != (oldkv.length - 1)) {
+ System.arraycopy(oldkv, 0, kv, oldkv.length - start, end + 1);
+ System.arraycopy(oldvv, 0, vv, oldvv.length - start, end + 1);
+ }
+ // reposition pointers
+ start = 0;
+ end = oldkv.length;
+ }
+
+ // create a new vector with just the valid keys in and return it
+ public long[] getKeys() {
+ int size;
+ if (start < end) size = end - start;
+ else size = kv.length - (start - end);
+ long[] lv = new long[size];
+ int copya;
+ if (size > kv.length - start) copya = kv.length - start;
+ else copya = size;
+ System.arraycopy(kv, start, lv, 0, copya);
+ if (copya < size) {
+ System.arraycopy(kv, 0, lv, copya, size - copya);
+ }
+ return lv;
+ }
+
+ private void shrink() {
+ if (null != kv && kv.length == init_size) return;
+ // reset to original size
+ kv = new long[init_size];
+ vv = new MethodCall[init_size];
+ start = 0;
+ end = 0;
+ }
+
+ public void put(long l, MethodCall m) {
+ // put this at the end
+ kv[end] = l;
+ vv[end] = m;
+ // move the end
+ if (end == (kv.length - 1)) end = 0;
+ else end++;
+ // if we are out of space, grow.
+ if (end == start) grow();
+ }
+
+ public MethodCall remove(long l) {
+ // find the item
+ int pos = find(l);
+ // if we don't have it return null
+ if (-1 == pos) return null;
+ // get the value
+ MethodCall m = vv[pos];
+ // set it as unused
+ vv[pos] = null;
+ kv[pos] = -1;
+ // move the pointer to the first full element
+ while (-1 == kv[start]) {
+ if (start == (kv.length - 1)) start = 0;
+ else start++;
+ // if we have emptied the list, shrink it
+ if (start == end) {
+ shrink();
+ break;
+ }
+ }
+ return m;
+ }
+
+ public boolean contains(long l) {
+ // check if find succeeds
+ return -1 != find(l);
+ }
+
+ /* could binary search, but it's probably the first one */
+ private int find(long l) {
+ int i = start;
+ while (i != end && kv[i] != l)
+ if (i == (kv.length - 1)) i = 0;
+ else i++;
+ if (i == end) return -1;
+ return i;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientQueue.java b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientQueue.java
new file mode 100644
index 0000000..a60c887
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/EfficientQueue.java
@@ -0,0 +1,109 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+/**
+ * Provides a Message queue which doesn't allocate objects
+ * on insertion/removal.
+ */
+class EfficientQueue {
+ private Message[] mv;
+ private int start;
+ private int end;
+ private int init_size;
+
+ public EfficientQueue(int initial_size) {
+ init_size = initial_size;
+ shrink();
+ }
+
+ private void grow() {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Growing");
+ // create new vectors twice as long
+ Message[] oldmv = mv;
+ mv = new Message[oldmv.length * 2];
+
+ // copy start->length to the start of the new vector
+ System.arraycopy(oldmv, start, mv, 0, oldmv.length - start);
+ // copy 0->end to the next part of the new vector
+ if (end != (oldmv.length - 1)) {
+ System.arraycopy(oldmv, 0, mv, oldmv.length - start, end + 1);
+ }
+ // reposition pointers
+ start = 0;
+ end = oldmv.length;
+ }
+
+ // create a new vector with just the valid keys in and return it
+ public Message[] getKeys() {
+ if (start == end) return new Message[0];
+ Message[] lv;
+ if (start < end) {
+ int size = end - start;
+ lv = new Message[size];
+ System.arraycopy(mv, start, lv, 0, size);
+ } else {
+ int size = mv.length - start + end;
+ lv = new Message[size];
+ System.arraycopy(mv, start, lv, 0, mv.length - start);
+ System.arraycopy(mv, 0, lv, mv.length - start, end);
+ }
+ return lv;
+ }
+
+ private void shrink() {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Shrinking");
+ if (null != mv && mv.length == init_size) return;
+ // reset to original size
+ mv = new Message[init_size];
+ start = 0;
+ end = 0;
+ }
+
+ public void add(Message m) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Enqueueing Message " + m);
+ // put this at the end
+ mv[end] = m;
+ // move the end
+ if (end == (mv.length - 1)) end = 0;
+ else end++;
+ // if we are out of space, grow.
+ if (end == start) grow();
+ }
+
+ public Message remove() {
+ if (start == end) return null;
+ // find the item
+ int pos = start;
+ // get the value
+ Message m = mv[pos];
+ // set it as unused
+ mv[pos] = null;
+ if (start == (mv.length - 1)) start = 0;
+ else start++;
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Dequeueing " + m);
+ return m;
+ }
+
+ public boolean isEmpty() {
+ // check if find succeeds
+ return start == end;
+ }
+
+ public int size() {
+ if (end >= start)
+ return end - start;
+ else
+ return mv.length - start + end;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Error.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Error.java
new file mode 100644
index 0000000..3350e95
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Error.java
@@ -0,0 +1,144 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.MessageFormatException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.lang.reflect.Constructor;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Error messages which can be sent over the bus.
+ */
+public class Error extends Message {
+ Error() {
+ }
+
+ public Error(String dest, String errorName, long replyserial, String sig, Object... args) throws DBusException {
+ this(null, dest, errorName, replyserial, sig, args);
+ }
+
+ public Error(String source, String dest, String errorName, long replyserial, String sig, Object... args) throws DBusException {
+ super(Message.Endian.BIG, Message.MessageType.ERROR, (byte) 0);
+
+ if (null == errorName)
+ throw new MessageFormatException(getString("missingErrorName"));
+ headers.put(Message.HeaderField.REPLY_SERIAL, replyserial);
+ headers.put(Message.HeaderField.ERROR_NAME, errorName);
+
+ Vector<Object> hargs = new Vector<Object>();
+ hargs.add(new Object[]{Message.HeaderField.ERROR_NAME, new Object[]{ArgumentType.STRING_STRING, errorName}});
+ hargs.add(new Object[]{Message.HeaderField.REPLY_SERIAL, new Object[]{ArgumentType.UINT32_STRING, replyserial}});
+
+ if (null != source) {
+ headers.put(Message.HeaderField.SENDER, source);
+ hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+ }
+
+ if (null != dest) {
+ headers.put(Message.HeaderField.DESTINATION, dest);
+ hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
+ }
+
+ if (null != sig) {
+ hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+ headers.put(Message.HeaderField.SIGNATURE, sig);
+ setArgs(args);
+ }
+
+ byte[] blen = new byte[4];
+ appendBytes(blen);
+ append("ua(yv)", serial, hargs.toArray());
+ pad((byte) 8);
+
+ long c = bytecounter;
+ if (null != sig) append(sig, args);
+ marshallint(bytecounter - c, blen, 0, 4);
+ }
+
+ public Error(String source, Message m, Throwable e) throws DBusException {
+ this(source, m.getSource(), AbstractConnection.dollar_pattern.matcher(e.getClass().getName()).replaceAll("."), m.getSerial(), "s", e.getMessage());
+ }
+
+ public Error(Message m, Throwable e) throws DBusException {
+ this(m.getSource(), AbstractConnection.dollar_pattern.matcher(e.getClass().getName()).replaceAll("."), m.getSerial(), "s", e.getMessage());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class<? extends DBusExecutionException> createExceptionClass(String name) {
+ if (name == "org.freedesktop.DBus.Local.disconnected") return NotConnected.class;
+ Class<? extends DBusExecutionException> c = null;
+ do {
+ try {
+ c = (Class<? extends org.freedesktop.dbus.exceptions.DBusExecutionException>) Class.forName(name);
+ } catch (ClassNotFoundException CNFe) {
+ }
+ name = name.replaceAll("\\.([^\\.]*)$", "\\$$1");
+ } while (null == c && name.matches(".*\\..*"));
+ return c;
+ }
+
+ /**
+ * Turns this into an exception of the correct type
+ */
+ public DBusExecutionException getException() {
+ try {
+ Class<? extends DBusExecutionException> c = createExceptionClass(getName());
+ if (null == c || !DBusExecutionException.class.isAssignableFrom(c)) c = DBusExecutionException.class;
+ Constructor<? extends DBusExecutionException> con = c.getConstructor(String.class);
+ DBusExecutionException ex;
+ Object[] args = getParameters();
+ if (null == args || 0 == args.length)
+ ex = con.newInstance("");
+ else {
+ String s = "";
+ for (Object o : args)
+ s += o + " ";
+ ex = con.newInstance(s.trim());
+ }
+ ex.setType(getName());
+ return ex;
+ } catch (Exception e) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug && null != e.getCause())
+ Debug.print(Debug.ERR, e.getCause());
+ DBusExecutionException ex;
+ Object[] args = null;
+ try {
+ args = getParameters();
+ } catch (Exception ee) {
+ }
+ if (null == args || 0 == args.length)
+ ex = new DBusExecutionException("");
+ else {
+ String s = "";
+ for (Object o : args)
+ s += o + " ";
+ ex = new DBusExecutionException(s.trim());
+ }
+ ex.setType(getName());
+ return ex;
+ }
+ }
+
+ /**
+ * Throw this as an exception of the correct type
+ */
+ public void throwException() throws DBusExecutionException {
+ throw getException();
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusException.java
new file mode 100644
index 0000000..d9c7e93
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusException.java
@@ -0,0 +1,24 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * An exception within DBus.
+ */
+@SuppressWarnings("serial")
+public class DBusException extends Exception {
+ /**
+ * Create an exception with the specified message
+ */
+ public DBusException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java
new file mode 100644
index 0000000..641a967
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/DBusExecutionException.java
@@ -0,0 +1,39 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * An exception while running a remote method within DBus.
+ */
+@SuppressWarnings("serial")
+public class DBusExecutionException extends RuntimeException {
+ private String type;
+
+ /**
+ * Create an exception with the specified message
+ */
+ public DBusExecutionException(String message) {
+ super(message);
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Get the DBus type of this exception. Use if this
+ * was an exception we don't have a class file for.
+ */
+ public String getType() {
+ if (null == type) return getClass().getName();
+ else return type;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalDBusException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalDBusException.java
new file mode 100644
index 0000000..90002de
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalDBusException.java
@@ -0,0 +1,18 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+@SuppressWarnings("serial")
+public class FatalDBusException extends DBusException implements FatalException {
+ public FatalDBusException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalException.java
new file mode 100644
index 0000000..58e3220
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/FatalException.java
@@ -0,0 +1,14 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+public interface FatalException {
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java
new file mode 100644
index 0000000..ab9ecc1
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/InternalMessageException.java
@@ -0,0 +1,18 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+@SuppressWarnings("serial")
+public class InternalMessageException extends DBusExecutionException implements NonFatalException {
+ public InternalMessageException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MarshallingException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MarshallingException.java
new file mode 100644
index 0000000..3635456
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MarshallingException.java
@@ -0,0 +1,18 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+@SuppressWarnings("serial")
+public class MarshallingException extends DBusException implements NonFatalException {
+ public MarshallingException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java
new file mode 100644
index 0000000..e8a1938
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageFormatException.java
@@ -0,0 +1,21 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * Thrown if a message is formatted incorrectly.
+ */
+@SuppressWarnings("serial")
+public class MessageFormatException extends DBusException implements NonFatalException {
+ public MessageFormatException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java
new file mode 100644
index 0000000..c093b41
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageProtocolVersionException.java
@@ -0,0 +1,20 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+import java.io.IOException;
+
+@SuppressWarnings("serial")
+public class MessageProtocolVersionException extends IOException implements FatalException {
+ public MessageProtocolVersionException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageTypeException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageTypeException.java
new file mode 100644
index 0000000..21028e1
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/MessageTypeException.java
@@ -0,0 +1,20 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+import java.io.IOException;
+
+@SuppressWarnings("serial")
+public class MessageTypeException extends IOException implements NonFatalException {
+ public MessageTypeException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NonFatalException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NonFatalException.java
new file mode 100644
index 0000000..e6a0f36
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NonFatalException.java
@@ -0,0 +1,14 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+public interface NonFatalException {
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NotConnected.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NotConnected.java
new file mode 100644
index 0000000..0610c20
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/NotConnected.java
@@ -0,0 +1,21 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+/**
+ * Thrown if a DBus action is called when not connected to the Bus.
+ */
+@SuppressWarnings("serial")
+public class NotConnected extends DBusExecutionException implements FatalException {
+ public NotConnected(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java
new file mode 100644
index 0000000..af35075
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/exceptions/UnknownTypeCodeException.java
@@ -0,0 +1,20 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.exceptions;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+@SuppressWarnings("serial")
+public class UnknownTypeCodeException extends DBusException implements NonFatalException {
+ public UnknownTypeCodeException(byte code) {
+ super(getString("invalidDBusCode") + code);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ExportedObject.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ExportedObject.java
new file mode 100644
index 0000000..b9719a1
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ExportedObject.java
@@ -0,0 +1,165 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.lang.annotation.Annotation;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+class ExportedObject {
+ @SuppressWarnings("unchecked")
+ private String getAnnotations(AnnotatedElement c) {
+ String ans = "";
+ for (Annotation a : c.getDeclaredAnnotations()) {
+ Class t = a.annotationType();
+ String value = "";
+ try {
+ Method m = t.getMethod("value");
+ value = m.invoke(a).toString();
+ } catch (NoSuchMethodException NSMe) {
+ } catch (InvocationTargetException ITe) {
+ } catch (IllegalAccessException IAe) {
+ }
+
+ ans += " <annotation name=\"" + AbstractConnection.dollar_pattern.matcher(t.getName()).replaceAll(".") + "\" value=\"" + value + "\" />\n";
+ }
+ return ans;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<MethodTuple, Method> getExportedMethods(Class c) throws DBusException {
+ if (DBusInterface.class.equals(c)) return new HashMap<MethodTuple, Method>();
+ Map<MethodTuple, Method> m = new HashMap<MethodTuple, Method>();
+ for (Class i : c.getInterfaces())
+ if (DBusInterface.class.equals(i)) {
+ // add this class's public methods
+ if (null != c.getAnnotation(DBusInterfaceName.class)) {
+ String name = ((DBusInterfaceName) c.getAnnotation(DBusInterfaceName.class)).value();
+ introspectiondata += " <interface name=\"" + name + "\">\n";
+ DBusSignal.addInterfaceMap(c.getName(), name);
+ } else {
+ // don't let people export things which don't have a
+ // valid D-Bus interface name
+ if (c.getName().equals(c.getSimpleName()))
+ throw new DBusException(getString("interfaceNotAllowedOutsidePackage"));
+ if (c.getName().length() > DBusConnection.MAX_NAME_LENGTH)
+ throw new DBusException(getString("introspectInterfaceExceedCharacters") + c.getName());
+ else
+ introspectiondata += " <interface name=\"" + AbstractConnection.dollar_pattern.matcher(c.getName()).replaceAll(".") + "\">\n";
+ }
+ introspectiondata += getAnnotations(c);
+ for (Method meth : c.getDeclaredMethods())
+ if (Modifier.isPublic(meth.getModifiers())) {
+ String ms = "";
+ String name;
+ if (meth.isAnnotationPresent(DBusMemberName.class))
+ name = meth.getAnnotation(DBusMemberName.class).value();
+ else
+ name = meth.getName();
+ if (name.length() > DBusConnection.MAX_NAME_LENGTH)
+ throw new DBusException(getString("introspectMethodExceedCharacters") + name);
+ introspectiondata += " <method name=\"" + name + "\" >\n";
+ introspectiondata += getAnnotations(meth);
+ for (Class ex : meth.getExceptionTypes())
+ if (DBusExecutionException.class.isAssignableFrom(ex))
+ introspectiondata +=
+ " <annotation name=\"org.freedesktop.DBus.Method.Error\" value=\"" + AbstractConnection.dollar_pattern.matcher(ex.getName()).replaceAll(".") + "\" />\n";
+ for (Type pt : meth.getGenericParameterTypes())
+ for (String s : Marshalling.getDBusType(pt)) {
+ introspectiondata += " <arg type=\"" + s + "\" direction=\"in\"/>\n";
+ ms += s;
+ }
+ if (!Void.TYPE.equals(meth.getGenericReturnType())) {
+ if (Tuple.class.isAssignableFrom((Class) meth.getReturnType())) {
+ ParameterizedType tc = (ParameterizedType) meth.getGenericReturnType();
+ Type[] ts = tc.getActualTypeArguments();
+
+ for (Type t : ts)
+ if (t != null)
+ for (String s : Marshalling.getDBusType(t))
+ introspectiondata += " <arg type=\"" + s + "\" direction=\"out\"/>\n";
+ } else if (Object[].class.equals(meth.getGenericReturnType())) {
+ throw new DBusException(getString("cannotIntrospectReturnType"));
+ } else
+ for (String s : Marshalling.getDBusType(meth.getGenericReturnType()))
+ introspectiondata += " <arg type=\"" + s + "\" direction=\"out\"/>\n";
+ }
+ introspectiondata += " </method>\n";
+ m.put(new MethodTuple(name, ms), meth);
+ }
+ for (Class sig : c.getDeclaredClasses())
+ if (DBusSignal.class.isAssignableFrom(sig)) {
+ String name;
+ if (sig.isAnnotationPresent(DBusMemberName.class)) {
+ name = ((DBusMemberName) sig.getAnnotation(DBusMemberName.class)).value();
+ DBusSignal.addSignalMap(sig.getSimpleName(), name);
+ } else
+ name = sig.getSimpleName();
+ if (name.length() > DBusConnection.MAX_NAME_LENGTH)
+ throw new DBusException(getString("introspectSignalExceedCharacters") + name);
+ introspectiondata += " <signal name=\"" + name + "\">\n";
+ Constructor con = sig.getConstructors()[0];
+ Type[] ts = con.getGenericParameterTypes();
+ for (int j = 1; j < ts.length; j++)
+ for (String s : Marshalling.getDBusType(ts[j]))
+ introspectiondata += " <arg type=\"" + s + "\" direction=\"out\" />\n";
+ introspectiondata += getAnnotations(sig);
+ introspectiondata += " </signal>\n";
+
+ }
+ introspectiondata += " </interface>\n";
+ } else {
+ // recurse
+ m.putAll(getExportedMethods(i));
+ }
+ return m;
+ }
+
+ Map<MethodTuple, Method> methods;
+ Reference<DBusInterface> object;
+ String introspectiondata;
+
+ public ExportedObject(DBusInterface object, boolean weakreferences) throws DBusException {
+ if (weakreferences)
+ this.object = new WeakReference<DBusInterface>(object);
+ else
+ this.object = new StrongReference<DBusInterface>(object);
+ introspectiondata = "";
+ methods = getExportedMethods(object.getClass());
+ introspectiondata +=
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" +
+ " <method name=\"Introspect\">\n" +
+ " <arg type=\"s\" direction=\"out\"/>\n" +
+ " </method>\n" +
+ " </interface>\n";
+ introspectiondata +=
+ " <interface name=\"org.freedesktop.DBus.Peer\">\n" +
+ " <method name=\"Ping\">\n" +
+ " </method>\n" +
+ " </interface>\n";
+ }
+}
+
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Gettext.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Gettext.java
new file mode 100644
index 0000000..a519a6f
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Gettext.java
@@ -0,0 +1,30 @@
+/*
+ * Pescetti Pseudo-Duplimate Generator
+ *
+ * Copyright (C) 2007 Matthew Johnson
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License Version 2 as published by
+ * the Free Software Foundation. This program is distributed in the hope that
+ * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details. You should have received a
+ * copy of the GNU Lesser General Public License along with this program; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * To Contact me, please email src@matthew.ath.cx
+ *
+ */
+package org.freedesktop.dbus;
+
+import java.util.ResourceBundle;
+
+public class Gettext {
+ private static ResourceBundle myResources =
+ ResourceBundle.getBundle("en_US");
+
+ public static String getString(String s) {
+ return myResources.getString(s);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/InternalSignal.java b/federation/sssd/src/main/java/org/freedesktop/dbus/InternalSignal.java
new file mode 100644
index 0000000..0a3072d
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/InternalSignal.java
@@ -0,0 +1,20 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+class InternalSignal extends DBusSignal {
+ public InternalSignal(String source, String objectpath, String name, String iface, String sig, long serial, Object... parameters) throws DBusException {
+ super(objectpath, iface, name, sig, parameters);
+ this.serial = serial;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Marshalling.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Marshalling.java
new file mode 100644
index 0000000..9e88309
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Marshalling.java
@@ -0,0 +1,629 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.types.DBusListType;
+import org.freedesktop.dbus.types.DBusMapType;
+import org.freedesktop.dbus.types.DBusStructType;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Contains static methods for marshalling values.
+ */
+public class Marshalling {
+ private static Map<Type, String[]> typeCache = new HashMap<Type, String[]>();
+
+ /**
+ * Will return the DBus type corresponding to the given Java type.
+ * Note, container type should have their ParameterizedType not their
+ * Class passed in here.
+ *
+ * @param c The Java types.
+ * @return The DBus types.
+ * @throws DBusException If the given type cannot be converted to a DBus type.
+ */
+ public static String getDBusType(Type[] c) throws DBusException {
+ StringBuffer sb = new StringBuffer();
+ for (Type t : c)
+ for (String s : getDBusType(t))
+ sb.append(s);
+ return sb.toString();
+ }
+
+ /**
+ * Will return the DBus type corresponding to the given Java type.
+ * Note, container type should have their ParameterizedType not their
+ * Class passed in here.
+ *
+ * @param c The Java type.
+ * @return The DBus type.
+ * @throws DBusException If the given type cannot be converted to a DBus type.
+ */
+ public static String[] getDBusType(Type c) throws DBusException {
+ String[] cached = typeCache.get(c);
+ if (null != cached) return cached;
+ cached = getDBusType(c, false);
+ typeCache.put(c, cached);
+ return cached;
+ }
+
+ /**
+ * Will return the DBus type corresponding to the given Java type.
+ * Note, container type should have their ParameterizedType not their
+ * Class passed in here.
+ *
+ * @param c The Java type.
+ * @param basic If true enforces this to be a non-compound type. (compound types are Maps, Structs and Lists/arrays).
+ * @return The DBus type.
+ * @throws DBusException If the given type cannot be converted to a DBus type.
+ */
+ public static String[] getDBusType(Type c, boolean basic) throws DBusException {
+ return recursiveGetDBusType(c, basic, 0);
+ }
+
+ private static StringBuffer[] out = new StringBuffer[10];
+
+ @SuppressWarnings("unchecked")
+ public static String[] recursiveGetDBusType(Type c, boolean basic, int level) throws DBusException {
+ if (out.length <= level) {
+ StringBuffer[] newout = new StringBuffer[out.length];
+ System.arraycopy(out, 0, newout, 0, out.length);
+ out = newout;
+ }
+ if (null == out[level]) out[level] = new StringBuffer();
+ else out[level].delete(0, out[level].length());
+
+ if (basic && !(c instanceof Class))
+ throw new DBusException(c + getString("notBasicType"));
+
+ if (c instanceof TypeVariable) out[level].append((char) Message.ArgumentType.VARIANT);
+ else if (c instanceof GenericArrayType) {
+ out[level].append((char) Message.ArgumentType.ARRAY);
+ String[] s = recursiveGetDBusType(((GenericArrayType) c).getGenericComponentType(), false, level + 1);
+ if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+ out[level].append(s[0]);
+ } else if ((c instanceof Class &&
+ DBusSerializable.class.isAssignableFrom((Class<? extends Object>) c)) ||
+ (c instanceof ParameterizedType &&
+ DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) c).getRawType()))) {
+ // it's a custom serializable type
+ Type[] newtypes = null;
+ if (c instanceof Class) {
+ for (Method m : ((Class<? extends Object>) c).getDeclaredMethods())
+ if (m.getName().equals("deserialize"))
+ newtypes = m.getGenericParameterTypes();
+ } else
+ for (Method m : ((Class<? extends Object>) ((ParameterizedType) c).getRawType()).getDeclaredMethods())
+ if (m.getName().equals("deserialize"))
+ newtypes = m.getGenericParameterTypes();
+
+ if (null == newtypes) throw new DBusException(getString("mustImplementDeserializeMethod"));
+
+ String[] sigs = new String[newtypes.length];
+ for (int j = 0; j < sigs.length; j++) {
+ String[] ss = recursiveGetDBusType(newtypes[j], false, level + 1);
+ if (1 != ss.length) throw new DBusException(getString("mustSerializeNativeDBusTypes"));
+ sigs[j] = ss[0];
+ }
+ return sigs;
+ } else if (c instanceof ParameterizedType) {
+ ParameterizedType p = (ParameterizedType) c;
+ if (p.getRawType().equals(Map.class)) {
+ out[level].append("a{");
+ Type[] t = p.getActualTypeArguments();
+ try {
+ String[] s = recursiveGetDBusType(t[0], true, level + 1);
+ if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+ out[level].append(s[0]);
+ s = recursiveGetDBusType(t[1], false, level + 1);
+ if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+ out[level].append(s[0]);
+ } catch (ArrayIndexOutOfBoundsException AIOOBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
+ throw new DBusException(getString("mapParameters"));
+ }
+ out[level].append('}');
+ } else if (List.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
+ for (Type t : p.getActualTypeArguments()) {
+ if (Type.class.equals(t))
+ out[level].append((char) Message.ArgumentType.SIGNATURE);
+ else {
+ String[] s = recursiveGetDBusType(t, false, level + 1);
+ if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+ out[level].append((char) Message.ArgumentType.ARRAY);
+ out[level].append(s[0]);
+ }
+ }
+ } else if (p.getRawType().equals(Variant.class)) {
+ out[level].append((char) Message.ArgumentType.VARIANT);
+ } else if (DBusInterface.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
+ out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+ } else if (Tuple.class.isAssignableFrom((Class<? extends Object>) p.getRawType())) {
+ Type[] ts = p.getActualTypeArguments();
+ Vector<String> vs = new Vector<String>();
+ for (Type t : ts)
+ for (String s : recursiveGetDBusType(t, false, level + 1))
+ vs.add(s);
+ return vs.toArray(new String[0]);
+ } else
+ throw new DBusException(getString("nonExportableParameterizedType") + c);
+ } else if (c.equals(Byte.class)) out[level].append((char) Message.ArgumentType.BYTE);
+ else if (c.equals(Byte.TYPE)) out[level].append((char) Message.ArgumentType.BYTE);
+ else if (c.equals(Boolean.class)) out[level].append((char) Message.ArgumentType.BOOLEAN);
+ else if (c.equals(Boolean.TYPE)) out[level].append((char) Message.ArgumentType.BOOLEAN);
+ else if (c.equals(Short.class)) out[level].append((char) Message.ArgumentType.INT16);
+ else if (c.equals(Short.TYPE)) out[level].append((char) Message.ArgumentType.INT16);
+ else if (c.equals(UInt16.class)) out[level].append((char) Message.ArgumentType.UINT16);
+ else if (c.equals(Integer.class)) out[level].append((char) Message.ArgumentType.INT32);
+ else if (c.equals(Integer.TYPE)) out[level].append((char) Message.ArgumentType.INT32);
+ else if (c.equals(UInt32.class)) out[level].append((char) Message.ArgumentType.UINT32);
+ else if (c.equals(Long.class)) out[level].append((char) Message.ArgumentType.INT64);
+ else if (c.equals(Long.TYPE)) out[level].append((char) Message.ArgumentType.INT64);
+ else if (c.equals(UInt64.class)) out[level].append((char) Message.ArgumentType.UINT64);
+ else if (c.equals(Double.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
+ else if (c.equals(Double.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
+ else if (c.equals(Float.class) && AbstractConnection.FLOAT_SUPPORT)
+ out[level].append((char) Message.ArgumentType.FLOAT);
+ else if (c.equals(Float.class)) out[level].append((char) Message.ArgumentType.DOUBLE);
+ else if (c.equals(Float.TYPE) && AbstractConnection.FLOAT_SUPPORT)
+ out[level].append((char) Message.ArgumentType.FLOAT);
+ else if (c.equals(Float.TYPE)) out[level].append((char) Message.ArgumentType.DOUBLE);
+ else if (c.equals(String.class)) out[level].append((char) Message.ArgumentType.STRING);
+ else if (c.equals(Variant.class)) out[level].append((char) Message.ArgumentType.VARIANT);
+ else if (c instanceof Class &&
+ DBusInterface.class.isAssignableFrom((Class<? extends Object>) c))
+ out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+ else if (c instanceof Class &&
+ Path.class.equals((Class<? extends Object>) c))
+ out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+ else if (c instanceof Class &&
+ ObjectPath.class.equals((Class<? extends Object>) c))
+ out[level].append((char) Message.ArgumentType.OBJECT_PATH);
+ else if (c instanceof Class &&
+ ((Class<? extends Object>) c).isArray()) {
+ if (Type.class.equals(((Class<? extends Object>) c).getComponentType()))
+ out[level].append((char) Message.ArgumentType.SIGNATURE);
+ else {
+ out[level].append((char) Message.ArgumentType.ARRAY);
+ String[] s = recursiveGetDBusType(((Class<? extends Object>) c).getComponentType(), false, level + 1);
+ if (s.length != 1) throw new DBusException(getString("multiValuedArrayNotPermitted"));
+ out[level].append(s[0]);
+ }
+ } else if (c instanceof Class &&
+ Struct.class.isAssignableFrom((Class<? extends Object>) c)) {
+ out[level].append((char) Message.ArgumentType.STRUCT1);
+ Type[] ts = Container.getTypeCache(c);
+ if (null == ts) {
+ Field[] fs = ((Class<? extends Object>) c).getDeclaredFields();
+ ts = new Type[fs.length];
+ for (Field f : fs) {
+ Position p = f.getAnnotation(Position.class);
+ if (null == p) continue;
+ ts[p.value()] = f.getGenericType();
+ }
+ Container.putTypeCache(c, ts);
+ }
+
+ for (Type t : ts)
+ if (t != null)
+ for (String s : recursiveGetDBusType(t, false, level + 1))
+ out[level].append(s);
+ out[level].append(')');
+ } else {
+ throw new DBusException(getString("nonExportableType") + c);
+ }
+
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Converted Java type: " + c + " to D-Bus Type: " + out[level]);
+
+ return new String[]{out[level].toString()};
+ }
+
+ /**
+ * Converts a dbus type string into Java Type objects,
+ *
+ * @param dbus The DBus type or types.
+ * @param rv Vector to return the types in.
+ * @param limit Maximum number of types to parse (-1 == nolimit).
+ * @return number of characters parsed from the type string.
+ */
+ public static int getJavaType(String dbus, List<Type> rv, int limit) throws DBusException {
+ if (null == dbus || "".equals(dbus) || 0 == limit) return 0;
+
+ try {
+ int i = 0;
+ for (; i < dbus.length() && (-1 == limit || limit > rv.size()); i++)
+ switch (dbus.charAt(i)) {
+ case Message.ArgumentType.STRUCT1:
+ int j = i + 1;
+ for (int c = 1; c > 0; j++) {
+ if (')' == dbus.charAt(j)) c--;
+ else if (Message.ArgumentType.STRUCT1 == dbus.charAt(j)) c++;
+ }
+
+ Vector<Type> contained = new Vector<Type>();
+ int c = getJavaType(dbus.substring(i + 1, j - 1), contained, -1);
+ rv.add(new DBusStructType(contained.toArray(new Type[0])));
+ i = j;
+ break;
+ case Message.ArgumentType.ARRAY:
+ if (Message.ArgumentType.DICT_ENTRY1 == dbus.charAt(i + 1)) {
+ contained = new Vector<Type>();
+ c = getJavaType(dbus.substring(i + 2), contained, 2);
+ rv.add(new DBusMapType(contained.get(0), contained.get(1)));
+ i += (c + 2);
+ } else {
+ contained = new Vector<Type>();
+ c = getJavaType(dbus.substring(i + 1), contained, 1);
+ rv.add(new DBusListType(contained.get(0)));
+ i += c;
+ }
+ break;
+ case Message.ArgumentType.VARIANT:
+ rv.add(Variant.class);
+ break;
+ case Message.ArgumentType.BOOLEAN:
+ rv.add(Boolean.class);
+ break;
+ case Message.ArgumentType.INT16:
+ rv.add(Short.class);
+ break;
+ case Message.ArgumentType.BYTE:
+ rv.add(Byte.class);
+ break;
+ case Message.ArgumentType.OBJECT_PATH:
+ rv.add(DBusInterface.class);
+ break;
+ case Message.ArgumentType.UINT16:
+ rv.add(UInt16.class);
+ break;
+ case Message.ArgumentType.INT32:
+ rv.add(Integer.class);
+ break;
+ case Message.ArgumentType.UINT32:
+ rv.add(UInt32.class);
+ break;
+ case Message.ArgumentType.INT64:
+ rv.add(Long.class);
+ break;
+ case Message.ArgumentType.UINT64:
+ rv.add(UInt64.class);
+ break;
+ case Message.ArgumentType.DOUBLE:
+ rv.add(Double.class);
+ break;
+ case Message.ArgumentType.FLOAT:
+ rv.add(Float.class);
+ break;
+ case Message.ArgumentType.STRING:
+ rv.add(String.class);
+ break;
+ case Message.ArgumentType.SIGNATURE:
+ rv.add(Type[].class);
+ break;
+ case Message.ArgumentType.DICT_ENTRY1:
+ rv.add(Map.Entry.class);
+ contained = new Vector<Type>();
+ c = getJavaType(dbus.substring(i + 1), contained, 2);
+ i += c + 1;
+ break;
+ default:
+ throw new DBusException(MessageFormat.format(getString("parseDBusSignatureFailure"), new Object[]{dbus, dbus.charAt(i)}));
+ }
+ return i;
+ } catch (IndexOutOfBoundsException IOOBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, IOOBe);
+ throw new DBusException(getString("parseDBusTypeSignatureFailure") + dbus);
+ }
+ }
+
+ /**
+ * Recursively converts types for serialization onto DBus.
+ *
+ * @param parameters The parameters to convert.
+ * @param types The (possibly generic) types of the parameters.
+ * @return The converted parameters.
+ * @throws DBusException Thrown if there is an error in converting the objects.
+ */
+ @SuppressWarnings("unchecked")
+ public static Object[] convertParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws DBusException {
+ if (null == parameters) return null;
+ for (int i = 0; i < parameters.length; i++) {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Converting " + i + " from " + parameters[i] + " to " + types[i]);
+ if (null == parameters[i]) continue;
+
+ if (parameters[i] instanceof DBusSerializable) {
+ for (Method m : parameters[i].getClass().getDeclaredMethods())
+ if (m.getName().equals("deserialize")) {
+ Type[] newtypes = m.getParameterTypes();
+ Type[] expand = new Type[types.length + newtypes.length - 1];
+ System.arraycopy(types, 0, expand, 0, i);
+ System.arraycopy(newtypes, 0, expand, i, newtypes.length);
+ System.arraycopy(types, i + 1, expand, i + newtypes.length, types.length - i - 1);
+ types = expand;
+ Object[] newparams = ((DBusSerializable) parameters[i]).serialize();
+ Object[] exparams = new Object[parameters.length + newparams.length - 1];
+ System.arraycopy(parameters, 0, exparams, 0, i);
+ System.arraycopy(newparams, 0, exparams, i, newparams.length);
+ System.arraycopy(parameters, i + 1, exparams, i + newparams.length, parameters.length - i - 1);
+ parameters = exparams;
+ }
+ i--;
+ } else if (parameters[i] instanceof Tuple) {
+ Type[] newtypes = ((ParameterizedType) types[i]).getActualTypeArguments();
+ Type[] expand = new Type[types.length + newtypes.length - 1];
+ System.arraycopy(types, 0, expand, 0, i);
+ System.arraycopy(newtypes, 0, expand, i, newtypes.length);
+ System.arraycopy(types, i + 1, expand, i + newtypes.length, types.length - i - 1);
+ types = expand;
+ Object[] newparams = ((Tuple) parameters[i]).getParameters();
+ Object[] exparams = new Object[parameters.length + newparams.length - 1];
+ System.arraycopy(parameters, 0, exparams, 0, i);
+ System.arraycopy(newparams, 0, exparams, i, newparams.length);
+ System.arraycopy(parameters, i + 1, exparams, i + newparams.length, parameters.length - i - 1);
+ parameters = exparams;
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "New params: " + Arrays.deepToString(parameters) + " new types: " + Arrays.deepToString(types));
+ i--;
+ } else if (types[i] instanceof TypeVariable &&
+ !(parameters[i] instanceof Variant))
+ // its an unwrapped variant, wrap it
+ parameters[i] = new Variant<Object>(parameters[i]);
+ else if (parameters[i] instanceof DBusInterface)
+ parameters[i] = conn.getExportedObject((DBusInterface) parameters[i]);
+ }
+ return parameters;
+ }
+
+ @SuppressWarnings("unchecked")
+ static Object deSerializeParameter(Object parameter, Type type, AbstractConnection conn) throws Exception {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Deserializing from " + parameter.getClass() + " to " + type.getClass());
+ if (null == parameter)
+ return null;
+
+ // its a wrapped variant, unwrap it
+ if (type instanceof TypeVariable
+ && parameter instanceof Variant) {
+ parameter = ((Variant) parameter).getValue();
+ }
+
+ // Turn a signature into a Type[]
+ if (type instanceof Class
+ && ((Class) type).isArray()
+ && ((Class) type).getComponentType().equals(Type.class)
+ && parameter instanceof String) {
+ Vector<Type> rv = new Vector<Type>();
+ getJavaType((String) parameter, rv, -1);
+ parameter = rv.toArray(new Type[0]);
+ }
+
+ // its an object path, get/create the proxy
+ if (parameter instanceof ObjectPath) {
+ if (type instanceof Class && DBusInterface.class.isAssignableFrom((Class) type))
+ parameter = conn.getExportedObject(
+ ((ObjectPath) parameter).source,
+ ((ObjectPath) parameter).path);
+ else
+ parameter = new Path(((ObjectPath) parameter).path);
+ }
+
+ // it should be a struct. create it
+ if (parameter instanceof Object[] &&
+ type instanceof Class &&
+ Struct.class.isAssignableFrom((Class) type)) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Creating Struct " + type + " from " + parameter);
+ Type[] ts = Container.getTypeCache(type);
+ if (null == ts) {
+ Field[] fs = ((Class) type).getDeclaredFields();
+ ts = new Type[fs.length];
+ for (Field f : fs) {
+ Position p = f.getAnnotation(Position.class);
+ if (null == p) continue;
+ ts[p.value()] = f.getGenericType();
+ }
+ Container.putTypeCache(type, ts);
+ }
+
+ // recurse over struct contents
+ parameter = deSerializeParameters((Object[]) parameter, ts, conn);
+ for (Constructor con : ((Class) type).getDeclaredConstructors()) {
+ try {
+ parameter = con.newInstance((Object[]) parameter);
+ break;
+ } catch (IllegalArgumentException IAe) {
+ }
+ }
+ }
+
+ // recurse over arrays
+ if (parameter instanceof Object[]) {
+ Type[] ts = new Type[((Object[]) parameter).length];
+ Arrays.fill(ts, parameter.getClass().getComponentType());
+ parameter = deSerializeParameters((Object[]) parameter,
+ ts, conn);
+ }
+ if (parameter instanceof List) {
+ Type type2;
+ if (type instanceof ParameterizedType)
+ type2 = ((ParameterizedType) type).getActualTypeArguments()[0];
+ else if (type instanceof GenericArrayType)
+ type2 = ((GenericArrayType) type).getGenericComponentType();
+ else if (type instanceof Class && ((Class) type).isArray())
+ type2 = ((Class) type).getComponentType();
+ else
+ type2 = null;
+ if (null != type2)
+ parameter = deSerializeParameters((List) parameter, type2, conn);
+ }
+
+ // correct floats if appropriate
+ if (type.equals(Float.class) || type.equals(Float.TYPE))
+ if (!(parameter instanceof Float))
+ parameter = ((Number) parameter).floatValue();
+
+ // make sure arrays are in the correct format
+ if (parameter instanceof Object[] ||
+ parameter instanceof List ||
+ parameter.getClass().isArray()) {
+ if (type instanceof ParameterizedType)
+ parameter = ArrayFrob.convert(parameter,
+ (Class<? extends Object>) ((ParameterizedType) type).getRawType());
+ else if (type instanceof GenericArrayType) {
+ Type ct = ((GenericArrayType) type).getGenericComponentType();
+ Class cc = null;
+ if (ct instanceof Class)
+ cc = (Class) ct;
+ if (ct instanceof ParameterizedType)
+ cc = (Class) ((ParameterizedType) ct).getRawType();
+ Object o = Array.newInstance(cc, 0);
+ parameter = ArrayFrob.convert(parameter,
+ o.getClass());
+ } else if (type instanceof Class &&
+ ((Class) type).isArray()) {
+ Class cc = ((Class) type).getComponentType();
+ if ((cc.equals(Float.class) || cc.equals(Float.TYPE))
+ && (parameter instanceof double[])) {
+ double[] tmp1 = (double[]) parameter;
+ float[] tmp2 = new float[tmp1.length];
+ for (int i = 0; i < tmp1.length; i++)
+ tmp2[i] = (float) tmp1[i];
+ parameter = tmp2;
+ }
+ Object o = Array.newInstance(cc, 0);
+ parameter = ArrayFrob.convert(parameter,
+ o.getClass());
+ }
+ }
+ if (parameter instanceof DBusMap) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing a Map");
+ DBusMap dmap = (DBusMap) parameter;
+ Type[] maptypes = ((ParameterizedType) type).getActualTypeArguments();
+ for (int i = 0; i < dmap.entries.length; i++) {
+ dmap.entries[i][0] = deSerializeParameter(dmap.entries[i][0], maptypes[0], conn);
+ dmap.entries[i][1] = deSerializeParameter(dmap.entries[i][1], maptypes[1], conn);
+ }
+ }
+ return parameter;
+ }
+
+ static List<Object> deSerializeParameters(List<Object> parameters, Type type, AbstractConnection conn) throws Exception {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Deserializing from " + parameters + " to " + type);
+ if (null == parameters) return null;
+ for (int i = 0; i < parameters.size(); i++) {
+ if (null == parameters.get(i)) continue;
+
+ /* DO NOT DO THIS! IT'S REALLY NOT SUPPORTED!
+ * if (type instanceof Class &&
+ DBusSerializable.class.isAssignableFrom((Class) types[i])) {
+ for (Method m: ((Class) types[i]).getDeclaredMethods())
+ if (m.getName().equals("deserialize")) {
+ Type[] newtypes = m.getGenericParameterTypes();
+ try {
+ Object[] sub = new Object[newtypes.length];
+ System.arraycopy(parameters, i, sub, 0, newtypes.length);
+ sub = deSerializeParameters(sub, newtypes, conn);
+ DBusSerializable sz = (DBusSerializable) ((Class) types[i]).newInstance();
+ m.invoke(sz, sub);
+ Object[] compress = new Object[parameters.length - newtypes.length + 1];
+ System.arraycopy(parameters, 0, compress, 0, i);
+ compress[i] = sz;
+ System.arraycopy(parameters, i + newtypes.length, compress, i+1, parameters.length - i - newtypes.length);
+ parameters = compress;
+ } catch (ArrayIndexOutOfBoundsException AIOOBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
+ throw new DBusException("Not enough elements to create custom object from serialized data ("+(parameters.size()-i)+" < "+(newtypes.length)+")");
+ }
+ }
+ } else*/
+ parameters.set(i, deSerializeParameter(parameters.get(i), type, conn));
+ }
+ return parameters;
+ }
+
+ @SuppressWarnings("unchecked")
+ static Object[] deSerializeParameters(Object[] parameters, Type[] types, AbstractConnection conn) throws Exception {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Deserializing from " + Arrays.deepToString(parameters) + " to " + Arrays.deepToString(types));
+ if (null == parameters) return null;
+
+ if (types.length == 1 && types[0] instanceof ParameterizedType
+ && Tuple.class.isAssignableFrom((Class) ((ParameterizedType) types[0]).getRawType())) {
+ types = ((ParameterizedType) types[0]).getActualTypeArguments();
+ }
+
+ for (int i = 0; i < parameters.length; i++) {
+ // CHECK IF ARRAYS HAVE THE SAME LENGTH <-- has to happen after expanding parameters
+ if (i >= types.length) {
+ if (Debug.debug) {
+ for (int j = 0; j < parameters.length; j++) {
+ Debug.print(Debug.ERR, String.format("Error, Parameters difference (%1d, '%2s')", j, parameters[j].toString()));
+ }
+ }
+ throw new DBusException(getString("errorDeserializingMessage"));
+ }
+ if (null == parameters[i]) continue;
+
+ if ((types[i] instanceof Class &&
+ DBusSerializable.class.isAssignableFrom((Class<? extends Object>) types[i])) ||
+ (types[i] instanceof ParameterizedType &&
+ DBusSerializable.class.isAssignableFrom((Class<? extends Object>) ((ParameterizedType) types[i]).getRawType()))) {
+ Class<? extends DBusSerializable> dsc;
+ if (types[i] instanceof Class)
+ dsc = (Class<? extends DBusSerializable>) types[i];
+ else
+ dsc = (Class<? extends DBusSerializable>) ((ParameterizedType) types[i]).getRawType();
+ for (Method m : dsc.getDeclaredMethods())
+ if (m.getName().equals("deserialize")) {
+ Type[] newtypes = m.getGenericParameterTypes();
+ try {
+ Object[] sub = new Object[newtypes.length];
+ System.arraycopy(parameters, i, sub, 0, newtypes.length);
+ sub = deSerializeParameters(sub, newtypes, conn);
+ DBusSerializable sz = dsc.newInstance();
+ m.invoke(sz, sub);
+ Object[] compress = new Object[parameters.length - newtypes.length + 1];
+ System.arraycopy(parameters, 0, compress, 0, i);
+ compress[i] = sz;
+ System.arraycopy(parameters, i + newtypes.length, compress, i + 1, parameters.length - i - newtypes.length);
+ parameters = compress;
+ } catch (ArrayIndexOutOfBoundsException AIOOBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, AIOOBe);
+ throw new DBusException(MessageFormat.format(getString("notEnoughElementsToCreateCustomObject"),
+ new Object[]{parameters.length - i, newtypes.length}));
+ }
+ }
+ } else
+ parameters[i] = deSerializeParameter(parameters[i], types[i], conn);
+ }
+ return parameters;
+ }
+}
+
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Message.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Message.java
new file mode 100644
index 0000000..01f00e8
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Message.java
@@ -0,0 +1,1216 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.utils.Hexdump;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MarshallingException;
+import org.freedesktop.dbus.exceptions.UnknownTypeCodeException;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Superclass of all messages which are sent over the Bus.
+ * This class deals with all the marshalling to/from the wire format.
+ */
+public class Message {
+ /**
+ * Defines constants representing the endianness of the message.
+ */
+ public static interface Endian {
+ public static final byte BIG = 'B';
+ public static final byte LITTLE = 'l';
+ }
+
+ /**
+ * Defines constants representing the flags which can be set on a message.
+ */
+ public static interface Flags {
+ public static final byte NO_REPLY_EXPECTED = 0x01;
+ public static final byte NO_AUTO_START = 0x02;
+ public static final byte ASYNC = 0x40;
+ }
+
+ /**
+ * Defines constants for each message type.
+ */
+ public static interface MessageType {
+ public static final byte METHOD_CALL = 1;
+ public static final byte METHOD_RETURN = 2;
+ public static final byte ERROR = 3;
+ public static final byte SIGNAL = 4;
+ }
+
+ /**
+ * The current protocol major version.
+ */
+ public static final byte PROTOCOL = 1;
+
+ /**
+ * Defines constants for each valid header field type.
+ */
+ public static interface HeaderField {
+ public static final byte PATH = 1;
+ public static final byte INTERFACE = 2;
+ public static final byte MEMBER = 3;
+ public static final byte ERROR_NAME = 4;
+ public static final byte REPLY_SERIAL = 5;
+ public static final byte DESTINATION = 6;
+ public static final byte SENDER = 7;
+ public static final byte SIGNATURE = 8;
+ }
+
+ /**
+ * Defines constants for each argument type.
+ * There are two constants for each argument type,
+ * as a byte or as a String (the _STRING version)
+ */
+ public static interface ArgumentType {
+ public static final String BYTE_STRING = "y";
+ public static final String BOOLEAN_STRING = "b";
+ public static final String INT16_STRING = "n";
+ public static final String UINT16_STRING = "q";
+ public static final String INT32_STRING = "i";
+ public static final String UINT32_STRING = "u";
+ public static final String INT64_STRING = "x";
+ public static final String UINT64_STRING = "t";
+ public static final String DOUBLE_STRING = "d";
+ public static final String FLOAT_STRING = "f";
+ public static final String STRING_STRING = "s";
+ public static final String OBJECT_PATH_STRING = "o";
+ public static final String SIGNATURE_STRING = "g";
+ public static final String ARRAY_STRING = "a";
+ public static final String VARIANT_STRING = "v";
+ public static final String STRUCT_STRING = "r";
+ public static final String STRUCT1_STRING = "(";
+ public static final String STRUCT2_STRING = ")";
+ public static final String DICT_ENTRY_STRING = "e";
+ public static final String DICT_ENTRY1_STRING = "{";
+ public static final String DICT_ENTRY2_STRING = "}";
+
+ public static final byte BYTE = 'y';
+ public static final byte BOOLEAN = 'b';
+ public static final byte INT16 = 'n';
+ public static final byte UINT16 = 'q';
+ public static final byte INT32 = 'i';
+ public static final byte UINT32 = 'u';
+ public static final byte INT64 = 'x';
+ public static final byte UINT64 = 't';
+ public static final byte DOUBLE = 'd';
+ public static final byte FLOAT = 'f';
+ public static final byte STRING = 's';
+ public static final byte OBJECT_PATH = 'o';
+ public static final byte SIGNATURE = 'g';
+ public static final byte ARRAY = 'a';
+ public static final byte VARIANT = 'v';
+ public static final byte STRUCT = 'r';
+ public static final byte STRUCT1 = '(';
+ public static final byte STRUCT2 = ')';
+ public static final byte DICT_ENTRY = 'e';
+ public static final byte DICT_ENTRY1 = '{';
+ public static final byte DICT_ENTRY2 = '}';
+ }
+
+ /**
+ * Keep a static reference to each size of padding array to prevent allocation.
+ */
+ private static byte[][] padding;
+
+ static {
+ padding = new byte[][]{
+ null,
+ new byte[1],
+ new byte[2],
+ new byte[3],
+ new byte[4],
+ new byte[5],
+ new byte[6],
+ new byte[7]};
+ }
+
+ /**
+ * Steps to increment the buffer array.
+ */
+ private static final int BUFFERINCREMENT = 20;
+
+ private boolean big;
+ protected byte[][] wiredata;
+ protected long bytecounter;
+ protected Map<Byte, Object> headers;
+ protected static long globalserial = 0;
+ protected long serial;
+ protected byte type;
+ protected byte flags;
+ protected byte protover;
+ private Object[] args;
+ private byte[] body;
+ private long bodylen = 0;
+ private int preallocated = 0;
+ private int paofs = 0;
+ private byte[] pabuf;
+ private int bufferuse = 0;
+
+ /**
+ * Returns the name of the given header field.
+ */
+ public static String getHeaderFieldName(byte field) {
+ switch (field) {
+ case HeaderField.PATH:
+ return "Path";
+ case HeaderField.INTERFACE:
+ return "Interface";
+ case HeaderField.MEMBER:
+ return "Member";
+ case HeaderField.ERROR_NAME:
+ return "Error Name";
+ case HeaderField.REPLY_SERIAL:
+ return "Reply Serial";
+ case HeaderField.DESTINATION:
+ return "Destination";
+ case HeaderField.SENDER:
+ return "Sender";
+ case HeaderField.SIGNATURE:
+ return "Signature";
+ default:
+ return "Invalid";
+ }
+ }
+
+ /**
+ * Create a message; only to be called by sub-classes.
+ *
+ * @param endian The endianness to create the message.
+ * @param type The message type.
+ * @param flags Any message flags.
+ */
+ protected Message(byte endian, byte type, byte flags) throws DBusException {
+ wiredata = new byte[BUFFERINCREMENT][];
+ headers = new HashMap<Byte, Object>();
+ big = (Endian.BIG == endian);
+ bytecounter = 0;
+ synchronized (Message.class) {
+ serial = ++globalserial;
+ }
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Creating message with serial " + serial);
+ this.type = type;
+ this.flags = flags;
+ preallocate(4);
+ append("yyyy", endian, type, flags, Message.PROTOCOL);
+ }
+
+ /**
+ * Create a blank message. Only to be used when calling populate.
+ */
+ protected Message() {
+ wiredata = new byte[BUFFERINCREMENT][];
+ headers = new HashMap<Byte, Object>();
+ bytecounter = 0;
+ }
+
+ /**
+ * Create a message from wire-format data.
+ *
+ * @param msg D-Bus serialized data of type yyyuu
+ * @param headers D-Bus serialized data of type a(yv)
+ * @param body D-Bus serialized data of the signature defined in headers.
+ */
+ @SuppressWarnings("unchecked")
+ void populate(byte[] msg, byte[] headers, byte[] body) throws DBusException {
+ big = (msg[0] == Endian.BIG);
+ type = msg[1];
+ flags = msg[2];
+ protover = msg[3];
+ wiredata[0] = msg;
+ wiredata[1] = headers;
+ wiredata[2] = body;
+ this.body = body;
+ bufferuse = 3;
+ bodylen = ((Number) extract(Message.ArgumentType.UINT32_STRING, msg, 4)[0]).longValue();
+ serial = ((Number) extract(Message.ArgumentType.UINT32_STRING, msg, 8)[0]).longValue();
+ bytecounter = msg.length + headers.length + body.length;
+ if (Debug.debug) Debug.print(Debug.VERBOSE, headers);
+ Object[] hs = extract("a(yv)", headers, 0);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, Arrays.deepToString(hs));
+ for (Object o : (Vector<Object>) hs[0]) {
+ this.headers.put((Byte) ((Object[]) o)[0], ((Variant<Object>) ((Object[]) o)[1]).getValue());
+ }
+ }
+
+ /**
+ * Create a buffer of num bytes.
+ * Data is copied to this rather than added to the buffer list.
+ */
+ private void preallocate(int num) {
+ preallocated = 0;
+ pabuf = new byte[num];
+ appendBytes(pabuf);
+ preallocated = num;
+ paofs = 0;
+ }
+
+ /**
+ * Ensures there are enough free buffers.
+ *
+ * @param num number of free buffers to create.
+ */
+ private void ensureBuffers(int num) {
+ int increase = num - wiredata.length + bufferuse;
+ if (increase > 0) {
+ if (increase < BUFFERINCREMENT) increase = BUFFERINCREMENT;
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing " + bufferuse);
+ byte[][] temp = new byte[wiredata.length + increase][];
+ System.arraycopy(wiredata, 0, temp, 0, wiredata.length);
+ wiredata = temp;
+ }
+ }
+
+ /**
+ * Appends a buffer to the buffer list.
+ */
+ protected void appendBytes(byte[] buf) {
+ if (null == buf) return;
+ if (preallocated > 0) {
+ if (paofs + buf.length > pabuf.length)
+ throw new ArrayIndexOutOfBoundsException(MessageFormat.format(getString("arrayOutOfBounds"), new Object[]{paofs, pabuf.length, buf.length}));
+ System.arraycopy(buf, 0, pabuf, paofs, buf.length);
+ paofs += buf.length;
+ preallocated -= buf.length;
+ } else {
+ if (bufferuse == wiredata.length) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing " + bufferuse);
+ byte[][] temp = new byte[wiredata.length + BUFFERINCREMENT][];
+ System.arraycopy(wiredata, 0, temp, 0, wiredata.length);
+ wiredata = temp;
+ }
+ wiredata[bufferuse++] = buf;
+ bytecounter += buf.length;
+ }
+ }
+
+ /**
+ * Appends a byte to the buffer list.
+ */
+ protected void appendByte(byte b) {
+ if (preallocated > 0) {
+ pabuf[paofs++] = b;
+ preallocated--;
+ } else {
+ if (bufferuse == wiredata.length) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing " + bufferuse);
+ byte[][] temp = new byte[wiredata.length + BUFFERINCREMENT][];
+ System.arraycopy(wiredata, 0, temp, 0, wiredata.length);
+ wiredata = temp;
+ }
+ wiredata[bufferuse++] = new byte[]{b};
+ bytecounter++;
+ }
+ }
+
+ /**
+ * Demarshalls an integer of a given width from a buffer.
+ * Endianness is determined from the format of the message.
+ *
+ * @param buf The buffer to demarshall from.
+ * @param ofs The offset to demarshall from.
+ * @param width The byte-width of the int.
+ */
+ public long demarshallint(byte[] buf, int ofs, int width) {
+ return big ? demarshallintBig(buf, ofs, width) : demarshallintLittle(buf, ofs, width);
+ }
+
+ /**
+ * Demarshalls an integer of a given width from a buffer.
+ *
+ * @param buf The buffer to demarshall from.
+ * @param ofs The offset to demarshall from.
+ * @param endian The endianness to use in demarshalling.
+ * @param width The byte-width of the int.
+ */
+ public static long demarshallint(byte[] buf, int ofs, byte endian, int width) {
+ return endian == Endian.BIG ? demarshallintBig(buf, ofs, width) : demarshallintLittle(buf, ofs, width);
+ }
+
+ /**
+ * Demarshalls an integer of a given width from a buffer using big-endian format.
+ *
+ * @param buf The buffer to demarshall from.
+ * @param ofs The offset to demarshall from.
+ * @param width The byte-width of the int.
+ */
+ public static long demarshallintBig(byte[] buf, int ofs, int width) {
+ long l = 0;
+ for (int i = 0; i < width; i++) {
+ l <<= 8;
+ l |= (buf[ofs + i] & 0xFF);
+ }
+ return l;
+ }
+
+ /**
+ * Demarshalls an integer of a given width from a buffer using little-endian format.
+ *
+ * @param buf The buffer to demarshall from.
+ * @param ofs The offset to demarshall from.
+ * @param width The byte-width of the int.
+ */
+ public static long demarshallintLittle(byte[] buf, int ofs, int width) {
+ long l = 0;
+ for (int i = (width - 1); i >= 0; i--) {
+ l <<= 8;
+ l |= (buf[ofs + i] & 0xFF);
+ }
+ return l;
+ }
+
+ /**
+ * Marshalls an integer of a given width and appends it to the message.
+ * Endianness is determined from the message.
+ *
+ * @param l The integer to marshall.
+ * @param width The byte-width of the int.
+ */
+ public void appendint(long l, int width) {
+ byte[] buf = new byte[width];
+ marshallint(l, buf, 0, width);
+ appendBytes(buf);
+ }
+
+ /**
+ * Marshalls an integer of a given width into a buffer.
+ * Endianness is determined from the message.
+ *
+ * @param l The integer to marshall.
+ * @param buf The buffer to marshall to.
+ * @param ofs The offset to marshall to.
+ * @param width The byte-width of the int.
+ */
+ public void marshallint(long l, byte[] buf, int ofs, int width) {
+ if (big) marshallintBig(l, buf, ofs, width);
+ else marshallintLittle(l, buf, ofs, width);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Marshalled int " + l + " to " + Hexdump.toHex(buf, ofs, width));
+ }
+
+ /**
+ * Marshalls an integer of a given width into a buffer using big-endian format.
+ *
+ * @param l The integer to marshall.
+ * @param buf The buffer to marshall to.
+ * @param ofs The offset to marshall to.
+ * @param width The byte-width of the int.
+ */
+ public static void marshallintBig(long l, byte[] buf, int ofs, int width) {
+ for (int i = (width - 1); i >= 0; i--) {
+ buf[i + ofs] = (byte) (l & 0xFF);
+ l >>= 8;
+ }
+ }
+
+ /**
+ * Marshalls an integer of a given width into a buffer using little-endian format.
+ *
+ * @param l The integer to marshall.
+ * @param buf The buffer to demarshall to.
+ * @param ofs The offset to demarshall to.
+ * @param width The byte-width of the int.
+ */
+ public static void marshallintLittle(long l, byte[] buf, int ofs, int width) {
+ for (int i = 0; i < width; i++) {
+ buf[i + ofs] = (byte) (l & 0xFF);
+ l >>= 8;
+ }
+ }
+
+ public byte[][] getWireData() {
+ return wiredata;
+ }
+
+ /**
+ * Formats the message in a human-readable format.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getSimpleName());
+ sb.append('(');
+ sb.append(flags);
+ sb.append(',');
+ sb.append(serial);
+ sb.append(')');
+ sb.append(' ');
+ sb.append('{');
+ sb.append(' ');
+ if (headers.size() == 0)
+ sb.append('}');
+ else {
+ for (Byte field : headers.keySet()) {
+ sb.append(getHeaderFieldName(field));
+ sb.append('=');
+ sb.append('>');
+ sb.append(headers.get(field).toString());
+ sb.append(',');
+ sb.append(' ');
+ }
+ sb.setCharAt(sb.length() - 2, ' ');
+ sb.setCharAt(sb.length() - 1, '}');
+ }
+ sb.append(' ');
+ sb.append('{');
+ sb.append(' ');
+ Object[] args = null;
+ try {
+ args = getParameters();
+ } catch (DBusException DBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ }
+ if (null == args || 0 == args.length)
+ sb.append('}');
+ else {
+ for (Object o : args) {
+ if (o instanceof Object[])
+ sb.append(Arrays.deepToString((Object[]) o));
+ else if (o instanceof byte[])
+ sb.append(Arrays.toString((byte[]) o));
+ else if (o instanceof int[])
+ sb.append(Arrays.toString((int[]) o));
+ else if (o instanceof short[])
+ sb.append(Arrays.toString((short[]) o));
+ else if (o instanceof long[])
+ sb.append(Arrays.toString((long[]) o));
+ else if (o instanceof boolean[])
+ sb.append(Arrays.toString((boolean[]) o));
+ else if (o instanceof double[])
+ sb.append(Arrays.toString((double[]) o));
+ else if (o instanceof float[])
+ sb.append(Arrays.toString((float[]) o));
+ else
+ sb.append(o.toString());
+ sb.append(',');
+ sb.append(' ');
+ }
+ sb.setCharAt(sb.length() - 2, ' ');
+ sb.setCharAt(sb.length() - 1, '}');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the value of the header field of a given field.
+ *
+ * @param type The field to return.
+ * @return The value of the field or null if unset.
+ */
+ public Object getHeader(byte type) {
+ return headers.get(type);
+ }
+
+ /**
+ * Appends a value to the message.
+ * The type of the value is read from a D-Bus signature and used to marshall
+ * the value.
+ *
+ * @param sigb A buffer of the D-Bus signature.
+ * @param sigofs The offset into the signature corresponding to this value.
+ * @param data The value to marshall.
+ * @return The offset into the signature of the end of this value's type.
+ */
+ @SuppressWarnings("unchecked")
+ private int appendone(byte[] sigb, int sigofs, Object data) throws DBusException {
+ try {
+ int i = sigofs;
+ if (Debug.debug) Debug.print(Debug.VERBOSE, (Object) bytecounter);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending type: " + ((char) sigb[i]) + " value: " + data);
+
+ // pad to the alignment of this type.
+ pad(sigb[i]);
+ switch (sigb[i]) {
+ case ArgumentType.BYTE:
+ appendByte(((Number) data).byteValue());
+ break;
+ case ArgumentType.BOOLEAN:
+ appendint(((Boolean) data).booleanValue() ? 1 : 0, 4);
+ break;
+ case ArgumentType.DOUBLE:
+ long l = Double.doubleToLongBits(((Number) data).doubleValue());
+ appendint(l, 8);
+ break;
+ case ArgumentType.FLOAT:
+ int rf = Float.floatToIntBits(((Number) data).floatValue());
+ appendint(rf, 4);
+ break;
+ case ArgumentType.UINT32:
+ appendint(((Number) data).longValue(), 4);
+ break;
+ case ArgumentType.INT64:
+ appendint(((Number) data).longValue(), 8);
+ break;
+ case ArgumentType.UINT64:
+ if (big) {
+ appendint(((UInt64) data).top(), 4);
+ appendint(((UInt64) data).bottom(), 4);
+ } else {
+ appendint(((UInt64) data).bottom(), 4);
+ appendint(((UInt64) data).top(), 4);
+ }
+ break;
+ case ArgumentType.INT32:
+ appendint(((Number) data).intValue(), 4);
+ break;
+ case ArgumentType.UINT16:
+ appendint(((Number) data).intValue(), 2);
+ break;
+ case ArgumentType.INT16:
+ appendint(((Number) data).shortValue(), 2);
+ break;
+ case ArgumentType.STRING:
+ case ArgumentType.OBJECT_PATH:
+ // Strings are marshalled as a UInt32 with the length,
+ // followed by the String, followed by a null byte.
+ String payload = data.toString();
+ byte[] payloadbytes = null;
+ try {
+ payloadbytes = payload.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException UEe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(UEe);
+ throw new DBusException(getString("utf8NotSupported"));
+ }
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending String of length " + payloadbytes.length);
+ appendint(payloadbytes.length, 4);
+ appendBytes(payloadbytes);
+ appendBytes(padding[1]);
+ //pad(ArgumentType.STRING);? do we need this?
+ break;
+ case ArgumentType.SIGNATURE:
+ // Signatures are marshalled as a byte with the length,
+ // followed by the String, followed by a null byte.
+ // Signatures are generally short, so preallocate the array
+ // for the string, length and null byte.
+ if (data instanceof Type[])
+ payload = Marshalling.getDBusType((Type[]) data);
+ else
+ payload = (String) data;
+ byte[] pbytes = payload.getBytes();
+ preallocate(2 + pbytes.length);
+ appendByte((byte) pbytes.length);
+ appendBytes(pbytes);
+ appendByte((byte) 0);
+ break;
+ case ArgumentType.ARRAY:
+ // Arrays are given as a UInt32 for the length in bytes,
+ // padding to the element alignment, then elements in
+ // order. The length is the length from the end of the
+ // initial padding to the end of the last element.
+ if (Debug.debug) {
+ if (data instanceof Object[])
+ Debug.print(Debug.VERBOSE, "Appending array: " + Arrays.deepToString((Object[]) data));
+ }
+
+ byte[] alen = new byte[4];
+ appendBytes(alen);
+ pad(sigb[++i]);
+ long c = bytecounter;
+
+ // optimise primatives
+ if (data.getClass().isArray() &&
+ data.getClass().getComponentType().isPrimitive()) {
+ byte[] primbuf;
+ int algn = getAlignment(sigb[i]);
+ int len = Array.getLength(data);
+ switch (sigb[i]) {
+ case ArgumentType.BYTE:
+ primbuf = (byte[]) data;
+ break;
+ case ArgumentType.INT16:
+ case ArgumentType.INT32:
+ case ArgumentType.INT64:
+ primbuf = new byte[len * algn];
+ for (int j = 0, k = 0; j < len; j++, k += algn)
+ marshallint(Array.getLong(data, j), primbuf, k, algn);
+ break;
+ case ArgumentType.BOOLEAN:
+ primbuf = new byte[len * algn];
+ for (int j = 0, k = 0; j < len; j++, k += algn)
+ marshallint(Array.getBoolean(data, j) ? 1 : 0, primbuf, k, algn);
+ break;
+ case ArgumentType.DOUBLE:
+ primbuf = new byte[len * algn];
+ if (data instanceof float[])
+ for (int j = 0, k = 0; j < len; j++, k += algn)
+ marshallint(Double.doubleToRawLongBits(((float[]) data)[j]),
+ primbuf, k, algn);
+ else
+ for (int j = 0, k = 0; j < len; j++, k += algn)
+ marshallint(Double.doubleToRawLongBits(((double[]) data)[j]),
+ primbuf, k, algn);
+ break;
+ case ArgumentType.FLOAT:
+ primbuf = new byte[len * algn];
+ for (int j = 0, k = 0; j < len; j++, k += algn)
+ marshallint(
+ Float.floatToRawIntBits(((float[]) data)[j]),
+ primbuf, k, algn);
+ break;
+ default:
+ throw new MarshallingException(getString("arraySentAsNonPrimitive"));
+ }
+ appendBytes(primbuf);
+ } else if (data instanceof List) {
+ Object[] contents = ((List) data).toArray();
+ int diff = i;
+ ensureBuffers(contents.length * 4);
+ for (Object o : contents)
+ diff = appendone(sigb, i, o);
+ i = diff;
+ } else if (data instanceof Map) {
+ int diff = i;
+ ensureBuffers(((Map) data).size() * 6);
+ for (Map.Entry<Object, Object> o : ((Map<Object, Object>) data).entrySet())
+ diff = appendone(sigb, i, o);
+ if (i == diff) {
+ // advance the type parser even on 0-size arrays.
+ Vector<Type> temp = new Vector<Type>();
+ byte[] temp2 = new byte[sigb.length - diff];
+ System.arraycopy(sigb, diff, temp2, 0, temp2.length);
+ String temp3 = new String(temp2);
+ int temp4 = Marshalling.getJavaType(temp3, temp, 1);
+ diff += temp4;
+ }
+ i = diff;
+ } else {
+ Object[] contents = (Object[]) data;
+ ensureBuffers(contents.length * 4);
+ int diff = i;
+ for (Object o : contents)
+ diff = appendone(sigb, i, o);
+ i = diff;
+ }
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "start: " + c + " end: " + bytecounter + " length: " + (bytecounter - c));
+ marshallint(bytecounter - c, alen, 0, 4);
+ break;
+ case ArgumentType.STRUCT1:
+ // Structs are aligned to 8 bytes
+ // and simply contain each element marshalled in order
+ Object[] contents;
+ if (data instanceof Container)
+ contents = ((Container) data).getParameters();
+ else
+ contents = (Object[]) data;
+ ensureBuffers(contents.length * 4);
+ int j = 0;
+ for (i++; sigb[i] != ArgumentType.STRUCT2; i++)
+ i = appendone(sigb, i, contents[j++]);
+ break;
+ case ArgumentType.DICT_ENTRY1:
+ // Dict entries are the same as structs.
+ if (data instanceof Map.Entry) {
+ i++;
+ i = appendone(sigb, i, ((Map.Entry) data).getKey());
+ i++;
+ i = appendone(sigb, i, ((Map.Entry) data).getValue());
+ i++;
+ } else {
+ contents = (Object[]) data;
+ j = 0;
+ for (i++; sigb[i] != ArgumentType.DICT_ENTRY2; i++)
+ i = appendone(sigb, i, contents[j++]);
+ }
+ break;
+ case ArgumentType.VARIANT:
+ // Variants are marshalled as a signature
+ // followed by the value.
+ if (data instanceof Variant) {
+ Variant var = (Variant) data;
+ appendone(new byte[]{ArgumentType.SIGNATURE}, 0, var.getSig());
+ appendone((var.getSig()).getBytes(), 0, var.getValue());
+ } else if (data instanceof Object[]) {
+ contents = (Object[]) data;
+ appendone(new byte[]{ArgumentType.SIGNATURE}, 0, contents[0]);
+ appendone(((String) contents[0]).getBytes(), 0, contents[1]);
+ } else {
+ String sig = Marshalling.getDBusType(data.getClass())[0];
+ appendone(new byte[]{ArgumentType.SIGNATURE}, 0, sig);
+ appendone((sig).getBytes(), 0, data);
+ }
+ break;
+ }
+ return i;
+ } catch (ClassCastException CCe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, CCe);
+ throw new MarshallingException(MessageFormat.format(getString("unconvertableType"), new Object[]{data.getClass().getName(), sigb[sigofs]}));
+ }
+ }
+
+ /**
+ * Pad the message to the proper alignment for the given type.
+ */
+ public void pad(byte type) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "padding for " + (char) type);
+ int a = getAlignment(type);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, preallocated + " " + paofs + " " + bytecounter + " " + a);
+ int b = (int) ((bytecounter - preallocated) % a);
+ if (0 == b) return;
+ a = (a - b);
+ if (preallocated > 0) {
+ paofs += a;
+ preallocated -= a;
+ } else
+ appendBytes(padding[a]);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, preallocated + " " + paofs + " " + bytecounter + " " + a);
+ }
+
+ /**
+ * Return the alignment for a given type.
+ */
+ public static int getAlignment(byte type) {
+ switch (type) {
+ case 2:
+ case ArgumentType.INT16:
+ case ArgumentType.UINT16:
+ return 2;
+ case 4:
+ case ArgumentType.BOOLEAN:
+ case ArgumentType.FLOAT:
+ case ArgumentType.INT32:
+ case ArgumentType.UINT32:
+ case ArgumentType.STRING:
+ case ArgumentType.OBJECT_PATH:
+ case ArgumentType.ARRAY:
+ return 4;
+ case 8:
+ case ArgumentType.INT64:
+ case ArgumentType.UINT64:
+ case ArgumentType.DOUBLE:
+ case ArgumentType.STRUCT:
+ case ArgumentType.DICT_ENTRY:
+ case ArgumentType.STRUCT1:
+ case ArgumentType.DICT_ENTRY1:
+ case ArgumentType.STRUCT2:
+ case ArgumentType.DICT_ENTRY2:
+ return 8;
+ case 1:
+ case ArgumentType.BYTE:
+ case ArgumentType.SIGNATURE:
+ case ArgumentType.VARIANT:
+ default:
+ return 1;
+ }
+ }
+
+ /**
+ * Append a series of values to the message.
+ *
+ * @param sig The signature(s) of the value(s).
+ * @param data The value(s).
+ */
+ public void append(String sig, Object... data) throws DBusException {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Appending sig: " + sig + " data: " + Arrays.deepToString(data));
+ byte[] sigb = sig.getBytes();
+ int j = 0;
+ for (int i = 0; i < sigb.length; i++) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending item: " + i + " " + ((char) sigb[i]) + " " + j);
+ i = appendone(sigb, i, data[j++]);
+ }
+ }
+
+ /**
+ * Align a counter to the given type.
+ *
+ * @param current The current counter.
+ * @param type The type to align to.
+ * @return The new, aligned, counter.
+ */
+ public int align(int current, byte type) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "aligning to " + (char) type);
+ int a = getAlignment(type);
+ if (0 == (current % a)) return current;
+ return current + (a - (current % a));
+ }
+
+ /**
+ * Demarshall one value from a buffer.
+ *
+ * @param sigb A buffer of the D-Bus signature.
+ * @param buf The buffer to demarshall from.
+ * @param ofs An array of two ints, the offset into the signature buffer
+ * and the offset into the data buffer. These values will be
+ * updated to the start of the next value ofter demarshalling.
+ * @param contained converts nested arrays to Lists
+ * @return The demarshalled value.
+ */
+ private Object extractone(byte[] sigb, byte[] buf, int[] ofs, boolean contained) throws DBusException {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Extracting type: " + ((char) sigb[ofs[0]]) + " from offset " + ofs[1]);
+ Object rv = null;
+ ofs[1] = align(ofs[1], sigb[ofs[0]]);
+ switch (sigb[ofs[0]]) {
+ case ArgumentType.BYTE:
+ rv = buf[ofs[1]++];
+ break;
+ case ArgumentType.UINT32:
+ rv = new UInt32(demarshallint(buf, ofs[1], 4));
+ ofs[1] += 4;
+ break;
+ case ArgumentType.INT32:
+ rv = (int) demarshallint(buf, ofs[1], 4);
+ ofs[1] += 4;
+ break;
+ case ArgumentType.INT16:
+ rv = (short) demarshallint(buf, ofs[1], 2);
+ ofs[1] += 2;
+ break;
+ case ArgumentType.UINT16:
+ rv = new UInt16((int) demarshallint(buf, ofs[1], 2));
+ ofs[1] += 2;
+ break;
+ case ArgumentType.INT64:
+ rv = demarshallint(buf, ofs[1], 8);
+ ofs[1] += 8;
+ break;
+ case ArgumentType.UINT64:
+ long top;
+ long bottom;
+ if (big) {
+ top = demarshallint(buf, ofs[1], 4);
+ ofs[1] += 4;
+ bottom = demarshallint(buf, ofs[1], 4);
+ } else {
+ bottom = demarshallint(buf, ofs[1], 4);
+ ofs[1] += 4;
+ top = demarshallint(buf, ofs[1], 4);
+ }
+ rv = new UInt64(top, bottom);
+ ofs[1] += 4;
+ break;
+ case ArgumentType.DOUBLE:
+ long l = demarshallint(buf, ofs[1], 8);
+ ofs[1] += 8;
+ rv = Double.longBitsToDouble(l);
+ break;
+ case ArgumentType.FLOAT:
+ int rf = (int) demarshallint(buf, ofs[1], 4);
+ ofs[1] += 4;
+ rv = Float.intBitsToFloat(rf);
+ break;
+ case ArgumentType.BOOLEAN:
+ rf = (int) demarshallint(buf, ofs[1], 4);
+ ofs[1] += 4;
+ rv = (1 == rf) ? Boolean.TRUE : Boolean.FALSE;
+ break;
+ case ArgumentType.ARRAY:
+ long size = demarshallint(buf, ofs[1], 4);
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Reading array of size: " + size);
+ ofs[1] += 4;
+ byte algn = (byte) getAlignment(sigb[++ofs[0]]);
+ ofs[1] = align(ofs[1], sigb[ofs[0]]);
+ int length = (int) (size / algn);
+ if (length > DBusConnection.MAX_ARRAY_LENGTH)
+ throw new MarshallingException(getString("arrayMustNotExceed") + DBusConnection.MAX_ARRAY_LENGTH);
+ // optimise primatives
+ switch (sigb[ofs[0]]) {
+ case ArgumentType.BYTE:
+ rv = new byte[length];
+ System.arraycopy(buf, ofs[1], rv, 0, length);
+ ofs[1] += size;
+ break;
+ case ArgumentType.INT16:
+ rv = new short[length];
+ for (int j = 0; j < length; j++, ofs[1] += algn)
+ ((short[]) rv)[j] = (short) demarshallint(buf, ofs[1], algn);
+ break;
+ case ArgumentType.INT32:
+ rv = new int[length];
+ for (int j = 0; j < length; j++, ofs[1] += algn)
+ ((int[]) rv)[j] = (int) demarshallint(buf, ofs[1], algn);
+ break;
+ case ArgumentType.INT64:
+ rv = new long[length];
+ for (int j = 0; j < length; j++, ofs[1] += algn)
+ ((long[]) rv)[j] = demarshallint(buf, ofs[1], algn);
+ break;
+ case ArgumentType.BOOLEAN:
+ rv = new boolean[length];
+ for (int j = 0; j < length; j++, ofs[1] += algn)
+ ((boolean[]) rv)[j] = (1 == demarshallint(buf, ofs[1], algn));
+ break;
+ case ArgumentType.FLOAT:
+ rv = new float[length];
+ for (int j = 0; j < length; j++, ofs[1] += algn)
+ ((float[]) rv)[j] =
+ Float.intBitsToFloat((int) demarshallint(buf, ofs[1], algn));
+ break;
+ case ArgumentType.DOUBLE:
+ rv = new double[length];
+ for (int j = 0; j < length; j++, ofs[1] += algn)
+ ((double[]) rv)[j] =
+ Double.longBitsToDouble(demarshallint(buf, ofs[1], algn));
+ break;
+ case ArgumentType.DICT_ENTRY1:
+ if (0 == size) {
+ // advance the type parser even on 0-size arrays.
+ Vector<Type> temp = new Vector<Type>();
+ byte[] temp2 = new byte[sigb.length - ofs[0]];
+ System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length);
+ String temp3 = new String(temp2);
+ // ofs[0] gets incremented anyway. Leave one character on the stack
+ int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1;
+ ofs[0] += temp4;
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]);
+ }
+ int ofssave = ofs[0];
+ long end = ofs[1] + size;
+ Vector<Object[]> entries = new Vector<Object[]>();
+ while (ofs[1] < end) {
+ ofs[0] = ofssave;
+ entries.add((Object[]) extractone(sigb, buf, ofs, true));
+ }
+ rv = new DBusMap<Object, Object>(entries.toArray(new Object[0][]));
+ break;
+ default:
+ if (0 == size) {
+ // advance the type parser even on 0-size arrays.
+ Vector<Type> temp = new Vector<Type>();
+ byte[] temp2 = new byte[sigb.length - ofs[0]];
+ System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length);
+ String temp3 = new String(temp2);
+ // ofs[0] gets incremented anyway. Leave one character on the stack
+ int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1;
+ ofs[0] += temp4;
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]);
+ }
+ ofssave = ofs[0];
+ end = ofs[1] + size;
+ Vector<Object> contents = new Vector<Object>();
+ while (ofs[1] < end) {
+ ofs[0] = ofssave;
+ contents.add(extractone(sigb, buf, ofs, true));
+ }
+ rv = contents;
+ }
+ if (contained && !(rv instanceof List) && !(rv instanceof Map))
+ rv = ArrayFrob.listify(rv);
+ break;
+ case ArgumentType.STRUCT1:
+ Vector<Object> contents = new Vector<Object>();
+ while (sigb[++ofs[0]] != ArgumentType.STRUCT2)
+ contents.add(extractone(sigb, buf, ofs, true));
+ rv = contents.toArray();
+ break;
+ case ArgumentType.DICT_ENTRY1:
+ Object[] decontents = new Object[2];
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Extracting Dict Entry (" + Hexdump.toAscii(sigb, ofs[0], sigb.length - ofs[0]) + ") from: " + Hexdump.toHex(buf, ofs[1], buf.length - ofs[1]));
+ ofs[0]++;
+ decontents[0] = extractone(sigb, buf, ofs, true);
+ ofs[0]++;
+ decontents[1] = extractone(sigb, buf, ofs, true);
+ ofs[0]++;
+ rv = decontents;
+ break;
+ case ArgumentType.VARIANT:
+ int[] newofs = new int[]{0, ofs[1]};
+ String sig = (String) extract(ArgumentType.SIGNATURE_STRING, buf, newofs)[0];
+ newofs[0] = 0;
+ rv = new Variant<Object>(extract(sig, buf, newofs)[0], sig);
+ ofs[1] = newofs[1];
+ break;
+ case ArgumentType.STRING:
+ length = (int) demarshallint(buf, ofs[1], 4);
+ ofs[1] += 4;
+ try {
+ rv = new String(buf, ofs[1], length, "UTF-8");
+ } catch (UnsupportedEncodingException UEe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(UEe);
+ throw new DBusException(getString("utf8NotSupported"));
+ }
+ ofs[1] += length + 1;
+ break;
+ case ArgumentType.OBJECT_PATH:
+ length = (int) demarshallint(buf, ofs[1], 4);
+ ofs[1] += 4;
+ rv = new ObjectPath(getSource(), new String(buf, ofs[1], length));
+ ofs[1] += length + 1;
+ break;
+ case ArgumentType.SIGNATURE:
+ length = (buf[ofs[1]++] & 0xFF);
+ rv = new String(buf, ofs[1], length);
+ ofs[1] += length + 1;
+ break;
+ default:
+ throw new UnknownTypeCodeException(sigb[ofs[0]]);
+ }
+ if (Debug.debug) if (rv instanceof Object[])
+ Debug.print(Debug.VERBOSE, "Extracted: " + Arrays.deepToString((Object[]) rv) + " (now at " + ofs[1] + ")");
+ else
+ Debug.print(Debug.VERBOSE, "Extracted: " + rv + " (now at " + ofs[1] + ")");
+ return rv;
+ }
+
+ /**
+ * Demarshall values from a buffer.
+ *
+ * @param sig The D-Bus signature(s) of the value(s).
+ * @param buf The buffer to demarshall from.
+ * @param ofs The offset into the data buffer to start.
+ * @return The demarshalled value(s).
+ */
+ public Object[] extract(String sig, byte[] buf, int ofs) throws DBusException {
+ return extract(sig, buf, new int[]{0, ofs});
+ }
+
+ /**
+ * Demarshall values from a buffer.
+ *
+ * @param sig The D-Bus signature(s) of the value(s).
+ * @param buf The buffer to demarshall from.
+ * @param ofs An array of two ints, the offset into the signature
+ * and the offset into the data buffer. These values will be
+ * updated to the start of the next value ofter demarshalling.
+ * @return The demarshalled value(s).
+ */
+ public Object[] extract(String sig, byte[] buf, int[] ofs) throws DBusException {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "extract(" + sig + ",#" + buf.length + ", {" + ofs[0] + "," + ofs[1] + "}");
+ Vector<Object> rv = new Vector<Object>();
+ byte[] sigb = sig.getBytes();
+ for (int[] i = ofs; i[0] < sigb.length; i[0]++) {
+ rv.add(extractone(sigb, buf, i, false));
+ }
+ return rv.toArray();
+ }
+
+ /**
+ * Returns the Bus ID that sent the message.
+ */
+ public String getSource() {
+ return (String) headers.get(HeaderField.SENDER);
+ }
+
+ /**
+ * Returns the destination of the message.
+ */
+ public String getDestination() {
+ return (String) headers.get(HeaderField.DESTINATION);
+ }
+
+ /**
+ * Returns the interface of the message.
+ */
+ public String getInterface() {
+ return (String) headers.get(HeaderField.INTERFACE);
+ }
+
+ /**
+ * Returns the object path of the message.
+ */
+ public String getPath() {
+ Object o = headers.get(HeaderField.PATH);
+ if (null == o) return null;
+ return o.toString();
+ }
+
+ /**
+ * Returns the member name or error name this message represents.
+ */
+ public String getName() {
+ if (this instanceof Error)
+ return (String) headers.get(HeaderField.ERROR_NAME);
+ else
+ return (String) headers.get(HeaderField.MEMBER);
+ }
+
+ /**
+ * Returns the dbus signature of the parameters.
+ */
+ public String getSig() {
+ return (String) headers.get(HeaderField.SIGNATURE);
+ }
+
+ /**
+ * Returns the message flags.
+ */
+ public int getFlags() {
+ return flags;
+ }
+
+ /**
+ * Returns the message serial ID (unique for this connection)
+ *
+ * @return the message serial.
+ */
+ public long getSerial() {
+ return serial;
+ }
+
+ /**
+ * If this is a reply to a message, this returns its serial.
+ *
+ * @return The reply serial, or 0 if it is not a reply.
+ */
+ public long getReplySerial() {
+ Number l = (Number) headers.get(HeaderField.REPLY_SERIAL);
+ if (null == l) return 0;
+ return l.longValue();
+ }
+
+ /**
+ * Parses and returns the parameters to this message as an Object array.
+ */
+ public Object[] getParameters() throws DBusException {
+ if (null == args && null != body) {
+ String sig = (String) headers.get(HeaderField.SIGNATURE);
+ if (null != sig && 0 != body.length) {
+ args = extract(sig, body, 0);
+ } else args = new Object[0];
+ }
+ return args;
+ }
+
+ protected void setArgs(Object[] args) {
+ this.args = args;
+ }
+
+ /**
+ * Warning, do not use this method unless you really know what you are doing.
+ */
+ public void setSource(String source) throws DBusException {
+ if (null != body) {
+ wiredata = new byte[BUFFERINCREMENT][];
+ bufferuse = 0;
+ bytecounter = 0;
+ preallocate(12);
+ append("yyyyuu", big ? Endian.BIG : Endian.LITTLE, type, flags, protover, bodylen, serial);
+ headers.put(HeaderField.SENDER, source);
+ Object[][] newhead = new Object[headers.size()][];
+ int i = 0;
+ for (Byte b : headers.keySet()) {
+ newhead[i] = new Object[2];
+ newhead[i][0] = b;
+ newhead[i][1] = headers.get(b);
+ i++;
+ }
+ append("a(yv)", (Object) newhead);
+ pad((byte) 8);
+ appendBytes(body);
+ }
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageReader.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageReader.java
new file mode 100644
index 0000000..4dbea00
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageReader.java
@@ -0,0 +1,194 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.utils.Hexdump;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MessageProtocolVersionException;
+import org.freedesktop.dbus.exceptions.MessageTypeException;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketTimeoutException;
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class MessageReader {
+ private InputStream in;
+ private byte[] buf = null;
+ private byte[] tbuf = null;
+ private byte[] header = null;
+ private byte[] body = null;
+ private int[] len = new int[4];
+
+ public MessageReader(InputStream in) {
+ this.in = new BufferedInputStream(in);
+ }
+
+ public Message readMessage() throws IOException, DBusException {
+ int rv;
+ /* Read the 12 byte fixed header, retrying as neccessary */
+ if (null == buf) {
+ buf = new byte[12];
+ len[0] = 0;
+ }
+ if (len[0] < 12) {
+ try {
+ rv = in.read(buf, len[0], 12 - len[0]);
+ } catch (SocketTimeoutException STe) {
+ return null;
+ }
+ if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+ len[0] += rv;
+ }
+ if (len[0] == 0) return null;
+ if (len[0] < 12) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[0] + " of 12 bytes of header");
+ return null;
+ }
+
+ /* Parse the details from the header */
+ byte endian = buf[0];
+ byte type = buf[1];
+ byte protover = buf[3];
+ if (protover > Message.PROTOCOL) {
+ buf = null;
+ throw new MessageProtocolVersionException(MessageFormat.format(getString("protocolVersionUnsupported"), new Object[]{protover}));
+ }
+
+ /* Read the length of the variable header */
+ if (null == tbuf) {
+ tbuf = new byte[4];
+ len[1] = 0;
+ }
+ if (len[1] < 4) {
+ try {
+ rv = in.read(tbuf, len[1], 4 - len[1]);
+ } catch (SocketTimeoutException STe) {
+ return null;
+ }
+ if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+ len[1] += rv;
+ }
+ if (len[1] < 4) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[1] + " of 4 bytes of header");
+ return null;
+ }
+
+ /* Parse the variable header length */
+ int headerlen = 0;
+ if (null == header) {
+ headerlen = (int) Message.demarshallint(tbuf, 0, endian, 4);
+ if (0 != headerlen % 8)
+ headerlen += 8 - (headerlen % 8);
+ } else
+ headerlen = header.length - 8;
+
+ /* Read the variable header */
+ if (null == header) {
+ header = new byte[headerlen + 8];
+ System.arraycopy(tbuf, 0, header, 0, 4);
+ len[2] = 0;
+ }
+ if (len[2] < headerlen) {
+ try {
+ rv = in.read(header, 8 + len[2], headerlen - len[2]);
+ } catch (SocketTimeoutException STe) {
+ return null;
+ }
+ if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+ len[2] += rv;
+ }
+ if (len[2] < headerlen) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[2] + " of " + headerlen + " bytes of header");
+ return null;
+ }
+
+ /* Read the body */
+ int bodylen = 0;
+ if (null == body) bodylen = (int) Message.demarshallint(buf, 4, endian, 4);
+ if (null == body) {
+ body = new byte[bodylen];
+ len[3] = 0;
+ }
+ if (len[3] < body.length) {
+ try {
+ rv = in.read(body, len[3], body.length - len[3]);
+ } catch (SocketTimeoutException STe) {
+ return null;
+ }
+ if (-1 == rv) throw new EOFException(getString("transportReturnedEOF"));
+ len[3] += rv;
+ }
+ if (len[3] < body.length) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[3] + " of " + body.length + " bytes of body");
+ return null;
+ }
+
+ Message m;
+ switch (type) {
+ case Message.MessageType.METHOD_CALL:
+ m = new MethodCall();
+ break;
+ case Message.MessageType.METHOD_RETURN:
+ m = new MethodReturn();
+ break;
+ case Message.MessageType.SIGNAL:
+ m = new DBusSignal();
+ break;
+ case Message.MessageType.ERROR:
+ m = new Error();
+ break;
+ default:
+ throw new MessageTypeException(MessageFormat.format(getString("messageTypeUnsupported"), new Object[]{type}));
+ }
+ if (Debug.debug) {
+ Debug.print(Debug.VERBOSE, Hexdump.format(buf));
+ Debug.print(Debug.VERBOSE, Hexdump.format(tbuf));
+ Debug.print(Debug.VERBOSE, Hexdump.format(header));
+ Debug.print(Debug.VERBOSE, Hexdump.format(body));
+ }
+ try {
+ m.populate(buf, header, body);
+ } catch (DBusException DBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ buf = null;
+ tbuf = null;
+ body = null;
+ header = null;
+ throw DBe;
+ } catch (RuntimeException Re) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, Re);
+ buf = null;
+ tbuf = null;
+ body = null;
+ header = null;
+ throw Re;
+ }
+ if (Debug.debug) {
+ Debug.print(Debug.INFO, "=> " + m);
+ }
+ buf = null;
+ tbuf = null;
+ body = null;
+ header = null;
+ return m;
+ }
+
+ public void close() throws IOException {
+ if (Debug.debug) Debug.print(Debug.INFO, "Closing Message Reader");
+ in.close();
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java
new file mode 100644
index 0000000..45e8cb7
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java
@@ -0,0 +1,67 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.unix.USOutputStream;
+import cx.ath.matthew.utils.Hexdump;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class MessageWriter {
+ private OutputStream out;
+ private boolean isunix;
+
+ public MessageWriter(OutputStream out) {
+ this.out = out;
+ this.isunix = false;
+ try {
+ if (out instanceof USOutputStream)
+ this.isunix = true;
+ } catch (Throwable t) {
+ }
+ if (!this.isunix)
+ this.out = new BufferedOutputStream(this.out);
+ }
+
+ public void writeMessage(Message m) throws IOException {
+ if (Debug.debug) {
+ Debug.print(Debug.INFO, "<= " + m);
+ }
+ if (null == m) return;
+ if (null == m.getWireData()) {
+ if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!");
+ return;
+ }
+ if (isunix) {
+ if (Debug.debug) {
+ Debug.print(Debug.DEBUG, "Writing all " + m.getWireData().length + " buffers simultaneously to Unix Socket");
+ for (byte[] buf : m.getWireData())
+ Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
+ }
+ ((USOutputStream) out).write(m.getWireData());
+ } else
+ for (byte[] buf : m.getWireData()) {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
+ if (null == buf) break;
+ out.write(buf);
+ }
+ out.flush();
+ }
+
+ public void close() throws IOException {
+ if (Debug.debug) Debug.print(Debug.INFO, "Closing Message Writer");
+ out.close();
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MethodCall.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodCall.java
new file mode 100644
index 0000000..72242cc
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodCall.java
@@ -0,0 +1,137 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.utils.Hexdump;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.MessageFormatException;
+
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class MethodCall extends Message {
+ MethodCall() {
+ }
+
+ public MethodCall(String dest, String path, String iface, String member, byte flags, String sig, Object... args) throws DBusException {
+ this(null, dest, path, iface, member, flags, sig, args);
+ }
+
+ public MethodCall(String source, String dest, String path, String iface, String member, byte flags, String sig, Object... args) throws DBusException {
+ super(Message.Endian.BIG, Message.MessageType.METHOD_CALL, flags);
+
+ if (null == member || null == path)
+ throw new MessageFormatException(getString("missingDestinationPathFunction"));
+ headers.put(Message.HeaderField.PATH, path);
+ headers.put(Message.HeaderField.MEMBER, member);
+
+ Vector<Object> hargs = new Vector<Object>();
+
+ hargs.add(new Object[]{Message.HeaderField.PATH, new Object[]{ArgumentType.OBJECT_PATH_STRING, path}});
+
+ if (null != source) {
+ headers.put(Message.HeaderField.SENDER, source);
+ hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+ }
+
+ if (null != dest) {
+ headers.put(Message.HeaderField.DESTINATION, dest);
+ hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
+ }
+
+ if (null != iface) {
+ hargs.add(new Object[]{Message.HeaderField.INTERFACE, new Object[]{ArgumentType.STRING_STRING, iface}});
+ headers.put(Message.HeaderField.INTERFACE, iface);
+ }
+
+ hargs.add(new Object[]{Message.HeaderField.MEMBER, new Object[]{ArgumentType.STRING_STRING, member}});
+
+ if (null != sig) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Appending arguments with signature: " + sig);
+ hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+ headers.put(Message.HeaderField.SIGNATURE, sig);
+ setArgs(args);
+ }
+
+ byte[] blen = new byte[4];
+ appendBytes(blen);
+ append("ua(yv)", serial, hargs.toArray());
+ pad((byte) 8);
+
+ long c = bytecounter;
+ if (null != sig) append(sig, args);
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Appended body, type: " + sig + " start: " + c + " end: " + bytecounter + " size: " + (bytecounter - c));
+ marshallint(bytecounter - c, blen, 0, 4);
+ if (Debug.debug) Debug.print("marshalled size (" + blen + "): " + Hexdump.format(blen));
+ }
+
+ private static long REPLY_WAIT_TIMEOUT = 20000;
+
+ /**
+ * Set the default timeout for method calls.
+ * Default is 20s.
+ *
+ * @param timeout New timeout in ms.
+ */
+ public static void setDefaultTimeout(long timeout) {
+ REPLY_WAIT_TIMEOUT = timeout;
+ }
+
+ Message reply = null;
+
+ public synchronized boolean hasReply() {
+ return null != reply;
+ }
+
+ /**
+ * Block (if neccessary) for a reply.
+ *
+ * @param timeout The length of time to block before timing out (ms).
+ * @return The reply to this MethodCall, or null if a timeout happens.
+ */
+ public synchronized Message getReply(long timeout) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking on " + this);
+ if (null != reply) return reply;
+ try {
+ wait(timeout);
+ return reply;
+ } catch (InterruptedException Ie) {
+ return reply;
+ }
+ }
+
+ /**
+ * Block (if neccessary) for a reply.
+ * Default timeout is 20s, or can be configured with setDefaultTimeout()
+ *
+ * @return The reply to this MethodCall, or null if a timeout happens.
+ */
+ public synchronized Message getReply() {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Blocking on " + this);
+ if (null != reply) return reply;
+ try {
+ wait(REPLY_WAIT_TIMEOUT);
+ return reply;
+ } catch (InterruptedException Ie) {
+ return reply;
+ }
+ }
+
+ protected synchronized void setReply(Message reply) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting reply to " + this + " to " + reply);
+ this.reply = reply;
+ notifyAll();
+ }
+
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MethodReturn.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodReturn.java
new file mode 100644
index 0000000..35f4d0d
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodReturn.java
@@ -0,0 +1,77 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.Vector;
+
+public class MethodReturn extends Message {
+ MethodReturn() {
+ }
+
+ public MethodReturn(String dest, long replyserial, String sig, Object... args) throws DBusException {
+ this(null, dest, replyserial, sig, args);
+ }
+
+ public MethodReturn(String source, String dest, long replyserial, String sig, Object... args) throws DBusException {
+ super(Message.Endian.BIG, Message.MessageType.METHOD_RETURN, (byte) 0);
+
+ headers.put(Message.HeaderField.REPLY_SERIAL, replyserial);
+
+ Vector<Object> hargs = new Vector<Object>();
+ hargs.add(new Object[]{Message.HeaderField.REPLY_SERIAL, new Object[]{ArgumentType.UINT32_STRING, replyserial}});
+
+ if (null != source) {
+ headers.put(Message.HeaderField.SENDER, source);
+ hargs.add(new Object[]{Message.HeaderField.SENDER, new Object[]{ArgumentType.STRING_STRING, source}});
+ }
+
+ if (null != dest) {
+ headers.put(Message.HeaderField.DESTINATION, dest);
+ hargs.add(new Object[]{Message.HeaderField.DESTINATION, new Object[]{ArgumentType.STRING_STRING, dest}});
+ }
+
+ if (null != sig) {
+ hargs.add(new Object[]{Message.HeaderField.SIGNATURE, new Object[]{ArgumentType.SIGNATURE_STRING, sig}});
+ headers.put(Message.HeaderField.SIGNATURE, sig);
+ setArgs(args);
+ }
+
+ byte[] blen = new byte[4];
+ appendBytes(blen);
+ append("ua(yv)", serial, hargs.toArray());
+ pad((byte) 8);
+
+ long c = bytecounter;
+ if (null != sig) append(sig, args);
+ marshallint(bytecounter - c, blen, 0, 4);
+ }
+
+ public MethodReturn(MethodCall mc, String sig, Object... args) throws DBusException {
+ this(null, mc, sig, args);
+ }
+
+ public MethodReturn(String source, MethodCall mc, String sig, Object... args) throws DBusException {
+ this(source, mc.getSource(), mc.getSerial(), sig, args);
+ this.call = mc;
+ }
+
+ MethodCall call;
+
+ public MethodCall getCall() {
+ return call;
+ }
+
+ protected void setCall(MethodCall call) {
+ this.call = call;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MethodTuple.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodTuple.java
new file mode 100644
index 0000000..d135714
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MethodTuple.java
@@ -0,0 +1,37 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+class MethodTuple {
+ String name;
+ String sig;
+
+ public MethodTuple(String name, String sig) {
+ this.name = name;
+ if (null != sig)
+ this.sig = sig;
+ else
+ this.sig = "";
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "new MethodTuple(" + this.name + ", " + this.sig + ")");
+ }
+
+ public boolean equals(Object o) {
+ return o.getClass().equals(MethodTuple.class)
+ && ((MethodTuple) o).name.equals(this.name)
+ && ((MethodTuple) o).sig.equals(this.sig);
+ }
+
+ public int hashCode() {
+ return name.hashCode() + sig.hashCode();
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectPath.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectPath.java
new file mode 100644
index 0000000..5ea1158
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectPath.java
@@ -0,0 +1,22 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+class ObjectPath extends Path {
+ public String source;
+
+ // public DBusConnection conn;
+ public ObjectPath(String source, String path/*, DBusConnection conn*/) {
+ super(path);
+ this.source = source;
+ // this.conn = conn;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectTree.java b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectTree.java
new file mode 100644
index 0000000..0332e6a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/ObjectTree.java
@@ -0,0 +1,158 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+import java.util.regex.Pattern;
+
+/**
+ * Keeps track of the exported objects for introspection data
+ */
+class ObjectTree {
+ class TreeNode {
+ String name;
+ ExportedObject object;
+ String data;
+ TreeNode right;
+ TreeNode down;
+
+ public TreeNode(String name) {
+ this.name = name;
+ }
+
+ public TreeNode(String name, ExportedObject object, String data) {
+ this.name = name;
+ this.object = object;
+ this.data = data;
+ }
+ }
+
+ private TreeNode root;
+
+ public ObjectTree() {
+ root = new TreeNode("");
+ }
+
+ public static final Pattern slashpattern = Pattern.compile("/");
+
+ private TreeNode recursiveFind(TreeNode current, String path) {
+ if ("/".equals(path)) return current;
+ String[] elements = path.split("/", 2);
+ // this is us or a parent node
+ if (path.startsWith(current.name)) {
+ // this is us
+ if (path.equals(current.name)) {
+ return current;
+ }
+ // recurse down
+ else {
+ if (current.down == null)
+ return null;
+ else return recursiveFind(current.down, elements[1]);
+ }
+ } else if (current.right == null) {
+ return null;
+ } else if (0 > current.right.name.compareTo(elements[0])) {
+ return null;
+ }
+ // recurse right
+ else {
+ return recursiveFind(current.right, path);
+ }
+ }
+
+ private TreeNode recursiveAdd(TreeNode current, String path, ExportedObject object, String data) {
+ String[] elements = slashpattern.split(path, 2);
+ // this is us or a parent node
+ if (path.startsWith(current.name)) {
+ // this is us
+ if (1 == elements.length || "".equals(elements[1])) {
+ current.object = object;
+ current.data = data;
+ }
+ // recurse down
+ else {
+ if (current.down == null) {
+ String[] el = elements[1].split("/", 2);
+ current.down = new TreeNode(el[0]);
+ }
+ current.down = recursiveAdd(current.down, elements[1], object, data);
+ }
+ }
+ // need to create a new sub-tree on the end
+ else if (current.right == null) {
+ current.right = new TreeNode(elements[0]);
+ current.right = recursiveAdd(current.right, path, object, data);
+ }
+ // need to insert here
+ else if (0 > current.right.name.compareTo(elements[0])) {
+ TreeNode t = new TreeNode(elements[0]);
+ t.right = current.right;
+ current.right = t;
+ current.right = recursiveAdd(current.right, path, object, data);
+ }
+ // recurse right
+ else {
+ current.right = recursiveAdd(current.right, path, object, data);
+ }
+ return current;
+ }
+
+ public void add(String path, ExportedObject object, String data) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Adding " + path + " to object tree");
+ root = recursiveAdd(root, path, object, data);
+ }
+
+ public void remove(String path) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Removing " + path + " from object tree");
+ TreeNode t = recursiveFind(root, path);
+ t.object = null;
+ t.data = null;
+ }
+
+ public String Introspect(String path) {
+ TreeNode t = recursiveFind(root, path);
+ if (null == t) return null;
+ StringBuilder sb = new StringBuilder();
+ sb.append("<node name=\"");
+ sb.append(path);
+ sb.append("\">\n");
+ if (null != t.data) sb.append(t.data);
+ t = t.down;
+ while (null != t) {
+ sb.append("<node name=\"");
+ sb.append(t.name);
+ sb.append("\"/>\n");
+ t = t.right;
+ }
+ sb.append("</node>");
+ return sb.toString();
+ }
+
+ private String recursivePrint(TreeNode current) {
+ String s = "";
+ if (null != current) {
+ s += current.name;
+ if (null != current.object)
+ s += "*";
+ if (null != current.down)
+ s += "/{" + recursivePrint(current.down) + "}";
+ if (null != current.right)
+ s += ", " + recursivePrint(current.right);
+ }
+ return s;
+ }
+
+ public String toString() {
+ return recursivePrint(root);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Path.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Path.java
new file mode 100644
index 0000000..91a5a6d
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Path.java
@@ -0,0 +1,39 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public class Path implements Comparable<Path> {
+ protected String path;
+
+ public Path(String path) {
+ this.path = path;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String toString() {
+ return path;
+ }
+
+ public boolean equals(Object other) {
+ return (other instanceof Path) && path.equals(((Path) other).path);
+ }
+
+ public int hashCode() {
+ return path.hashCode();
+ }
+
+ public int compareTo(Path that) {
+ return path.compareTo(that.path);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Position.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Position.java
new file mode 100644
index 0000000..ed0bb11
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Position.java
@@ -0,0 +1,29 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Position annotation, to annotate Struct fields
+ * to be sent over DBus.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Position {
+ /**
+ * The order of this field in the Struct.
+ */
+ int value();
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java
new file mode 100644
index 0000000..f6b7867
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java
@@ -0,0 +1,187 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+class RemoteInvocationHandler implements InvocationHandler {
+ public static final int CALL_TYPE_SYNC = 0;
+ public static final int CALL_TYPE_ASYNC = 1;
+ public static final int CALL_TYPE_CALLBACK = 2;
+
+ public static Object convertRV(String sig, Object[] rp, Method m, AbstractConnection conn) throws DBusException {
+ Class<? extends Object> c = m.getReturnType();
+
+ if (null == rp) {
+ if (null == c || Void.TYPE.equals(c)) return null;
+ else throw new DBusExecutionException(getString("voidReturnType"));
+ } else {
+ try {
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Converting return parameters from " + Arrays.deepToString(rp) + " to type " + m.getGenericReturnType());
+ rp = Marshalling.deSerializeParameters(rp,
+ new Type[]{m.getGenericReturnType()}, conn);
+ } catch (Exception e) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusExecutionException(MessageFormat.format(getString("invalidReturnType"), new Object[]{e.getMessage()}));
+ }
+ }
+
+ switch (rp.length) {
+ case 0:
+ if (null == c || Void.TYPE.equals(c))
+ return null;
+ else throw new DBusExecutionException(getString("voidReturnType"));
+ case 1:
+ return rp[0];
+ default:
+
+ // check we are meant to return multiple values
+ if (!Tuple.class.isAssignableFrom(c))
+ throw new DBusExecutionException(getString("tupleReturnType"));
+
+ Constructor<? extends Object> cons = c.getConstructors()[0];
+ try {
+ return cons.newInstance(rp);
+ } catch (Exception e) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusException(e.getMessage());
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Object executeRemoteMethod(RemoteObject ro, Method m, AbstractConnection conn, int syncmethod, CallbackHandler callback, Object... args) throws DBusExecutionException {
+ Type[] ts = m.getGenericParameterTypes();
+ String sig = null;
+ if (ts.length > 0) try {
+ sig = Marshalling.getDBusType(ts);
+ args = Marshalling.convertParameters(args, ts, conn);
+ } catch (DBusException DBe) {
+ throw new DBusExecutionException(getString("contructDBusTypeFailure") + DBe.getMessage());
+ }
+ MethodCall call;
+ byte flags = 0;
+ if (!ro.autostart) flags |= Message.Flags.NO_AUTO_START;
+ if (syncmethod == CALL_TYPE_ASYNC) flags |= Message.Flags.ASYNC;
+ if (m.isAnnotationPresent(DBus.Method.NoReply.class)) flags |= Message.Flags.NO_REPLY_EXPECTED;
+ try {
+ String name;
+ if (m.isAnnotationPresent(DBusMemberName.class))
+ name = m.getAnnotation(DBusMemberName.class).value();
+ else
+ name = m.getName();
+ if (null == ro.iface)
+ call = new MethodCall(ro.busname, ro.objectpath, null, name, flags, sig, args);
+ else {
+ if (null != ro.iface.getAnnotation(DBusInterfaceName.class)) {
+ call = new MethodCall(ro.busname, ro.objectpath, ro.iface.getAnnotation(DBusInterfaceName.class).value(), name, flags, sig, args);
+ } else
+ call = new MethodCall(ro.busname, ro.objectpath, AbstractConnection.dollar_pattern.matcher(ro.iface.getName()).replaceAll("."), name, flags, sig, args);
+ }
+ } catch (DBusException DBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ throw new DBusExecutionException(getString("constructOutgoingMethodCallFailure") + DBe.getMessage());
+ }
+ if (null == conn.outgoing) throw new NotConnected(getString("notConnected"));
+
+ switch (syncmethod) {
+ case CALL_TYPE_ASYNC:
+ conn.queueOutgoing(call);
+ return new DBusAsyncReply(call, m, conn);
+ case CALL_TYPE_CALLBACK:
+ synchronized (conn.pendingCallbacks) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Queueing Callback " + callback + " for " + call);
+ conn.pendingCallbacks.put(call, callback);
+ conn.pendingCallbackReplys.put(call, new DBusAsyncReply(call, m, conn));
+ }
+ conn.queueOutgoing(call);
+ return null;
+ case CALL_TYPE_SYNC:
+ conn.queueOutgoing(call);
+ break;
+ }
+
+ // get reply
+ if (m.isAnnotationPresent(DBus.Method.NoReply.class)) return null;
+
+ Message reply = call.getReply();
+ if (null == reply) throw new DBus.Error.NoReply(getString("notReplyWithSpecifiedTime"));
+
+ if (reply instanceof Error)
+ ((Error) reply).throwException();
+
+ try {
+ return convertRV(reply.getSig(), reply.getParameters(), m, conn);
+ } catch (DBusException e) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, e);
+ throw new DBusExecutionException(e.getMessage());
+ }
+ }
+
+ AbstractConnection conn;
+ RemoteObject remote;
+
+ public RemoteInvocationHandler(AbstractConnection conn, RemoteObject remote) {
+ this.remote = remote;
+ this.conn = conn;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("isRemote")) return true;
+ else if (method.getName().equals("clone")) return null;
+ else if (method.getName().equals("equals")) {
+ try {
+ if (1 == args.length)
+ return new Boolean(remote.equals(((RemoteInvocationHandler) Proxy.getInvocationHandler(args[0])).remote));
+ } catch (IllegalArgumentException IAe) {
+ return Boolean.FALSE;
+ }
+ } else if (method.getName().equals("finalize")) return null;
+ else if (method.getName().equals("getClass")) return DBusInterface.class;
+ else if (method.getName().equals("hashCode")) return remote.hashCode();
+ else if (method.getName().equals("notify")) {
+ remote.notify();
+ return null;
+ } else if (method.getName().equals("notifyAll")) {
+ remote.notifyAll();
+ return null;
+ } else if (method.getName().equals("wait")) {
+ if (0 == args.length) remote.wait();
+ else if (1 == args.length
+ && args[0] instanceof Long) remote.wait((Long) args[0]);
+ else if (2 == args.length
+ && args[0] instanceof Long
+ && args[1] instanceof Integer)
+ remote.wait((Long) args[0], (Integer) args[1]);
+ if (args.length <= 2)
+ return null;
+ } else if (method.getName().equals("toString"))
+ return remote.toString();
+
+ return executeRemoteMethod(remote, method, conn, CALL_TYPE_SYNC, null, args);
+ }
+}
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteObject.java b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteObject.java
new file mode 100644
index 0000000..c157d12
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/RemoteObject.java
@@ -0,0 +1,67 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+class RemoteObject {
+ String busname;
+ String objectpath;
+ Class<? extends DBusInterface> iface;
+ boolean autostart;
+
+ public RemoteObject(String busname, String objectpath, Class<? extends DBusInterface> iface, boolean autostart) {
+ this.busname = busname;
+ this.objectpath = objectpath;
+ this.iface = iface;
+ this.autostart = autostart;
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof RemoteObject)) return false;
+ RemoteObject them = (RemoteObject) o;
+
+ if (!them.objectpath.equals(this.objectpath)) return false;
+
+ if (null == this.busname && null != them.busname) return false;
+ if (null != this.busname && null == them.busname) return false;
+ if (null != them.busname && !them.busname.equals(this.busname)) return false;
+
+ if (null == this.iface && null != them.iface) return false;
+ if (null != this.iface && null == them.iface) return false;
+ if (null != them.iface && !them.iface.equals(this.iface)) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (null == busname ? 0 : busname.hashCode()) + objectpath.hashCode() +
+ (null == iface ? 0 : iface.hashCode());
+ }
+
+ public boolean autoStarting() {
+ return autostart;
+ }
+
+ public String getBusName() {
+ return busname;
+ }
+
+ public String getObjectPath() {
+ return objectpath;
+ }
+
+ public Class<? extends DBusInterface> getInterface() {
+ return iface;
+ }
+
+ public String toString() {
+ return busname + ":" + objectpath + ":" + iface;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/SignalTuple.java b/federation/sssd/src/main/java/org/freedesktop/dbus/SignalTuple.java
new file mode 100644
index 0000000..29ec987
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/SignalTuple.java
@@ -0,0 +1,51 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+class SignalTuple {
+ String type;
+ String name;
+ String object;
+ String source;
+
+ public SignalTuple(String type, String name, String object, String source) {
+ this.type = type;
+ this.name = name;
+ this.object = object;
+ this.source = source;
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof SignalTuple)) return false;
+ SignalTuple other = (SignalTuple) o;
+ if (null == this.type && null != other.type) return false;
+ if (null != this.type && !this.type.equals(other.type)) return false;
+ if (null == this.name && null != other.name) return false;
+ if (null != this.name && !this.name.equals(other.name)) return false;
+ if (null == this.object && null != other.object) return false;
+ if (null != this.object && !this.object.equals(other.object)) return false;
+ if (null == this.source && null != other.source) return false;
+ if (null != this.source && !this.source.equals(other.source)) return false;
+ return true;
+ }
+
+ public int hashCode() {
+ return (null == type ? 0 : type.hashCode())
+ + (null == name ? 0 : name.hashCode())
+ + (null == source ? 0 : source.hashCode())
+ + (null == object ? 0 : object.hashCode());
+ }
+
+ public String toString() {
+ return "SignalTuple(" + type + "," + name + "," + object + "," + source + ")";
+ }
+}
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/StrongReference.java b/federation/sssd/src/main/java/org/freedesktop/dbus/StrongReference.java
new file mode 100644
index 0000000..d5358ec
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/StrongReference.java
@@ -0,0 +1,42 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * An alternative to a WeakReference when you don't want
+ * that behaviour.
+ */
+public class StrongReference<T> extends WeakReference<T> {
+ T referant;
+
+ public StrongReference(T referant) {
+ super(referant);
+ this.referant = referant;
+ }
+
+ public void clear() {
+ referant = null;
+ }
+
+ public boolean enqueue() {
+ return false;
+ }
+
+ public T get() {
+ return referant;
+ }
+
+ public boolean isEnqueued() {
+ return false;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Struct.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Struct.java
new file mode 100644
index 0000000..18667e5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Struct.java
@@ -0,0 +1,23 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * This class should be extended to create Structs.
+ * Any such class may be sent over DBus to a method which takes a Struct.
+ * All fields in the Struct which you wish to be serialized and sent to the
+ * remote method should be annotated with the org.freedesktop.dbus.Position
+ * annotation, in the order they should appear in to Struct to DBus.
+ */
+public abstract class Struct extends Container {
+ public Struct() {
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java
new file mode 100644
index 0000000..1745bcf
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java
@@ -0,0 +1,835 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import cx.ath.matthew.unix.UnixSocket;
+import cx.ath.matthew.unix.UnixSocketAddress;
+import cx.ath.matthew.utils.Hexdump;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Method;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.Collator;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+public class Transport {
+ public static class SASL {
+ public static class Command {
+ private int command;
+ private int mechs;
+ private String data;
+ private String response;
+
+ public Command() {
+ }
+
+ public Command(String s) throws IOException {
+ String[] ss = s.split(" ");
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Creating command from: " + Arrays.toString(ss));
+ if (0 == col.compare(ss[0], "OK")) {
+ command = COMMAND_OK;
+ data = ss[1];
+ } else if (0 == col.compare(ss[0], "AUTH")) {
+ command = COMMAND_AUTH;
+ if (ss.length > 1) {
+ if (0 == col.compare(ss[1], "EXTERNAL"))
+ mechs = AUTH_EXTERNAL;
+ else if (0 == col.compare(ss[1], "DBUS_COOKIE_SHA1"))
+ mechs = AUTH_SHA;
+ else if (0 == col.compare(ss[1], "ANONYMOUS"))
+ mechs = AUTH_ANON;
+ }
+ if (ss.length > 2)
+ data = ss[2];
+ } else if (0 == col.compare(ss[0], "DATA")) {
+ command = COMMAND_DATA;
+ data = ss[1];
+ } else if (0 == col.compare(ss[0], "REJECTED")) {
+ command = COMMAND_REJECTED;
+ for (int i = 1; i < ss.length; i++)
+ if (0 == col.compare(ss[i], "EXTERNAL"))
+ mechs |= AUTH_EXTERNAL;
+ else if (0 == col.compare(ss[i], "DBUS_COOKIE_SHA1"))
+ mechs |= AUTH_SHA;
+ else if (0 == col.compare(ss[i], "ANONYMOUS"))
+ mechs |= AUTH_ANON;
+ } else if (0 == col.compare(ss[0], "BEGIN")) {
+ command = COMMAND_BEGIN;
+ } else if (0 == col.compare(ss[0], "CANCEL")) {
+ command = COMMAND_CANCEL;
+ } else if (0 == col.compare(ss[0], "ERROR")) {
+ command = COMMAND_ERROR;
+ data = ss[1];
+ } else {
+ throw new IOException(getString("invalidCommand") + ss[0]);
+ }
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Created command: " + this);
+ }
+
+ public int getCommand() {
+ return command;
+ }
+
+ public int getMechs() {
+ return mechs;
+ }
+
+ public String getData() {
+ return data;
+ }
+
+ public String getResponse() {
+ return response;
+ }
+
+ public void setResponse(String s) {
+ response = s;
+ }
+
+ public String toString() {
+ return "Command(" + command + ", " + mechs + ", " + data + ", " + null + ")";
+ }
+ }
+
+ private static Collator col = Collator.getInstance();
+
+ static {
+ col.setDecomposition(Collator.FULL_DECOMPOSITION);
+ col.setStrength(Collator.PRIMARY);
+ }
+
+ public static final int LOCK_TIMEOUT = 1000;
+ public static final int NEW_KEY_TIMEOUT_SECONDS = 60 * 5;
+ public static final int EXPIRE_KEYS_TIMEOUT_SECONDS = NEW_KEY_TIMEOUT_SECONDS + (60 * 2);
+ public static final int MAX_TIME_TRAVEL_SECONDS = 60 * 5;
+ public static final int COOKIE_TIMEOUT = 240;
+ public static final String COOKIE_CONTEXT = "org_freedesktop_java";
+
+ private String findCookie(String context, String ID) throws IOException {
+ String homedir = System.getProperty("user.home");
+ File f = new File(homedir + "/.dbus-keyrings/" + context);
+ BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
+ String s = null;
+ String cookie = null;
+ long now = System.currentTimeMillis() / 1000;
+ while (null != (s = r.readLine())) {
+ String[] line = s.split(" ");
+ long timestamp = Long.parseLong(line[1]);
+ if (line[0].equals(ID) && (!(timestamp < 0 ||
+ (now + MAX_TIME_TRAVEL_SECONDS) < timestamp ||
+ (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp))) {
+ cookie = line[2];
+ break;
+ }
+ }
+ r.close();
+ return cookie;
+ }
+
+ private void addCookie(String context, String ID, long timestamp, String cookie) throws IOException {
+ String homedir = System.getProperty("user.home");
+ File keydir = new File(homedir + "/.dbus-keyrings/");
+ File cookiefile = new File(homedir + "/.dbus-keyrings/" + context);
+ File lock = new File(homedir + "/.dbus-keyrings/" + context + ".lock");
+ File temp = new File(homedir + "/.dbus-keyrings/" + context + ".temp");
+
+ // ensure directory exists
+ if (!keydir.exists()) keydir.mkdirs();
+
+ // acquire lock
+ long start = System.currentTimeMillis();
+ while (!lock.createNewFile() && LOCK_TIMEOUT > (System.currentTimeMillis() - start)) ;
+
+ // read old file
+ Vector<String> lines = new Vector<String>();
+ if (cookiefile.exists()) {
+ BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(cookiefile)));
+ String s = null;
+ while (null != (s = r.readLine())) {
+ String[] line = s.split(" ");
+ long time = Long.parseLong(line[1]);
+ // expire stale cookies
+ if ((timestamp - time) < COOKIE_TIMEOUT)
+ lines.add(s);
+ }
+ r.close();
+ }
+
+ // add cookie
+ lines.add(ID + " " + timestamp + " " + cookie);
+
+ // write temp file
+ PrintWriter w = new PrintWriter(new FileOutputStream(temp));
+ for (String l : lines)
+ w.println(l);
+ w.close();
+
+ // atomically move to old file
+ if (!temp.renameTo(cookiefile)) {
+ cookiefile.delete();
+ temp.renameTo(cookiefile);
+ }
+
+ // remove lock
+ lock.delete();
+ }
+
+ /**
+ * Takes the string, encodes it as hex and then turns it into a string again.
+ * No, I don't know why either.
+ */
+ private String stupidlyEncode(String data) {
+ return Hexdump.toHex(data.getBytes()).replaceAll(" ", "");
+ }
+
+ private String stupidlyEncode(byte[] data) {
+ return Hexdump.toHex(data).replaceAll(" ", "");
+ }
+
+ private byte getNibble(char c) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return (byte) (c - '0');
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ return (byte) (c - 'A' + 10);
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ return (byte) (c - 'a' + 10);
+ default:
+ return 0;
+ }
+ }
+
+ private String stupidlyDecode(String data) {
+ char[] cs = new char[data.length()];
+ char[] res = new char[cs.length / 2];
+ data.getChars(0, data.length(), cs, 0);
+ for (int i = 0, j = 0; j < res.length; i += 2, j++) {
+ int b = 0;
+ b |= getNibble(cs[i]) << 4;
+ b |= getNibble(cs[i + 1]);
+ res[j] = (char) b;
+ }
+ return new String(res);
+ }
+
+ public static final int MODE_SERVER = 1;
+ public static final int MODE_CLIENT = 2;
+
+ public static final int AUTH_NONE = 0;
+ public static final int AUTH_EXTERNAL = 1;
+ public static final int AUTH_SHA = 2;
+ public static final int AUTH_ANON = 4;
+
+ public static final int COMMAND_AUTH = 1;
+ public static final int COMMAND_DATA = 2;
+ public static final int COMMAND_REJECTED = 3;
+ public static final int COMMAND_OK = 4;
+ public static final int COMMAND_BEGIN = 5;
+ public static final int COMMAND_CANCEL = 6;
+ public static final int COMMAND_ERROR = 7;
+
+ public static final int INITIAL_STATE = 0;
+ public static final int WAIT_DATA = 1;
+ public static final int WAIT_OK = 2;
+ public static final int WAIT_REJECT = 3;
+ public static final int WAIT_AUTH = 4;
+ public static final int WAIT_BEGIN = 5;
+ public static final int AUTHENTICATED = 6;
+ public static final int FAILED = 7;
+
+ public static final int OK = 1;
+ public static final int CONTINUE = 2;
+ public static final int ERROR = 3;
+ public static final int REJECT = 4;
+
+ public Command receive(InputStream s) throws IOException {
+ StringBuffer sb = new StringBuffer();
+ top:
+ while (true) {
+ int c = s.read();
+ switch (c) {
+ case -1:
+ throw new IOException("Stream unexpectedly short (broken pipe)");
+ case 0:
+ case '\r':
+ continue;
+ case '\n':
+ break top;
+ default:
+ sb.append((char) c);
+ }
+ }
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "received: " + sb);
+ try {
+ return new Command(sb.toString());
+ } catch (Exception e) {
+ if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, e);
+ return new Command();
+ }
+ }
+
+ public void send(OutputStream out, int command, String... data) throws IOException {
+ StringBuffer sb = new StringBuffer();
+ switch (command) {
+ case COMMAND_AUTH:
+ sb.append("AUTH");
+ break;
+ case COMMAND_DATA:
+ sb.append("DATA");
+ break;
+ case COMMAND_REJECTED:
+ sb.append("REJECTED");
+ break;
+ case COMMAND_OK:
+ sb.append("OK");
+ break;
+ case COMMAND_BEGIN:
+ sb.append("BEGIN");
+ break;
+ case COMMAND_CANCEL:
+ sb.append("CANCEL");
+ break;
+ case COMMAND_ERROR:
+ sb.append("ERROR");
+ break;
+ default:
+ return;
+ }
+ for (String s : data) {
+ sb.append(' ');
+ sb.append(s);
+ }
+ sb.append('\r');
+ sb.append('\n');
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "sending: " + sb);
+ out.write(sb.toString().getBytes());
+ }
+
+ public int do_challenge(int auth, Command c) throws IOException {
+ switch (auth) {
+ case AUTH_SHA:
+ String[] reply = stupidlyDecode(c.getData()).split(" ");
+ if (Debug.debug) Debug.print(Debug.VERBOSE, Arrays.toString(reply));
+ if (3 != reply.length) {
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Reply is not length 3");
+ return ERROR;
+ }
+ String context = reply[0];
+ String ID = reply[1];
+ String serverchallenge = reply[2];
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA");
+ } catch (NoSuchAlgorithmException NSAe) {
+ if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe);
+ return ERROR;
+ }
+ byte[] buf = new byte[8];
+ Message.marshallintBig(System.currentTimeMillis(), buf, 0, 8);
+ String clientchallenge = stupidlyEncode(md.digest(buf));
+ md.reset();
+ long start = System.currentTimeMillis();
+ String cookie = null;
+ while (null == cookie && (System.currentTimeMillis() - start) < LOCK_TIMEOUT)
+ cookie = findCookie(context, ID);
+ if (null == cookie) {
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Did not find a cookie in context " + context + " with ID " + ID);
+ return ERROR;
+ }
+ String response = serverchallenge + ":" + clientchallenge + ":" + cookie;
+ buf = md.digest(response.getBytes());
+ if (Debug.debug)
+ Debug.print(Debug.VERBOSE, "Response: " + response + " hash: " + Hexdump.format(buf));
+ response = stupidlyEncode(buf);
+ c.setResponse(stupidlyEncode(clientchallenge + " " + response));
+ return OK;
+ default:
+ if (Debug.debug) Debug.print(Debug.DEBUG, "Not DBUS_COOKIE_SHA1 authtype.");
+ return ERROR;
+ }
+ }
+
+ public String challenge = "";
+ public String cookie = "";
+
+ public int do_response(int auth, String Uid, String kernelUid, Command c) {
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA");
+ } catch (NoSuchAlgorithmException NSAe) {
+ if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe);
+ return ERROR;
+ }
+ switch (auth) {
+ case AUTH_NONE:
+ switch (c.getMechs()) {
+ case AUTH_ANON:
+ return OK;
+ case AUTH_EXTERNAL:
+ if (0 == col.compare(Uid, c.getData()) &&
+ (null == kernelUid || 0 == col.compare(Uid, kernelUid)))
+ return OK;
+ else
+ return ERROR;
+ case AUTH_SHA:
+ String context = COOKIE_CONTEXT;
+ long id = System.currentTimeMillis();
+ byte[] buf = new byte[8];
+ Message.marshallintBig(id, buf, 0, 8);
+ challenge = stupidlyEncode(md.digest(buf));
+ Random r = new Random();
+ r.nextBytes(buf);
+ cookie = stupidlyEncode(md.digest(buf));
+ try {
+ addCookie(context, "" + id, id / 1000, cookie);
+ } catch (IOException IOe) {
+ if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, IOe);
+ }
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Sending challenge: " + context + ' ' + id + ' ' + challenge);
+ c.setResponse(stupidlyEncode(context + ' ' + id + ' ' + challenge));
+ return CONTINUE;
+ default:
+ return ERROR;
+ }
+ case AUTH_SHA:
+ String[] response = stupidlyDecode(c.getData()).split(" ");
+ if (response.length < 2) return ERROR;
+ String cchal = response[0];
+ String hash = response[1];
+ String prehash = challenge + ":" + cchal + ":" + cookie;
+ byte[] buf = md.digest(prehash.getBytes());
+ String posthash = stupidlyEncode(buf);
+ if (Debug.debug)
+ Debug.print(Debug.DEBUG, "Authenticating Hash; data=" + prehash + " remote hash=" + hash + " local hash=" + posthash);
+ if (0 == col.compare(posthash, hash))
+ return OK;
+ else
+ return ERROR;
+ default:
+ return ERROR;
+ }
+ }
+
+ public String[] getTypes(int types) {
+ switch (types) {
+ case AUTH_EXTERNAL:
+ return new String[]{"EXTERNAL"};
+ case AUTH_SHA:
+ return new String[]{"DBUS_COOKIE_SHA1"};
+ case AUTH_ANON:
+ return new String[]{"ANONYMOUS"};
+ case AUTH_SHA + AUTH_EXTERNAL:
+ return new String[]{"EXTERNAL", "DBUS_COOKIE_SHA1"};
+ case AUTH_SHA + AUTH_ANON:
+ return new String[]{"ANONYMOUS", "DBUS_COOKIE_SHA1"};
+ case AUTH_EXTERNAL + AUTH_ANON:
+ return new String[]{"ANONYMOUS", "EXTERNAL"};
+ case AUTH_EXTERNAL + AUTH_ANON + AUTH_SHA:
+ return new String[]{"ANONYMOUS", "EXTERNAL", "DBUS_COOKIE_SHA1"};
+ default:
+ return new String[]{};
+ }
+ }
+
+ /**
+ * performs SASL auth on the given streams.
+ * Mode selects whether to run as a SASL server or client.
+ * Types is a bitmask of the available auth types.
+ * Returns true if the auth was successful and false if it failed.
+ */
+ @SuppressWarnings("unchecked")
+ public boolean auth(int mode, int types, String guid, OutputStream out, InputStream in, UnixSocket us) throws IOException {
+ String username = System.getProperty("user.name");
+ String Uid = null;
+ String kernelUid = null;
+ try {
+ Class c = Class.forName("com.sun.security.auth.module.UnixSystem");
+ Method m = c.getMethod("getUid");
+ Object o = c.newInstance();
+ long uid = (Long) m.invoke(o);
+ Uid = stupidlyEncode("" + uid);
+ } catch (Exception e) {
+ Uid = stupidlyEncode(username);
+ }
+ Command c;
+ int failed = 0;
+ int current = 0;
+ int state = INITIAL_STATE;
+
+ while (state != AUTHENTICATED && state != FAILED) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "AUTH state: " + state);
+ switch (mode) {
+ case MODE_CLIENT:
+ switch (state) {
+ case INITIAL_STATE:
+ if (null == us)
+ out.write(new byte[]{0});
+ else
+ us.sendCredentialByte((byte) 0);
+ send(out, COMMAND_AUTH);
+ state = WAIT_DATA;
+ break;
+ case WAIT_DATA:
+ c = receive(in);
+ switch (c.getCommand()) {
+ case COMMAND_DATA:
+ switch (do_challenge(current, c)) {
+ case CONTINUE:
+ send(out, COMMAND_DATA, c.getResponse());
+ break;
+ case OK:
+ send(out, COMMAND_DATA, c.getResponse());
+ state = WAIT_OK;
+ break;
+ case ERROR:
+ send(out, COMMAND_ERROR, c.getResponse());
+ break;
+ }
+ break;
+ case COMMAND_REJECTED:
+ failed |= current;
+ int available = c.getMechs() & (~failed);
+ if (0 != (available & AUTH_EXTERNAL)) {
+ send(out, COMMAND_AUTH, "EXTERNAL", Uid);
+ current = AUTH_EXTERNAL;
+ } else if (0 != (available & AUTH_SHA)) {
+ send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
+ current = AUTH_SHA;
+ } else if (0 != (available & AUTH_ANON)) {
+ send(out, COMMAND_AUTH, "ANONYMOUS");
+ current = AUTH_ANON;
+ } else state = FAILED;
+ break;
+ case COMMAND_ERROR:
+ send(out, COMMAND_CANCEL);
+ state = WAIT_REJECT;
+ break;
+ case COMMAND_OK:
+ send(out, COMMAND_BEGIN);
+ state = AUTHENTICATED;
+ break;
+ default:
+ send(out, COMMAND_ERROR, "Got invalid command");
+ break;
+ }
+ break;
+ case WAIT_OK:
+ c = receive(in);
+ switch (c.getCommand()) {
+ case COMMAND_OK:
+ send(out, COMMAND_BEGIN);
+ state = AUTHENTICATED;
+ break;
+ case COMMAND_ERROR:
+ case COMMAND_DATA:
+ send(out, COMMAND_CANCEL);
+ state = WAIT_REJECT;
+ break;
+ case COMMAND_REJECTED:
+ failed |= current;
+ int available = c.getMechs() & (~failed);
+ state = WAIT_DATA;
+ if (0 != (available & AUTH_EXTERNAL)) {
+ send(out, COMMAND_AUTH, "EXTERNAL", Uid);
+ current = AUTH_EXTERNAL;
+ } else if (0 != (available & AUTH_SHA)) {
+ send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
+ current = AUTH_SHA;
+ } else if (0 != (available & AUTH_ANON)) {
+ send(out, COMMAND_AUTH, "ANONYMOUS");
+ current = AUTH_ANON;
+ } else state = FAILED;
+ break;
+ default:
+ send(out, COMMAND_ERROR, "Got invalid command");
+ break;
+ }
+ break;
+ case WAIT_REJECT:
+ c = receive(in);
+ switch (c.getCommand()) {
+ case COMMAND_REJECTED:
+ failed |= current;
+ int available = c.getMechs() & (~failed);
+ if (0 != (available & AUTH_EXTERNAL)) {
+ send(out, COMMAND_AUTH, "EXTERNAL", Uid);
+ current = AUTH_EXTERNAL;
+ } else if (0 != (available & AUTH_SHA)) {
+ send(out, COMMAND_AUTH, "DBUS_COOKIE_SHA1", Uid);
+ current = AUTH_SHA;
+ } else if (0 != (available & AUTH_ANON)) {
+ send(out, COMMAND_AUTH, "ANONYMOUS");
+ current = AUTH_ANON;
+ } else state = FAILED;
+ break;
+ default:
+ state = FAILED;
+ break;
+ }
+ break;
+ default:
+ state = FAILED;
+ }
+ break;
+ case MODE_SERVER:
+ switch (state) {
+ case INITIAL_STATE:
+ byte[] buf = new byte[1];
+ if (null == us) {
+ in.read(buf);
+ } else {
+ buf[0] = us.recvCredentialByte();
+ int kuid = us.getPeerUID();
+ if (kuid >= 0)
+ kernelUid = stupidlyEncode("" + kuid);
+ }
+ if (0 != buf[0]) state = FAILED;
+ else state = WAIT_AUTH;
+ break;
+ case WAIT_AUTH:
+ c = receive(in);
+ switch (c.getCommand()) {
+ case COMMAND_AUTH:
+ if (null == c.getData()) {
+ send(out, COMMAND_REJECTED, getTypes(types));
+ } else {
+ switch (do_response(current, Uid, kernelUid, c)) {
+ case CONTINUE:
+ send(out, COMMAND_DATA, c.getResponse());
+ current = c.getMechs();
+ state = WAIT_DATA;
+ break;
+ case OK:
+ send(out, COMMAND_OK, guid);
+ state = WAIT_BEGIN;
+ current = 0;
+ break;
+ case REJECT:
+ send(out, COMMAND_REJECTED, getTypes(types));
+ current = 0;
+ break;
+ }
+ }
+ break;
+ case COMMAND_ERROR:
+ send(out, COMMAND_REJECTED, getTypes(types));
+ break;
+ case COMMAND_BEGIN:
+ state = FAILED;
+ break;
+ default:
+ send(out, COMMAND_ERROR, "Got invalid command");
+ break;
+ }
+ break;
+ case WAIT_DATA:
+ c = receive(in);
+ switch (c.getCommand()) {
+ case COMMAND_DATA:
+ switch (do_response(current, Uid, kernelUid, c)) {
+ case CONTINUE:
+ send(out, COMMAND_DATA, c.getResponse());
+ state = WAIT_DATA;
+ break;
+ case OK:
+ send(out, COMMAND_OK, guid);
+ state = WAIT_BEGIN;
+ current = 0;
+ break;
+ case REJECT:
+ send(out, COMMAND_REJECTED, getTypes(types));
+ current = 0;
+ break;
+ }
+ break;
+ case COMMAND_ERROR:
+ case COMMAND_CANCEL:
+ send(out, COMMAND_REJECTED, getTypes(types));
+ state = WAIT_AUTH;
+ break;
+ case COMMAND_BEGIN:
+ state = FAILED;
+ break;
+ default:
+ send(out, COMMAND_ERROR, "Got invalid command");
+ break;
+ }
+ break;
+ case WAIT_BEGIN:
+ c = receive(in);
+ switch (c.getCommand()) {
+ case COMMAND_ERROR:
+ case COMMAND_CANCEL:
+ send(out, COMMAND_REJECTED, getTypes(types));
+ state = WAIT_AUTH;
+ break;
+ case COMMAND_BEGIN:
+ state = AUTHENTICATED;
+ break;
+ default:
+ send(out, COMMAND_ERROR, "Got invalid command");
+ break;
+ }
+ break;
+ default:
+ state = FAILED;
+ }
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return state == AUTHENTICATED;
+ }
+ }
+
+ public MessageReader min;
+ public MessageWriter mout;
+
+ public Transport() {
+ }
+
+ public static String genGUID() {
+ Random r = new Random();
+ byte[] buf = new byte[16];
+ r.nextBytes(buf);
+ String guid = Hexdump.toHex(buf);
+ return guid.replaceAll(" ", "");
+ }
+
+ public Transport(BusAddress address) throws IOException {
+ connect(address);
+ }
+
+ public Transport(String address) throws IOException, ParseException {
+ connect(new BusAddress(address));
+ }
+
+ public Transport(String address, int timeout) throws IOException, ParseException {
+ connect(new BusAddress(address), timeout);
+ }
+
+ public void connect(String address) throws IOException, ParseException {
+ connect(new BusAddress(address), 0);
+ }
+
+ public void connect(String address, int timeout) throws IOException, ParseException {
+ connect(new BusAddress(address), timeout);
+ }
+
+ public void connect(BusAddress address) throws IOException {
+ connect(address, 0);
+ }
+
+ public void connect(BusAddress address, int timeout) throws IOException {
+ if (Debug.debug) Debug.print(Debug.INFO, "Connecting to " + address);
+ OutputStream out = null;
+ InputStream in = null;
+ UnixSocket us = null;
+ Socket s = null;
+ int mode = 0;
+ int types = 0;
+ if ("unix".equals(address.getType())) {
+ types = SASL.AUTH_EXTERNAL;
+ mode = SASL.MODE_CLIENT;
+ us = new UnixSocket();
+ if (null != address.getParameter("abstract"))
+ us.connect(new UnixSocketAddress(address.getParameter("abstract"), true));
+ else if (null != address.getParameter("path"))
+ us.connect(new UnixSocketAddress(address.getParameter("path"), false));
+ us.setPassCred(true);
+ in = us.getInputStream();
+ out = us.getOutputStream();
+ } else if ("tcp".equals(address.getType())) {
+ types = SASL.AUTH_SHA;
+ if (null != address.getParameter("listen")) {
+ mode = SASL.MODE_SERVER;
+ ServerSocket ss = new ServerSocket();
+ ss.bind(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
+ s = ss.accept();
+ } else {
+ mode = SASL.MODE_CLIENT;
+ s = new Socket();
+ s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
+ }
+ in = s.getInputStream();
+ out = s.getOutputStream();
+ } else {
+ throw new IOException(getString("unknownAddress") + address.getType());
+ }
+
+ if (!(new SASL()).auth(mode, types, address.getParameter("guid"), out, in, us)) {
+ out.close();
+ throw new IOException(getString("errorAuth"));
+ }
+ if (null != us) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting timeout to " + timeout + " on Socket");
+ if (timeout == 1)
+ us.setBlocking(false);
+ else
+ us.setSoTimeout(timeout);
+ }
+ if (null != s) {
+ if (Debug.debug) Debug.print(Debug.VERBOSE, "Setting timeout to " + timeout + " on Socket");
+ s.setSoTimeout(timeout);
+ }
+ mout = new MessageWriter(out);
+ min = new MessageReader(in);
+ }
+
+ public void disconnect() throws IOException {
+ if (Debug.debug) Debug.print(Debug.INFO, "Disconnecting Transport");
+ min.close();
+ mout.close();
+ }
+}
+
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Tuple.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Tuple.java
new file mode 100644
index 0000000..5fc13d5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Tuple.java
@@ -0,0 +1,24 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+/**
+ * This class should be extended to create Tuples.
+ * Any such class may be used as the return type for a method
+ * which returns multiple values.
+ * All fields in the Tuple which you wish to be serialized and sent to the
+ * remote method should be annotated with the org.freedesktop.dbus.Position
+ * annotation, in the order they should appear to DBus.
+ */
+public abstract class Tuple extends Container {
+ public Tuple() {
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusListType.java b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusListType.java
new file mode 100644
index 0000000..a00c307
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusListType.java
@@ -0,0 +1,44 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.types;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * The type of a list.
+ * Should be used whenever you need a Type variable for a list.
+ */
+public class DBusListType implements ParameterizedType {
+ private Type v;
+
+ /**
+ * Create a List type.
+ *
+ * @param v Type of the list contents.
+ */
+ public DBusListType(Type v) {
+ this.v = v;
+ }
+
+ public Type[] getActualTypeArguments() {
+ return new Type[]{v};
+ }
+
+ public Type getRawType() {
+ return List.class;
+ }
+
+ public Type getOwnerType() {
+ return null;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusMapType.java b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusMapType.java
new file mode 100644
index 0000000..754e0a2
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusMapType.java
@@ -0,0 +1,47 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.types;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Map;
+
+/**
+ * The type of a map.
+ * Should be used whenever you need a Type variable for a map.
+ */
+public class DBusMapType implements ParameterizedType {
+ private Type k;
+ private Type v;
+
+ /**
+ * Create a map type.
+ *
+ * @param k The type of the keys.
+ * @param v The type of the values.
+ */
+ public DBusMapType(Type k, Type v) {
+ this.k = k;
+ this.v = v;
+ }
+
+ public Type[] getActualTypeArguments() {
+ return new Type[]{k, v};
+ }
+
+ public Type getRawType() {
+ return Map.class;
+ }
+
+ public Type getOwnerType() {
+ return null;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusStructType.java b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusStructType.java
new file mode 100644
index 0000000..fda2065
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/types/DBusStructType.java
@@ -0,0 +1,45 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus.types;
+
+import org.freedesktop.dbus.Struct;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * The type of a struct.
+ * Should be used whenever you need a Type variable for a struct.
+ */
+public class DBusStructType implements ParameterizedType {
+ private Type[] contents;
+
+ /**
+ * Create a struct type.
+ *
+ * @param contents The types contained in this struct.
+ */
+ public DBusStructType(Type... contents) {
+ this.contents = contents;
+ }
+
+ public Type[] getActualTypeArguments() {
+ return contents;
+ }
+
+ public Type getRawType() {
+ return Struct.class;
+ }
+
+ public Type getOwnerType() {
+ return null;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/TypeSignature.java b/federation/sssd/src/main/java/org/freedesktop/dbus/TypeSignature.java
new file mode 100644
index 0000000..eaad166
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/TypeSignature.java
@@ -0,0 +1,37 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.lang.reflect.Type;
+
+public class TypeSignature {
+ String sig;
+
+ public TypeSignature(String sig) {
+ this.sig = sig;
+ }
+
+ public TypeSignature(Type[] types) throws DBusException {
+ StringBuffer sb = new StringBuffer();
+ for (Type t : types) {
+ String[] ts = Marshalling.getDBusType(t);
+ for (String s : ts)
+ sb.append(s);
+ }
+ this.sig = sb.toString();
+ }
+
+ public String getSig() {
+ return sig;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/UInt16.java b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt16.java
new file mode 100644
index 0000000..a8f0600
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt16.java
@@ -0,0 +1,122 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Class to represent 16-bit unsigned integers.
+ */
+@SuppressWarnings("serial")
+public class UInt16 extends Number implements Comparable<UInt16> {
+ /**
+ * Maximum possible value.
+ */
+ public static final int MAX_VALUE = 65535;
+ /**
+ * Minimum possible value.
+ */
+ public static final int MIN_VALUE = 0;
+ private int value;
+
+ /**
+ * Create a UInt16 from an int.
+ *
+ * @param value Must be within MIN_VALUE–MAX_VALUE
+ * @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
+ */
+ public UInt16(int value) {
+ if (value < MIN_VALUE || value > MAX_VALUE)
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_VALUE}));
+ this.value = value;
+ }
+
+ /**
+ * Create a UInt16 from a String.
+ *
+ * @param value Must parse to a valid integer within MIN_VALUE–MAX_VALUE
+ * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_VALUE
+ */
+ public UInt16(String value) {
+ this(Integer.parseInt(value));
+ }
+
+ /**
+ * The value of this as a byte.
+ */
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ /**
+ * The value of this as a double.
+ */
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ /**
+ * The value of this as a float.
+ */
+ public float floatValue() {
+ return (float) value;
+ }
+
+ /**
+ * The value of this as a int.
+ */
+ public int intValue() {
+ return /*(int)*/ value;
+ }
+
+ /**
+ * The value of this as a long.
+ */
+ public long longValue() {
+ return (long) value;
+ }
+
+ /**
+ * The value of this as a short.
+ */
+ public short shortValue() {
+ return (short) value;
+ }
+
+ /**
+ * Test two UInt16s for equality.
+ */
+ public boolean equals(Object o) {
+ return o instanceof UInt16 && ((UInt16) o).value == this.value;
+ }
+
+ public int hashCode() {
+ return /*(int)*/ value;
+ }
+
+ /**
+ * Compare two UInt16s.
+ *
+ * @return 0 if equal, -ve or +ve if they are different.
+ */
+ public int compareTo(UInt16 other) {
+ return /*(int)*/ (this.value - other.value);
+ }
+
+ /**
+ * The value of this as a string.
+ */
+ public String toString() {
+ return "" + value;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/UInt32.java b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt32.java
new file mode 100644
index 0000000..4651919
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt32.java
@@ -0,0 +1,122 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Class to represent unsigned 32-bit numbers.
+ */
+@SuppressWarnings("serial")
+public class UInt32 extends Number implements Comparable<UInt32> {
+ /**
+ * Maximum allowed value
+ */
+ public static final long MAX_VALUE = 4294967295L;
+ /**
+ * Minimum allowed value
+ */
+ public static final long MIN_VALUE = 0;
+ private long value;
+
+ /**
+ * Create a UInt32 from a long.
+ *
+ * @param value Must be a valid integer within MIN_VALUE–MAX_VALUE
+ * @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
+ */
+ public UInt32(long value) {
+ if (value < MIN_VALUE || value > MAX_VALUE)
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_VALUE}));
+ this.value = value;
+ }
+
+ /**
+ * Create a UInt32 from a String.
+ *
+ * @param value Must parse to a valid integer within MIN_VALUE–MAX_VALUE
+ * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_VALUE
+ */
+ public UInt32(String value) {
+ this(Long.parseLong(value));
+ }
+
+ /**
+ * The value of this as a byte.
+ */
+ public byte byteValue() {
+ return (byte) value;
+ }
+
+ /**
+ * The value of this as a double.
+ */
+ public double doubleValue() {
+ return (double) value;
+ }
+
+ /**
+ * The value of this as a float.
+ */
+ public float floatValue() {
+ return (float) value;
+ }
+
+ /**
+ * The value of this as a int.
+ */
+ public int intValue() {
+ return (int) value;
+ }
+
+ /**
+ * The value of this as a long.
+ */
+ public long longValue() {
+ return /*(long)*/ value;
+ }
+
+ /**
+ * The value of this as a short.
+ */
+ public short shortValue() {
+ return (short) value;
+ }
+
+ /**
+ * Test two UInt32s for equality.
+ */
+ public boolean equals(Object o) {
+ return o instanceof UInt32 && ((UInt32) o).value == this.value;
+ }
+
+ public int hashCode() {
+ return (int) value;
+ }
+
+ /**
+ * Compare two UInt32s.
+ *
+ * @return 0 if equal, -ve or +ve if they are different.
+ */
+ public int compareTo(UInt32 other) {
+ return (int) (this.value - other.value);
+ }
+
+ /**
+ * The value of this as a string
+ */
+ public String toString() {
+ return "" + value;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/UInt64.java b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt64.java
new file mode 100644
index 0000000..fde2cf0
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/UInt64.java
@@ -0,0 +1,203 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.math.BigInteger;
+import java.text.MessageFormat;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * Class to represent unsigned 64-bit numbers.
+ * Warning: Any functions which take or return a <tt>long</tt>
+ * are restricted to the range of a signed 64bit number.
+ * Use the BigInteger methods if you wish access to the full
+ * range.
+ */
+@SuppressWarnings("serial")
+public class UInt64 extends Number implements Comparable<UInt64> {
+ /**
+ * Maximum allowed value (when accessed as a long)
+ */
+ public static final long MAX_LONG_VALUE = Long.MAX_VALUE;
+ /**
+ * Maximum allowed value (when accessed as a BigInteger)
+ */
+ public static final BigInteger MAX_BIG_VALUE = new BigInteger("18446744073709551615");
+ /**
+ * Minimum allowed value
+ */
+ public static final long MIN_VALUE = 0;
+ private BigInteger value;
+ private long top;
+ private long bottom;
+
+ /**
+ * Create a UInt64 from a long.
+ *
+ * @param value Must be a valid integer within MIN_VALUE–MAX_VALUE
+ * @throws NumberFormatException if value is not between MIN_VALUE and MAX_VALUE
+ */
+ public UInt64(long value) {
+ if (value < MIN_VALUE || value > MAX_LONG_VALUE)
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_LONG_VALUE}));
+ this.value = new BigInteger("" + value);
+ this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
+ this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
+ }
+
+ /**
+ * Create a UInt64 from two longs.
+ *
+ * @param top Most significant 4 bytes.
+ * @param bottom Least significant 4 bytes.
+ */
+ public UInt64(long top, long bottom) {
+ BigInteger a = new BigInteger("" + top);
+ a = a.shiftLeft(32);
+ a = a.add(new BigInteger("" + bottom));
+ if (0 > a.compareTo(BigInteger.ZERO))
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{a, MIN_VALUE, MAX_BIG_VALUE}));
+ if (0 < a.compareTo(MAX_BIG_VALUE))
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{a, MIN_VALUE, MAX_BIG_VALUE}));
+ this.value = a;
+ this.top = top;
+ this.bottom = bottom;
+ }
+
+ /**
+ * Create a UInt64 from a BigInteger
+ *
+ * @param value Must be a valid BigInteger between MIN_VALUE–MAX_BIG_VALUE
+ * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_BIG_VALUE
+ */
+ public UInt64(BigInteger value) {
+ if (null == value)
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+ if (0 > value.compareTo(BigInteger.ZERO))
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+ if (0 < value.compareTo(MAX_BIG_VALUE))
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+ this.value = value;
+ this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
+ this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
+ }
+
+ /**
+ * Create a UInt64 from a String.
+ *
+ * @param value Must parse to a valid integer within MIN_VALUE–MAX_BIG_VALUE
+ * @throws NumberFormatException if value is not an integer between MIN_VALUE and MAX_BIG_VALUE
+ */
+ public UInt64(String value) {
+ if (null == value)
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+ BigInteger a = new BigInteger(value);
+ if (0 > a.compareTo(BigInteger.ZERO))
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+ if (0 < a.compareTo(MAX_BIG_VALUE))
+ throw new NumberFormatException(MessageFormat.format(getString("isNotBetween"), new Object[]{value, MIN_VALUE, MAX_BIG_VALUE}));
+ this.value = a;
+ this.top = this.value.shiftRight(32).and(new BigInteger("4294967295")).longValue();
+ this.bottom = this.value.and(new BigInteger("4294967295")).longValue();
+ }
+
+ /**
+ * The value of this as a BigInteger.
+ */
+ public BigInteger value() {
+ return value;
+ }
+
+ /**
+ * The value of this as a byte.
+ */
+ public byte byteValue() {
+ return value.byteValue();
+ }
+
+ /**
+ * The value of this as a double.
+ */
+ public double doubleValue() {
+ return value.doubleValue();
+ }
+
+ /**
+ * The value of this as a float.
+ */
+ public float floatValue() {
+ return value.floatValue();
+ }
+
+ /**
+ * The value of this as a int.
+ */
+ public int intValue() {
+ return value.intValue();
+ }
+
+ /**
+ * The value of this as a long.
+ */
+ public long longValue() {
+ return value.longValue();
+ }
+
+ /**
+ * The value of this as a short.
+ */
+ public short shortValue() {
+ return value.shortValue();
+ }
+
+ /**
+ * Test two UInt64s for equality.
+ */
+ public boolean equals(Object o) {
+ return o instanceof UInt64 && this.value.equals(((UInt64) o).value);
+ }
+
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ /**
+ * Compare two UInt32s.
+ *
+ * @return 0 if equal, -ve or +ve if they are different.
+ */
+ public int compareTo(UInt64 other) {
+ return this.value.compareTo(other.value);
+ }
+
+ /**
+ * The value of this as a string.
+ */
+ public String toString() {
+ return value.toString();
+ }
+
+ /**
+ * Most significant 4 bytes.
+ */
+ public long top() {
+ return top;
+ }
+
+ /**
+ * Least significant 4 bytes.
+ */
+ public long bottom() {
+ return bottom;
+ }
+}
+
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Variant.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Variant.java
new file mode 100644
index 0000000..8fe21a5
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Variant.java
@@ -0,0 +1,136 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Vector;
+
+import static org.freedesktop.dbus.Gettext.getString;
+
+/**
+ * A Wrapper class for Variant values.
+ * A method on DBus can send or receive a Variant.
+ * This will wrap another value whose type is determined at runtime.
+ * The Variant may be parameterized to restrict the types it may accept.
+ */
+public class Variant<T> {
+ private final T o;
+ private final Type type;
+ private final String sig;
+
+ /**
+ * Create a Variant from a basic type object.
+ *
+ * @param o The wrapped value.
+ * @throws IllegalArugmentException If you try and wrap Null or an object of a non-basic type.
+ */
+ public Variant(T o) throws IllegalArgumentException {
+ if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
+ type = o.getClass();
+ try {
+ String[] ss = Marshalling.getDBusType(o.getClass(), true);
+ if (ss.length != 1)
+ throw new IllegalArgumentException(getString("cannotWrapMultiValuedInVariant") + type);
+ this.sig = ss[0];
+ } catch (DBusException DBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{o.getClass(), DBe.getMessage()}));
+ }
+ this.o = o;
+ }
+
+ /**
+ * Create a Variant.
+ *
+ * @param o The wrapped value.
+ * @param type The explicit type of the value.
+ * @throws IllegalArugmentException If you try and wrap Null or an object which cannot be sent over DBus.
+ */
+ public Variant(T o, Type type) throws IllegalArgumentException {
+ if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
+ this.type = type;
+ try {
+ String[] ss = Marshalling.getDBusType(type);
+ if (ss.length != 1)
+ throw new IllegalArgumentException(getString("cannotWrapMultiValuedInVariant") + type);
+ this.sig = ss[0];
+ } catch (DBusException DBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{type, DBe.getMessage()}));
+ }
+ this.o = o;
+ }
+
+ /**
+ * Create a Variant.
+ *
+ * @param o The wrapped value.
+ * @param sig The explicit type of the value, as a dbus type string.
+ * @throws IllegalArugmentException If you try and wrap Null or an object which cannot be sent over DBus.
+ */
+ public Variant(T o, String sig) throws IllegalArgumentException {
+ if (null == o) throw new IllegalArgumentException(getString("cannotWrapNullInVariant"));
+ this.sig = sig;
+ try {
+ Vector<Type> ts = new Vector<Type>();
+ Marshalling.getJavaType(sig, ts, 1);
+ if (ts.size() != 1)
+ throw new IllegalArgumentException(getString("cannotWrapNoTypesInVariant") + sig);
+ this.type = ts.get(0);
+ } catch (DBusException DBe) {
+ if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe);
+ throw new IllegalArgumentException(MessageFormat.format(getString("cannotWrapUnqualifiedVariant"), new Object[]{sig, DBe.getMessage()}));
+ }
+ this.o = o;
+ }
+
+ /**
+ * Return the wrapped value.
+ */
+ public T getValue() {
+ return o;
+ }
+
+ /**
+ * Return the type of the wrapped value.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Return the dbus signature of the wrapped value.
+ */
+ public String getSig() {
+ return sig;
+ }
+
+ /**
+ * Format the Variant as a string.
+ */
+ public String toString() {
+ return "[" + o + "]";
+ }
+
+ /**
+ * Compare this Variant with another by comparing contents
+ */
+ @SuppressWarnings("unchecked")
+ public boolean equals(Object other) {
+ if (null == other) return false;
+ if (!(other instanceof Variant)) return false;
+ return this.o.equals(((Variant<? extends Object>) other).o);
+ }
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/Cache.java b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/Cache.java
new file mode 100644
index 0000000..1a45839
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/Cache.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.freedesktop.sssd.infopipe;
+
+import org.freedesktop.dbus.DBusInterface;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+public interface Cache extends DBusInterface {
+
+ List<DBusInterface> List();
+
+ List<DBusInterface> ListByDomain(String domain_name);
+
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java
new file mode 100644
index 0000000..8791170
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.freedesktop.sssd.infopipe;
+
+import org.freedesktop.dbus.DBusInterface;
+import org.freedesktop.dbus.DBusInterfaceName;
+import org.freedesktop.dbus.DBusMemberName;
+import org.freedesktop.dbus.Variant;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+@DBusInterfaceName("org.freedesktop.sssd.infopipe")
+public interface InfoPipe extends DBusInterface {
+
+ String OBJECTPATH = "/org/freedesktop/sssd/infopipe";
+
+ @DBusMemberName("GetUserAttr")
+ Map<String, Variant> getUserAttributes(String user, List<String> attr);
+
+ @DBusMemberName("GetUserGroups")
+ List<String> getUserGroups(String user);
+
+}
diff --git a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/User.java b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/User.java
new file mode 100644
index 0000000..896b80a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/User.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.freedesktop.sssd.infopipe;
+
+import org.freedesktop.dbus.DBusInterface;
+import org.freedesktop.dbus.DBusInterfaceName;
+import org.freedesktop.dbus.DBusMemberName;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+@DBusInterfaceName("org.freedesktop.sssd.infopipe.Users")
+public interface User extends DBusInterface {
+
+ String OBJECTPATH = "/org/freedesktop/sssd/infopipe/Users";
+
+ @DBusMemberName("FindByCertificate")
+ DBusInterface findByCertificate(String pem_cert);
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDCLibrary.java
new file mode 100644
index 0000000..0de8a2a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDCLibrary.java
@@ -0,0 +1,34 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2011, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author Sebastian Sdorra
+ */
+public interface BSDCLibrary extends CLibrary {
+
+ BSDPasswd getpwnam(String username);
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDPasswd.java
new file mode 100644
index 0000000..2e437bb
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/BSDPasswd.java
@@ -0,0 +1,93 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2011, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * FreeeBSD, OpenBSD and MacOS passwd
+ * <p>
+ * struct passwd {
+ * char *pw_name;
+ * char *pw_passwd;
+ * uid_t pw_uid;
+ * gid_t pw_gid;
+ * time_t pw_change;
+ * char *pw_class;
+ * char *pw_gecos;
+ * char *pw_dir;
+ * char *pw_shell;
+ * time_t pw_expire;
+ * };
+ *
+ * @author Sebastian Sdorra
+ */
+public class BSDPasswd extends passwd {
+ /* password change time */
+ public long pw_change;
+
+ /* user access class */
+ public String pw_class;
+
+ /* Honeywell login info */
+ public String pw_gecos;
+
+ /* home directory */
+ public String pw_dir;
+
+ /* default shell */
+ public String pw_shell;
+
+ /* account expiration */
+ public long pw_expire;
+
+ @Override
+ public String getPwGecos() {
+ return pw_gecos;
+ }
+
+ @Override
+ public String getPwDir() {
+ return pw_dir;
+ }
+
+ @Override
+ public String getPwShell() {
+ return pw_shell;
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ List fieldOrder = new ArrayList(super.getFieldOrder());
+ fieldOrder.addAll(Arrays.asList("pw_change", "pw_class", "pw_gecos",
+ "pw_dir", "pw_shell", "pw_expire"));
+ return fieldOrder;
+ }
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/CLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/CLibrary.java
new file mode 100644
index 0000000..e3b6105
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/CLibrary.java
@@ -0,0 +1,154 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam.impl;
+
+import com.sun.jna.Library;
+import com.sun.jna.Memory;
+import com.sun.jna.Native;
+import com.sun.jna.Platform;
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+import com.sun.jna.ptr.IntByReference;
+import org.jvnet.libpam.PAMException;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+public interface CLibrary extends Library {
+ /**
+ * Comparing http://linux.die.net/man/3/getpwnam
+ * and my Mac OS X reveals that the structure of this field isn't very portable.
+ * In particular, we cannot read the real name reliably.
+ */
+ public class passwd extends Structure {
+ /**
+ * User name.
+ */
+ public String pw_name;
+ /**
+ * Encrypted password.
+ */
+ public String pw_passwd;
+ public int pw_uid;
+ public int pw_gid;
+
+ // ... there are a lot more fields
+
+ public static passwd loadPasswd(String userName) throws PAMException {
+ passwd pwd = libc.getpwnam(userName);
+ if (pwd == null) {
+ throw new PAMException("No user information is available");
+ }
+ return pwd;
+ }
+
+ public String getPwName() {
+ return pw_name;
+ }
+
+ public String getPwPasswd() {
+ return pw_passwd;
+ }
+
+ public int getPwUid() {
+ return pw_uid;
+ }
+
+ public int getPwGid() {
+ return pw_gid;
+ }
+
+ public String getPwGecos() {
+ return null;
+ }
+
+ public String getPwDir() {
+ return null;
+ }
+
+ public String getPwShell() {
+ return null;
+ }
+
+ protected List getFieldOrder() {
+ return Arrays.asList("pw_name", "pw_passwd", "pw_uid", "pw_gid");
+ }
+ }
+
+ public class group extends Structure {
+ public String gr_name;
+ // ... the rest of the field is not interesting for us
+
+ protected List getFieldOrder() {
+ return Arrays.asList("gr_name");
+ }
+ }
+
+ Pointer calloc(int count, int size);
+
+ Pointer strdup(String s);
+
+ passwd getpwnam(String username);
+
+ /**
+ * Lists up group IDs of the given user. On Linux and most BSDs, but not on Solaris.
+ * See http://www.gnu.org/software/hello/manual/gnulib/getgrouplist.html
+ */
+ int getgrouplist(String user, int/*gid_t*/ group, Memory groups, IntByReference ngroups);
+
+ /**
+ * getgrouplist equivalent on Solaris.
+ * See http://mail.opensolaris.org/pipermail/sparks-discuss/2008-September/000528.html
+ */
+ int _getgroupsbymember(String user, Memory groups, int maxgids, int numgids);
+
+ group getgrgid(int/*gid_t*/ gid);
+
+ group getgrnam(String name);
+
+ // other user/group related functions that are likely useful
+ // see http://www.gnu.org/software/libc/manual/html_node/Users-and-Groups.html#Users-and-Groups
+
+
+ public static final CLibrary libc = Instance.init();
+
+ static class Instance {
+ private static CLibrary init() {
+ if (Platform.isMac() || Platform.isOpenBSD()) {
+ return (CLibrary) Native.loadLibrary("c", BSDCLibrary.class);
+ } else if (Platform.isFreeBSD()) {
+ return (CLibrary) Native.loadLibrary("c", FreeBSDCLibrary.class);
+ } else if (Platform.isSolaris()) {
+ return (CLibrary) Native.loadLibrary("c", SolarisCLibrary.class);
+ } else if (Platform.isLinux()) {
+ return (CLibrary) Native.loadLibrary("c", LinuxCLibrary.class);
+ } else {
+ return (CLibrary) Native.loadLibrary("c", CLibrary.class);
+ }
+ }
+ }
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDCLibrary.java
new file mode 100644
index 0000000..638aec2
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDCLibrary.java
@@ -0,0 +1,34 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2014, R. Tyler Croy, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author R. Tyler Croy
+ */
+public interface FreeBSDCLibrary extends CLibrary {
+
+ FreeBSDPasswd getpwnam(String username);
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDPasswd.java
new file mode 100644
index 0000000..28e519b
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/FreeBSDPasswd.java
@@ -0,0 +1,98 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2014, R. Tyler Croy, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * FreeeBSD
+ * <p>
+ * struct passwd {
+ * char *pw_name;
+ * char *pw_passwd;
+ * uid_t pw_uid;
+ * gid_t pw_gid;
+ * time_t pw_change;
+ * char *pw_class;
+ * char *pw_gecos;
+ * char *pw_dir;
+ * char *pw_shell;
+ * time_t pw_expire;
+ * int pw_fields;
+ * };
+ *
+ * @author R. Tyler Croy
+ */
+
+public class FreeBSDPasswd extends passwd {
+ /* password change time */
+ public long pw_change;
+
+ /* user access class */
+ public String pw_class;
+
+ /* Honeywell login info */
+ public String pw_gecos;
+
+ /* home directory */
+ public String pw_dir;
+
+ /* default shell */
+ public String pw_shell;
+
+ /* account expiration */
+ public long pw_expire;
+
+ /* internal on FreeBSD? */
+ public int pw_fields;
+
+ @Override
+ public String getPwGecos() {
+ return pw_gecos;
+ }
+
+ @Override
+ public String getPwDir() {
+ return pw_dir;
+ }
+
+ @Override
+ public String getPwShell() {
+ return pw_shell;
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ List fieldOrder = new ArrayList(super.getFieldOrder());
+ fieldOrder.addAll(Arrays.asList("pw_change", "pw_class", "pw_gecos",
+ "pw_dir", "pw_shell", "pw_expire", "pw_fields"));
+ return fieldOrder;
+ }
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxCLibrary.java
new file mode 100644
index 0000000..2525bbe
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxCLibrary.java
@@ -0,0 +1,34 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2011, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author Sebastian Sdorra
+ */
+public interface LinuxCLibrary extends CLibrary {
+
+ LinuxPasswd getpwnam(String username);
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxPasswd.java
new file mode 100644
index 0000000..c1b1678
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/LinuxPasswd.java
@@ -0,0 +1,81 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2011, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Linux passwd
+ * <p>
+ * ?struct passwd
+ * {
+ * char *pw_name;
+ * char *pw_passwd;
+ * __uid_t pw_uid;
+ * __gid_t pw_gid;
+ * char *pw_gecos;
+ * char *pw_dir;
+ * char *pw_shell;
+ * };
+ *
+ * @author Sebastian Sdorra
+ */
+public class LinuxPasswd extends passwd {
+ /* Honeywell login info */
+ public String pw_gecos;
+
+ /* home directory */
+ public String pw_dir;
+
+ /* default shell */
+ public String pw_shell;
+
+
+ public String getPwGecos() {
+ return pw_gecos;
+ }
+
+ @Override
+ public String getPwDir() {
+ return pw_dir;
+ }
+
+ @Override
+ public String getPwShell() {
+ return pw_shell;
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ List fieldOrder = new ArrayList(super.getFieldOrder());
+ fieldOrder.addAll(Arrays.asList("pw_gecos", "pw_dir", "pw_shell"));
+ return fieldOrder;
+ }
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java
new file mode 100644
index 0000000..a34ec31
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/PAMLibrary.java
@@ -0,0 +1,163 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam.impl;
+
+import com.sun.jna.Callback;
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.PointerType;
+import com.sun.jna.Structure;
+import com.sun.jna.ptr.PointerByReference;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.jvnet.libpam.impl.CLibrary.libc;
+
+/**
+ * libpam.so binding.
+ * <p>
+ * See http://www.opengroup.org/onlinepubs/008329799/apdxa.htm
+ * for the online reference of pam_appl.h
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public interface PAMLibrary extends Library {
+ class pam_handle_t extends PointerType {
+ public pam_handle_t() {
+ }
+
+ public pam_handle_t(Pointer pointer) {
+ super(pointer);
+ }
+ }
+
+ class pam_message extends Structure {
+ public int msg_style;
+ public String msg;
+
+ /**
+ * Attach to the memory region pointed by the given pointer.
+ */
+ public pam_message(Pointer src) {
+ useMemory(src);
+ read();
+ }
+
+ protected List getFieldOrder() {
+ return Arrays.asList("msg_style", "msg");
+ }
+ }
+
+ class pam_response extends Structure {
+ /**
+ * This is really a string, but this field needs to be malloc-ed by the conversation
+ * method, and to be freed by the caler, so I bind it to {@link Pointer} here.
+ * <p>
+ * The man page doesn't say that, but see
+ * http://www.netbsd.org/docs/guide/en/chap-pam.html#pam-sample-conv
+ * This behavior is confirmed with a test, too; if I don't do strdup,
+ * libpam crashes.
+ */
+ public Pointer resp;
+ public int resp_retcode;
+
+ /**
+ * Attach to the memory region pointed by the given memory.
+ */
+ public pam_response(Pointer src) {
+ useMemory(src);
+ read();
+ }
+
+ public pam_response() {
+ }
+
+ /**
+ * Sets the response code.
+ */
+ public void setResp(String msg) {
+ this.resp = libc.strdup(msg);
+ }
+
+ protected List getFieldOrder() {
+ return Arrays.asList("resp", "resp_retcode");
+ }
+
+ public static final int SIZE = new pam_response().size();
+ }
+
+ class pam_conv extends Structure {
+ public interface PamCallback extends Callback {
+ /**
+ * According to http://www.netbsd.org/docs/guide/en/chap-pam.html#pam-sample-conv,
+ * resp and its member string both needs to be allocated by malloc,
+ * to be freed by the caller.
+ */
+ int callback(int num_msg, Pointer msg, Pointer resp, Pointer _);
+ }
+
+ public PamCallback conv;
+ public Pointer _;
+
+ public pam_conv(PamCallback conv) {
+ this.conv = conv;
+ }
+
+ protected List getFieldOrder() {
+ return Arrays.asList("conv", "_");
+ }
+ }
+
+ int pam_start(String service, String user, pam_conv conv, PointerByReference/* pam_handle_t** */ pamh_p);
+
+ int pam_end(pam_handle_t handle, int pam_status);
+
+ int pam_set_item(pam_handle_t handle, int item_type, String item);
+
+ int pam_get_item(pam_handle_t handle, int item_type, PointerByReference item);
+
+ int pam_authenticate(pam_handle_t handle, int flags);
+
+ int pam_setcred(pam_handle_t handle, int flags);
+
+ int pam_acct_mgmt(pam_handle_t handle, int flags);
+
+ String pam_strerror(pam_handle_t handle, int pam_error);
+
+ final int PAM_USER = 2;
+
+ // error code
+ final int PAM_SUCCESS = 0;
+ final int PAM_CONV_ERR = 6;
+
+
+ final int PAM_PROMPT_ECHO_OFF = 1; /* Echo off when getting response */
+ final int PAM_PROMPT_ECHO_ON = 2; /* Echo on when getting response */
+ final int PAM_ERROR_MSG = 3; /* Error message */
+ final int PAM_TEXT_INFO = 4; /* Textual information */
+
+ public static final PAMLibrary libpam = (PAMLibrary) Native.loadLibrary("pam", PAMLibrary.class);
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisCLibrary.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisCLibrary.java
new file mode 100644
index 0000000..6b538a2
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisCLibrary.java
@@ -0,0 +1,35 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+package org.jvnet.libpam.impl;
+
+/**
+ * @author Sebastian Sdorra
+ */
+public interface SolarisCLibrary extends CLibrary {
+
+ SolarisPasswd getpwnam(String username);
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisPasswd.java b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisPasswd.java
new file mode 100644
index 0000000..37ee749
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/impl/SolarisPasswd.java
@@ -0,0 +1,86 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+package org.jvnet.libpam.impl;
+
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Solaris passwd
+ * <p>
+ * struct passwd {
+ * char *pw_name;
+ * char *pw_passwd;
+ * uid_t pw_uid;
+ * gid_t pw_gid;
+ * char *pw_age;
+ * char *pw_comment;
+ * char *pw_gecos;
+ * char *pw_dir;
+ * char *pw_shell;
+ * };
+ *
+ * @author Sebastian Sdorra
+ */
+public class SolarisPasswd extends passwd {
+ public String pw_age;
+
+ public String pw_comment;
+
+ public String pw_gecos;
+
+ public String pw_dir;
+
+ public String pw_shell;
+
+
+ @Override
+ public String getPwGecos() {
+ return pw_gecos;
+ }
+
+ @Override
+ public String getPwDir() {
+ return pw_dir;
+ }
+
+ @Override
+ public String getPwShell() {
+ return pw_shell;
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ List fieldOrder = new ArrayList(super.getFieldOrder());
+ fieldOrder.addAll(Arrays.asList("pw_age", "pw_comment", "pw_gecos",
+ "pw_dir", "pw_shell"));
+ return fieldOrder;
+ }
+
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/PAM.java b/federation/sssd/src/main/java/org/jvnet/libpam/PAM.java
new file mode 100644
index 0000000..7de5f90
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/PAM.java
@@ -0,0 +1,188 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import com.sun.jna.Pointer;
+import com.sun.jna.ptr.PointerByReference;
+import org.jboss.logging.Logger;
+import org.jvnet.libpam.impl.CLibrary.passwd;
+import org.jvnet.libpam.impl.PAMLibrary.pam_conv;
+import org.jvnet.libpam.impl.PAMLibrary.pam_conv.PamCallback;
+import org.jvnet.libpam.impl.PAMLibrary.pam_handle_t;
+import org.jvnet.libpam.impl.PAMLibrary.pam_message;
+import org.jvnet.libpam.impl.PAMLibrary.pam_response;
+
+import java.util.Set;
+
+import static com.sun.jna.Native.POINTER_SIZE;
+import static org.jvnet.libpam.impl.CLibrary.libc;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_CONV_ERR;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_PROMPT_ECHO_OFF;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_SUCCESS;
+import static org.jvnet.libpam.impl.PAMLibrary.PAM_USER;
+import static org.jvnet.libpam.impl.PAMLibrary.libpam;
+
+/**
+ * PAM authenticator.
+ * <p>
+ * <p>
+ * Instances are thread unsafe and non reentrant. An instace cannot be reused
+ * to authenticate multiple users.
+ * <p>
+ * <p>
+ * For an overview of PAM programming, refer to the following resources:
+ * <p>
+ * <ul>
+ * <li><a href="http://www.netbsd.org/docs/guide/en/chap-pam.html">NetBSD PAM programming guide</a>
+ * <li><a href="http://www.kernel.org/pub/linux/libs/pam/">Linux PAM</a>
+ * </ul>
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class PAM {
+ private pam_handle_t pht;
+ private int ret;
+
+ /**
+ * Temporarily stored to pass a value from {@link #authenticate(String, String...)}
+ * to {@link pam_conv}.
+ */
+ private String[] factors;
+
+ /**
+ * Creates a new authenticator.
+ *
+ * @param serviceName PAM service name. This corresponds to the service name that shows up
+ * in the PAM configuration,
+ */
+ public PAM(String serviceName) throws PAMException {
+ pam_conv conv = new pam_conv(new PamCallback() {
+ public int callback(int num_msg, Pointer msg, Pointer resp, Pointer _) {
+ LOGGER.debug("pam_conv num_msg=" + num_msg);
+ if (factors == null)
+ return PAM_CONV_ERR;
+
+ // allocates pam_response[num_msg]. the caller will free this
+ Pointer m = libc.calloc(pam_response.SIZE, num_msg);
+ resp.setPointer(0, m);
+
+ for (int i = 0; i < factors.length; i++) {
+ pam_message pm = new pam_message(msg.getPointer(POINTER_SIZE * i));
+ LOGGER.debug(pm.msg_style + ":" + pm.msg);
+ if (pm.msg_style == PAM_PROMPT_ECHO_OFF) {
+ pam_response r = new pam_response(m.share(pam_response.SIZE * i));
+ r.setResp(factors[i]);
+ r.write(); // write to (*resp)[i]
+ }
+ }
+
+ return PAM_SUCCESS;
+ }
+ });
+
+ PointerByReference phtr = new PointerByReference();
+ check(libpam.pam_start(serviceName, null, conv, phtr), "pam_start failed");
+ pht = new pam_handle_t(phtr.getValue());
+ }
+
+ private void check(int ret, String msg) throws PAMException {
+ this.ret = ret;
+ if (ret != 0) {
+ if (pht != null)
+ throw new PAMException(msg + " : " + libpam.pam_strerror(pht, ret));
+ else
+ throw new PAMException(msg);
+ }
+ }
+
+ /**
+ * Authenticate the user with a password.
+ *
+ * @return Upon a successful authentication, return information about the user.
+ * @throws PAMException If the authentication fails.
+ */
+ public UnixUser authenticate(String username, String... factors) throws PAMException {
+ this.factors = factors;
+ try {
+ check(libpam.pam_set_item(pht, PAM_USER, username), "pam_set_item failed");
+ check(libpam.pam_authenticate(pht, 0), "pam_authenticate failed");
+ check(libpam.pam_setcred(pht, 0), "pam_setcred failed");
+ // several different error code seem to be used to represent authentication failures
+// check(libpam.pam_acct_mgmt(pht,0),"pam_acct_mgmt failed");
+
+ PointerByReference r = new PointerByReference();
+ check(libpam.pam_get_item(pht, PAM_USER, r), "pam_get_item failed");
+ String userName = r.getValue().getString(0);
+ passwd pwd = libc.getpwnam(userName);
+ if (pwd == null)
+ throw new PAMException("Authentication succeeded but no user information is available");
+ return new UnixUser(userName, pwd);
+ } finally {
+ this.factors = null;
+ }
+ }
+
+ /**
+ * Returns the groups a user belongs to
+ *
+ * @param username
+ * @return Set of group names
+ * @throws PAMException
+ * @deprecated Pointless and ugly convenience method.
+ */
+ public Set<String> getGroupsOfUser(String username) throws PAMException {
+ return new UnixUser(username).getGroups();
+ }
+
+ /**
+ * After a successful authentication, call this method to obtain the effective user name.
+ * This can be different from the user name that you passed to the {@link #authenticate(String, String)}
+ * method.
+ */
+
+ /**
+ * Performs an early disposal of the object, instead of letting this GC-ed.
+ * Since PAM may hold on to native resources that don't put pressure on Java GC,
+ * doing this is a good idea.
+ * <p>
+ * <p>
+ * This method is called by {@link #finalize()}, too, so it's not required
+ * to call this method explicitly, however.
+ */
+ public void dispose() {
+ if (pht != null) {
+ libpam.pam_end(pht, ret);
+ pht = null;
+ }
+ }
+
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ dispose();
+ }
+
+ private static final Logger LOGGER = Logger.getLogger(PAM.class.getName());
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/PAMException.java b/federation/sssd/src/main/java/org/jvnet/libpam/PAMException.java
new file mode 100644
index 0000000..d26faf7
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/PAMException.java
@@ -0,0 +1,48 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+/**
+ * Exception in PAM invoactions.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class PAMException extends Exception {
+ public PAMException() {
+ }
+
+ public PAMException(String message) {
+ super(message);
+ }
+
+ public PAMException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public PAMException(Throwable cause) {
+ super(cause);
+ }
+
+ private static final long serialVersionUID = 1L;
+}
diff --git a/federation/sssd/src/main/java/org/jvnet/libpam/UnixUser.java b/federation/sssd/src/main/java/org/jvnet/libpam/UnixUser.java
new file mode 100644
index 0000000..bc1ceab
--- /dev/null
+++ b/federation/sssd/src/main/java/org/jvnet/libpam/UnixUser.java
@@ -0,0 +1,159 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import com.sun.jna.Memory;
+import com.sun.jna.ptr.IntByReference;
+import org.jvnet.libpam.impl.CLibrary.group;
+import org.jvnet.libpam.impl.CLibrary.passwd;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.jvnet.libpam.impl.CLibrary.libc;
+
+/**
+ * Represents an Unix user. Immutable.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class UnixUser {
+ private final String userName, gecos, dir, shell;
+ private final int uid, gid;
+ private final Set<String> groups;
+
+ /*package*/ UnixUser(String userName, passwd pwd) throws PAMException {
+ this.userName = userName;
+ this.gecos = pwd.getPwGecos();
+ this.dir = pwd.getPwDir();
+ this.shell = pwd.getPwShell();
+ this.uid = pwd.getPwUid();
+ this.gid = pwd.getPwGid();
+
+ int sz = 4; /*sizeof(gid_t)*/
+
+ int ngroups = 64;
+ Memory m = new Memory(ngroups * sz);
+ IntByReference pngroups = new IntByReference(ngroups);
+ try {
+ if (libc.getgrouplist(userName, pwd.getPwGid(), m, pngroups) < 0) {
+ // allocate a bigger memory
+ m = new Memory(pngroups.getValue() * sz);
+ if (libc.getgrouplist(userName, pwd.getPwGid(), m, pngroups) < 0)
+ // shouldn't happen, but just in case.
+ throw new PAMException("getgrouplist failed");
+ }
+ ngroups = pngroups.getValue();
+ } catch (LinkageError e) {
+ // some platform, notably Solaris, doesn't have the getgrouplist function
+ ngroups = libc._getgroupsbymember(userName, m, ngroups, 0);
+ if (ngroups < 0)
+ throw new PAMException("_getgroupsbymember failed");
+ }
+
+ groups = new HashSet<String>();
+ for (int i = 0; i < ngroups; i++) {
+ int gid = m.getInt(i * sz);
+ group grp = libc.getgrgid(gid);
+ if (grp == null) {
+ continue;
+ }
+ groups.add(grp.gr_name);
+ }
+ }
+
+ public UnixUser(String userName) throws PAMException {
+ this(userName, passwd.loadPasswd(userName));
+ }
+
+ /**
+ * Copy constructor for mocking. Not intended for regular use. Only for testing.
+ * This signature may change in the future.
+ */
+ protected UnixUser(String userName, String gecos, String dir, String shell, int uid, int gid, Set<String> groups) {
+ this.userName = userName;
+ this.gecos = gecos;
+ this.dir = dir;
+ this.shell = shell;
+ this.uid = uid;
+ this.gid = gid;
+ this.groups = groups;
+ }
+
+ /**
+ * Gets the unix account name. Never null.
+ */
+ public String getUserName() {
+ return userName;
+ }
+
+ /**
+ * Gets the UID of this user.
+ */
+ public int getUID() {
+ return uid;
+ }
+
+ /**
+ * Gets the GID of this user.
+ */
+ public int getGID() {
+ return gid;
+ }
+
+ /**
+ * Gets the gecos (the real name) of this user.
+ */
+ public String getGecos() {
+ return gecos;
+ }
+
+ /**
+ * Gets the home directory of this user.
+ */
+ public String getDir() {
+ return dir;
+ }
+
+ /**
+ * Gets the shell of this user.
+ */
+ public String getShell() {
+ return shell;
+ }
+
+ /**
+ * Gets the groups that this user belongs to.
+ *
+ * @return never null.
+ */
+ public Set<String> getGroups() {
+ return Collections.unmodifiableSet(groups);
+ }
+
+ public static boolean exists(String name) {
+ return libc.getpwnam(name) != null;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java
new file mode 100644
index 0000000..a5bb57a
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd.api;
+
+import org.freedesktop.dbus.DBusConnection;
+import org.freedesktop.dbus.Variant;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.sssd.infopipe.InfoPipe;
+import org.freedesktop.sssd.infopipe.User;
+import org.jboss.logging.Logger;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class Sssd {
+
+ public static final String BUSNAME = "org.freedesktop.sssd.infopipe";
+
+ public static User user() {
+ return SingletonHolder.USER_OBJECT;
+ }
+
+ public static InfoPipe infopipe() {
+ return SingletonHolder.INFOPIPE_OBJECT;
+ }
+
+ public static void disconnect() {
+ SingletonHolder.DBUS_CONNECTION.disconnect();
+ }
+
+ private String username;
+ private static final Logger logger = Logger.getLogger(Sssd.class);
+
+ private Sssd() {
+ }
+
+ public Sssd(String username) {
+ this.username = username;
+ }
+
+ private static final class SingletonHolder {
+ private static InfoPipe INFOPIPE_OBJECT;
+ private static User USER_OBJECT;
+ private static DBusConnection DBUS_CONNECTION;
+
+ static {
+ try {
+ DBUS_CONNECTION = DBusConnection.getConnection(DBusConnection.SYSTEM);
+ INFOPIPE_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, InfoPipe.OBJECTPATH, InfoPipe.class);
+ USER_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, User.OBJECTPATH, User.class);
+ } catch (DBusException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static String getRawAttribute(Variant variant) {
+ if (variant != null) {
+ Vector value = (Vector) variant.getValue();
+ if (value.size() >= 1) {
+ return value.get(0).toString();
+ }
+ }
+ return null;
+ }
+
+ public Map<String, Variant> getUserAttributes() {
+ String[] attr = {"mail", "givenname", "sn", "telephoneNumber"};
+ Map<String, Variant> attributes = null;
+ try {
+ InfoPipe infoPipe = infopipe();
+ attributes = infoPipe.getUserAttributes(username, Arrays.asList(attr));
+ } catch (Exception e) {
+ logger.error("Failed to retrieve user's attributes from SSSD", e);
+ }
+
+ return attributes;
+ }
+
+ public List<String> getUserGroups() {
+ List<String> userGroups = null;
+ try {
+ InfoPipe infoPipe = Sssd.infopipe();
+ userGroups = infoPipe.getUserGroups(username);
+ } catch (Exception e) {
+ logger.error("Failed to retrieve user's groups from SSSD", e);
+ }
+ return userGroups;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/impl/PAMAuthenticator.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/impl/PAMAuthenticator.java
new file mode 100644
index 0000000..f982201
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/impl/PAMAuthenticator.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd.impl;
+
+import org.jboss.logging.Logger;
+import org.jvnet.libpam.PAM;
+import org.jvnet.libpam.PAMException;
+import org.jvnet.libpam.UnixUser;
+
+/**
+ * PAMAuthenticator for Unix users
+ *
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class PAMAuthenticator {
+
+ private static final String PAM_SERVICE = "keycloak";
+ private static final Logger logger = Logger.getLogger(PAMAuthenticator.class);
+ private final String username;
+ private final String[] factors;
+
+ public PAMAuthenticator(String username, String... factors) {
+ this.username = username;
+ this.factors = factors;
+ }
+
+ /**
+ * Returns true if user was successfully authenticated against PAM
+ *
+ * @return UnixUser object if user was successfully authenticated
+ */
+ public UnixUser authenticate() {
+ PAM pam = null;
+ UnixUser user = null;
+ try {
+ pam = new PAM(PAM_SERVICE);
+ user = pam.authenticate(username, factors);
+ } catch (PAMException e) {
+ logger.error("Authentication failed", e);
+ e.printStackTrace();
+ } finally {
+ pam.dispose();
+ }
+ return user;
+ }
+}
diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java
new file mode 100755
index 0000000..52061c9
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/ReadonlySSSDUserModelDelegate.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd;
+
+import org.keycloak.models.ModelReadOnlyException;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.UserModelDelegate;
+
+/**
+ * Readonly proxy for a SSSD UserModel that prevents attributes from being updated.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class ReadonlySSSDUserModelDelegate extends UserModelDelegate implements UserModel {
+
+ private final SSSDFederationProvider provider;
+
+ public ReadonlySSSDUserModelDelegate(UserModel delegate, SSSDFederationProvider provider) {
+ super(delegate);
+ this.provider = provider;
+ }
+
+ @Override
+ public void setUsername(String username) {
+ throw new ModelReadOnlyException("Federated storage is not writable");
+ }
+
+ @Override
+ public void setLastName(String lastName) {
+ throw new ModelReadOnlyException("Federated storage is not writable");
+ }
+
+ @Override
+ public void setFirstName(String first) {
+ throw new ModelReadOnlyException("Federated storage is not writable");
+ }
+
+ @Override
+ public void updateCredentialDirectly(UserCredentialValueModel cred) {
+ if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+ throw new IllegalStateException("Federated storage is not writable");
+ }
+ super.updateCredentialDirectly(cred);
+ }
+
+ @Override
+ public void updateCredential(UserCredentialModel cred) {
+ if (provider.getSupportedCredentialTypes(delegate).contains(cred.getType())) {
+ throw new ModelReadOnlyException("Federated storage is not writable");
+ }
+ delegate.updateCredential(cred);
+ }
+
+ @Override
+ public void setEmail(String email) {
+ throw new ModelReadOnlyException("Federated storage is not writable");
+ }
+}
diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java
new file mode 100755
index 0000000..a9089ec
--- /dev/null
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProvider.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.federation.sssd;
+
+import org.freedesktop.dbus.Variant;
+import org.jboss.logging.Logger;
+import org.keycloak.federation.sssd.api.Sssd;
+import org.keycloak.federation.sssd.impl.PAMAuthenticator;
+import org.keycloak.models.CredentialValidationOutput;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.services.managers.UserManager;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * SPI provider implementation to retrieve data from SSSD and authenticate
+ * against PAM
+ *
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
+ * @version $Revision: 1 $
+ */
+public class SSSDFederationProvider implements UserFederationProvider {
+
+ private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
+
+ protected static final Set<String> supportedCredentialTypes = new HashSet<>();
+ private final SSSDFederationProviderFactory factory;
+ protected KeycloakSession session;
+ protected UserFederationProviderModel model;
+
+ public SSSDFederationProvider(KeycloakSession session, UserFederationProviderModel model, SSSDFederationProviderFactory sssdFederationProviderFactory) {
+ this.session = session;
+ this.model = model;
+ this.factory = sssdFederationProviderFactory;
+ }
+
+ static {
+ supportedCredentialTypes.add(UserCredentialModel.PASSWORD);
+ }
+
+
+ @Override
+ public UserModel getUserByUsername(RealmModel realm, String username) {
+ return findOrCreateAuthenticatedUser(realm, username);
+ }
+
+ /**
+ * Called after successful authentication
+ *
+ * @param realm realm
+ * @param username username without realm prefix
+ * @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider
+ */
+ protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
+ UserModel user = session.userStorage().getUserByUsername(username, realm);
+ if (user != null) {
+ logger.debug("SSSD authenticated user " + username + " found in Keycloak storage");
+
+ if (!model.getId().equals(user.getFederationLink())) {
+ logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() + "]");
+ return null;
+ } else {
+ UserModel proxied = validateAndProxy(realm, user);
+ if (proxied != null) {
+ return proxied;
+ } else {
+ logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
+ "] but principal is not correct.");
+ logger.warn("Will re-create user");
+ new UserManager(session).removeUser(realm, user, session.userStorage());
+ }
+ }
+ }
+
+ logger.debug("SSSD authenticated user " + username + " not in Keycloak storage. Creating...");
+ return importUserToKeycloak(realm, username);
+ }
+
+ protected UserModel importUserToKeycloak(RealmModel realm, String username) {
+ Sssd sssd = new Sssd(username);
+ Map<String, Variant> sssdUser = sssd.getUserAttributes();
+ logger.debugf("Creating SSSD user: %s to local Keycloak storage", username);
+ UserModel user = session.userStorage().addUser(realm, username);
+ user.setEnabled(true);
+ user.setEmail(Sssd.getRawAttribute(sssdUser.get("mail")));
+ user.setFirstName(Sssd.getRawAttribute(sssdUser.get("givenname")));
+ user.setLastName(Sssd.getRawAttribute(sssdUser.get("sn")));
+ for (String s : sssd.getUserGroups()) {
+ GroupModel group = KeycloakModelUtils.findGroupByPath(realm, "/" + s);
+ if (group == null) {
+ group = session.realms().createGroup(realm, s);
+ }
+ user.joinGroup(group);
+ }
+ user.setFederationLink(model.getId());
+ return validateAndProxy(realm, user);
+ }
+
+ @Override
+ public UserModel getUserByEmail(RealmModel realm, String email) {
+ return null;
+ }
+
+ @Override
+ public List<UserModel> searchByAttributes(Map<String, String> attributes, RealmModel realm, int maxResults) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void preRemove(RealmModel realm) {
+ // complete We don't care about the realm being removed
+ }
+
+ @Override
+ public void preRemove(RealmModel realm, RoleModel role) {
+ // complete we dont'care if a role is removed
+
+ }
+
+ @Override
+ public void preRemove(RealmModel realm, GroupModel group) {
+ // complete we dont'care if a role is removed
+
+ }
+
+ @Override
+ public boolean isValid(RealmModel realm, UserModel local) {
+ Map<String, Variant> attributes = new Sssd(local.getUsername()).getUserAttributes();
+ return Sssd.getRawAttribute(attributes.get("mail")).equalsIgnoreCase(local.getEmail());
+ }
+
+ @Override
+ public Set<String> getSupportedCredentialTypes(UserModel user) {
+ return supportedCredentialTypes;
+ }
+
+ @Override
+ public Set<String> getSupportedCredentialTypes() {
+ return supportedCredentialTypes;
+ }
+
+ @Override
+ public boolean validCredentials(RealmModel realm, UserModel user, List<UserCredentialModel> input) {
+ for (UserCredentialModel cred : input) {
+ if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+ PAMAuthenticator pam = factory.createPAMAuthenticator(user.getUsername(), cred.getValue());
+ return (pam.authenticate() != null);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean validCredentials(RealmModel realm, UserModel user, UserCredentialModel... input) {
+ return validCredentials(realm, user, Arrays.asList(input));
+ }
+
+ @Override
+ public CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential) {
+ return CredentialValidationOutput.failed();
+ }
+
+ @Override
+ public UserModel validateAndProxy(RealmModel realm, UserModel local) {
+ if (isValid(realm, local)) {
+ return new ReadonlySSSDUserModelDelegate(local, this);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean synchronizeRegistrations() {
+ return false;
+ }
+
+ @Override
+ public UserModel register(RealmModel realm, UserModel user) {
+ throw new IllegalStateException("Registration not supported");
+ }
+
+ @Override
+ public boolean removeUser(RealmModel realm, UserModel user) {
+ return true;
+ }
+
+ @Override
+ public void close() {
+ Sssd.disconnect();
+ }
+}
diff --git a/federation/sssd/src/main/resources/DBUS-JAVA-AUTHORS b/federation/sssd/src/main/resources/DBUS-JAVA-AUTHORS
new file mode 100644
index 0000000..9b7699e
--- /dev/null
+++ b/federation/sssd/src/main/resources/DBUS-JAVA-AUTHORS
@@ -0,0 +1,37 @@
+The D-Bus Java implementation was written by:
+
+Matthew Johnson <dbus -at matthew -dot- ath -dot- cx>
+
+Bug fixes/reports and other suggestions from:
+
+Remi Emonet <remi.emonet -at- inrialpes -dot- fr>
+Simon McVittie <simon -dot- mcvittie -at- collabora -dot- co -dot- uk>
+Dick Hollenbeck <dick -at- softplc -dot- com>
+Joshua Nichols <nichoj -at- gentoo -dot- org>
+Ralf Kistner <ralf.kistner -at- gmail -dot- com>
+Henrik Petander <henrik -dot- petander -at- iki -dot- fi>
+Luigi Paioro <luigi -at- lambrate -dot- it>
+Roberto Francisco Arroyo Moreno <robfram -at- ugr -dot- es>
+Steve Crane <Steve -dot Crane -at- rococosoft -dot- com>
+Philippe Marschall <philippe -dot- marschall -at- gmail -dot- com>
+Daniel Machado <cdanielmachado -at- gmail -dot- com>
+Anibal Sanchez <anibal -dot- sanchez -at- sunya -dot- com -dot- ar>
+Jan Kümmel <freedesktop -at- snorc -dot- org>
+Johannes Felten <johannesfelten -at- googlemail -dot- com>
+Tom Walsh <walshtc -at- gmail -dot- com>
+Ed Wei <Edward.Wei.03 -at- alum -dot- dartmouth -dot- org>
+Sveinung Kvilhaugsvik <sveinung84 -at- users -dot- sourceforge -dot- net>
+Hugues Moreau <hmoreau -at- gmail -dot- com>
+Viktar Vauchkevich <vctr -at- yandex -dot- ru>
+Serkan Kaba <serkan_kaba -at- yahoo -dot- com>
+Adam Bennett <cruxic -at- gmail -dot- com>
+Frank Benoit <benoit -at- tionex -dot- de>
+Gunnar Aastrand Grimnes <gunnar -dot- grimnes -at- dfki -dot- de>
+
+The included Viewer application was originally written by:
+
+Peter Cox <petercox -at- gawab -dot- com>
+
+with patches from:
+
+Zsombor Gegesy <gzsombor -at- gmail -dot- com>
federation/sssd/src/main/resources/DBUS-JAVA-LICENSE 680(+680 -0)
diff --git a/federation/sssd/src/main/resources/DBUS-JAVA-LICENSE b/federation/sssd/src/main/resources/DBUS-JAVA-LICENSE
new file mode 100644
index 0000000..d651143
--- /dev/null
+++ b/federation/sssd/src/main/resources/DBUS-JAVA-LICENSE
@@ -0,0 +1,680 @@
+The D-Bus Java implementation is licensed to you under your choice of the
+Academic Free License version 2.1, or the GNU Lesser/Library General Public License
+version 2. Both licenses are included here. Each source code file is marked
+with the proper copyright information.
+
+The Academic Free License
+v. 2.1
+
+This Academic Free License (the "License") applies to any original work of
+authorship (the "Original Work") whose owner (the "Licensor") has placed the
+following notice immediately following the copyright notice for the Original
+Work:
+
+Licensed under the Academic Free License version 2.1
+
+1) Grant of Copyright License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license to do the
+following:
+
+a) to reproduce the Original Work in copies;
+
+b) to prepare derivative works ("Derivative Works") based upon the Original
+Work;
+
+c) to distribute copies of the Original Work and Derivative Works to the
+public;
+
+d) to perform the Original Work publicly; and
+
+e) to display the Original Work publicly.
+
+2) Grant of Patent License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
+claims owned or controlled by the Licensor that are embodied in the Original
+Work as furnished by the Licensor, to make, use, sell and offer for sale the
+Original Work and Derivative Works.
+
+3) Grant of Source Code License. The term "Source Code" means the preferred
+form of the Original Work for making modifications to it and all available
+documentation describing how to modify the Original Work. Licensor hereby
+agrees to provide a machine-readable copy of the Source Code of the Original
+Work along with each copy of the Original Work that Licensor distributes.
+Licensor reserves the right to satisfy this obligation by placing a
+machine-readable copy of the Source Code in an information repository
+reasonably calculated to permit inexpensive and convenient access by You for as
+long as Licensor continues to distribute the Original Work, and by publishing
+the address of that information repository in a notice immediately following
+the copyright notice that applies to the Original Work.
+
+4) Exclusions From License Grant. Neither the names of Licensor, nor the names
+of any contributors to the Original Work, nor any of their trademarks or
+service marks, may be used to endorse or promote products derived from this
+Original Work without express prior written permission of the Licensor. Nothing
+in this License shall be deemed to grant any rights to trademarks, copyrights,
+patents, trade secrets or any other intellectual property of Licensor except as
+expressly stated herein. No patent license is granted to make, use, sell or
+offer to sell embodiments of any patent claims other than the licensed claims
+defined in Section 2. No right is granted to the trademarks of Licensor even if
+such marks are included in the Original Work. Nothing in this License shall be
+interpreted to prohibit Licensor from licensing under different terms from this
+License any Original Work that Licensor otherwise would have a right to
+license.
+
+5) This section intentionally omitted.
+
+6) Attribution Rights. You must retain, in the Source Code of any Derivative
+Works that You create, all copyright, patent or trademark notices from the
+Source Code of the Original Work, as well as any notices of licensing and any
+descriptive text identified therein as an "Attribution Notice." You must cause
+the Source Code for any Derivative Works that You create to carry a prominent
+Attribution Notice reasonably calculated to inform recipients that You have
+modified the Original Work.
+
+7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
+the copyright in and to the Original Work and the patent rights granted herein
+by Licensor are owned by the Licensor or are sublicensed to You under the terms
+of this License with the permission of the contributor(s) of those copyrights
+and patent rights. Except as expressly stated in the immediately proceeding
+sentence, the Original Work is provided under this License on an "AS IS" BASIS
+and WITHOUT WARRANTY, either express or implied, including, without limitation,
+the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
+This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
+license to Original Work is granted hereunder except under this disclaimer.
+
+8) Limitation of Liability. Under no circumstances and under no legal theory,
+whether in tort (including negligence), contract, or otherwise, shall the
+Licensor be liable to any person for any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License
+or the use of the Original Work including, without limitation, damages for loss
+of goodwill, work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses. This limitation of liability shall not
+apply to liability for death or personal injury resulting from Licensor's
+negligence to the extent applicable law prohibits such limitation. Some
+jurisdictions do not allow the exclusion or limitation of incidental or
+consequential damages, so this exclusion and limitation may not apply to You.
+
+9) Acceptance and Termination. If You distribute copies of the Original Work or
+a Derivative Work, You must make a reasonable effort under the circumstances to
+obtain the express assent of recipients to the terms of this License. Nothing
+else but this License (or another written agreement between Licensor and You)
+grants You permission to create Derivative Works based upon the Original Work
+or to exercise any of the rights granted in Section 1 herein, and any attempt
+to do so except under the terms of this License (or another written agreement
+between Licensor and You) is expressly prohibited by U.S. copyright law, the
+equivalent laws of other countries, and by international treaty. Therefore, by
+exercising any of the rights granted to You in Section 1 herein, You indicate
+Your acceptance of this License and all of its terms and conditions.
+
+10) Termination for Patent Action. This License shall terminate automatically
+and You may no longer exercise any of the rights granted to You by this License
+as of the date You commence an action, including a cross-claim or counterclaim,
+against Licensor or any licensee alleging that the Original Work infringes a
+patent. This termination provision shall not apply for an action alleging
+patent infringement by combinations of the Original Work with other software or
+hardware.
+
+11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
+License may be brought only in the courts of a jurisdiction wherein the
+Licensor resides or in which Licensor conducts its primary business, and under
+the laws of that jurisdiction excluding its conflict-of-law provisions. The
+application of the United Nations Convention on Contracts for the International
+Sale of Goods is expressly excluded. Any use of the Original Work outside the
+scope of this License or after its termination shall be subject to the
+requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq.,
+the equivalent laws of other countries, and international treaty. This section
+shall survive the termination of this License.
+
+12) Attorneys Fees. In any action to enforce the terms of this License or
+seeking damages relating thereto, the prevailing party shall be entitled to
+recover its costs and expenses, including, without limitation, reasonable
+attorneys' fees and costs incurred in connection with such action, including
+any appeal of such action. This section shall survive the termination of this
+License.
+
+13) Miscellaneous. This License represents the complete agreement concerning
+the subject matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent necessary to
+make it enforceable.
+
+14) Definition of "You" in This License. "You" throughout this License, whether
+in upper or lower case, means an individual or a legal entity exercising rights
+under, and complying with all of the terms of, this License. For legal
+entities, "You" includes any entity that controls, is controlled by, or is
+under common control with you. For purposes of this definition, "control" means
+(i) the power, direct or indirect, to cause the direction or management of such
+entity, whether by contract or otherwise, or (ii) ownership of fifty percent
+(50%) or more of the outstanding shares, or (iii) beneficial ownership of such
+entity.
+
+15) Right to Use. You may use the Original Work in all ways not otherwise
+restricted or conditioned by this License or by law, and Licensor promises not
+to interfere with or be responsible for such uses by You.
+
+This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved.
+Permission is hereby granted to copy and distribute this license without
+modification. This license may not be modified without the express written
+permission of its copyright owner.
+
+
+--
+END OF ACADEMIC FREE LICENSE. The following is intended to describe the
+essential differences between the Academic Free License (AFL) version 1.0 and
+other open source licenses:
+
+The Academic Free License is similar to the BSD, MIT, UoI/NCSA and Apache
+licenses in many respects but it is intended to solve a few problems with those
+licenses.
+
+* The AFL is written so as to make it clear what software is being
+licensed (by the inclusion of a statement following the copyright notice in the
+software). This way, the license functions better than a template license. The
+BSD, MIT and UoI/NCSA licenses apply to unidentified software.
+
+* The AFL contains a complete copyright grant to the software. The BSD
+and Apache licenses are vague and incomplete in that respect.
+
+* The AFL contains a complete patent grant to the software. The BSD, MIT,
+UoI/NCSA and Apache licenses rely on an implied patent license and contain no
+explicit patent grant.
+
+* The AFL makes it clear that no trademark rights are granted to the
+licensor's trademarks. The Apache license contains such a provision, but the
+BSD, MIT and UoI/NCSA licenses do not.
+
+* The AFL includes the warranty by the licensor that it either owns the
+copyright or that it is distributing the software under a license. None of the
+other licenses contain that warranty. All other warranties are disclaimed, as
+is the case for the other licenses.
+
+* The AFL is itself copyrighted (with the right granted to copy and distribute
+without modification). This ensures that the owner of the copyright to the
+license will control changes. The Apache license contains a copyright notice,
+but the BSD, MIT and UoI/NCSA licenses do not.
+
+--
+START OF GNU LIBRARY GENERAL PUBLIC LICENSE
+--
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/federation/sssd/src/main/resources/en_US.properties b/federation/sssd/src/main/resources/en_US.properties
new file mode 100644
index 0000000..31bc06c
--- /dev/null
+++ b/federation/sssd/src/main/resources/en_US.properties
@@ -0,0 +1,82 @@
+#java-format
+notBasicType=" is not a basic type"
+notObjectProvidedByProcess=" is not an object provided by this process."
+arrayOutOfBounds="Array index out of bounds, paofs={0}, pabuf.length={1}, buf.length={2}."
+arrayMustNotExceed="Arrays must not exceed "
+asyncCallNoReply="Async call has not had a reply"
+busAddressBlank="Bus address is blank"
+busAddressInvalid="Bus address is invalid: "
+cannotWrapNullInVariant="Can't wrap Null in a Variant"
+cannotWrapMultiValuedInVariant="Can't wrap a multi-valued type in a Variant: "
+cannotWrapNoTypesInVariant="Can't wrap multiple or no types in a Variant: "
+cannotWrapUnqualifiedVariant="Can't wrap {0} in an unqualified Variant ({1})."
+cannotResolveSessionBusAddress="Cannot Resolve Session Bus Address"
+cannotWatchSignalsWellKnownBussName="Cannot watch for signals based on well known bus name as source, only unique names."
+cannotCreateClassFromSignal="Could not create class from signal "
+interfaceToCastNotFound="Could not find an interface to cast to"
+interfaceNotAllowedOutsidePackage="DBusInterfaces cannot be declared outside a package"
+interfaceMustBeDefinedPackage="DBusInterfaces must be defined in a package."
+disconnected="Disconnected"
+errorExecutingMethod="Error Executing Method {0}.{1}: {2}"
+errorDeserializingMessage="Error deserializing message: number of parameters didn't match receiving signature"
+nonExportableParameterizedType="Exporting non-exportable parameterized type "
+nonExportableType "Exporting non-exportable type "
+errorAddSignalParameters="Failed to add signal parameters: "
+errorAuth="Failed to auth"
+connectionFailure="Failed to connect to bus "
+contructDBusTypeFailure="Failed to construct D-Bus type: "
+constructOutgoingMethodCallFailure="Failed to construct outgoing method call: "
+createProxyExportFailure="Failed to create proxy object for {0} exported by {1}. Reason: {2}"
+createProxyFailure="Failed to create proxy object for {0}; reason: {1}."
+parseDBusTypeSignatureFailure="Failed to parse DBus type signature: "
+parseDBusSignatureFailure="Failed to parse DBus type signature: {0} ({1})."
+dbusRegistrationFailure="Failed to register bus name"
+deSerializationFailure="Failure in de-serializing message: "
+introspectInterfaceExceedCharacters="Introspected interface name exceeds 255 characters. Cannot export objects of type "
+introspectMethodExceedCharacters="Introspected method name exceeds 255 characters. Cannot export objects with method "
+introspectSignalExceedCharacters="Introspected signal name exceeds 255 characters. Cannot export objects with signals of type "
+invalidBusType="Invalid Bus Type: "
+invalidCommand="Invalid Command "
+invalidBusName="Invalid bus name"
+nullBusName="Invalid bus name: null"
+invalidObjectPath="Invalid object path: "
+nullObjectPath="Invalid object path: null"
+invalidTypeMatchRule="Invalid type for match rule: "
+mapParameters="Map must have 2 parameters"
+messageFailedSend="Message Failed to Send: "
+messageTypeUnsupported="Message type {0} unsupported"
+multiValuedArrayNotPermitted="Multi-valued array types not permitted"
+missingObjectPath="Must Specify an Object Path"
+missingDestinationPathFunction="Must specify destination, path and function name to MethodCalls."
+missingErrorName="Must specify error name to Errors."
+missingPathInterfaceSignal="Must specify object path, interface and signal name to Signals."
+notReplyWithSpecifiedTime="No reply within specified time"
+missingTransport="No transport present"
+notDBusInterface="Not A DBus Interface"
+notDBusSignal="Not A DBus Signal"
+convertionTypeNotExpected="Not An Expected Convertion type from {0} to {1}"
+notConnected="Not Connected"
+notPrimitiveType="Not a primitive type"
+invalidDBusCode="Not a valid D-Bus type code: "
+invalidWrapperType="Not a wrapper type"
+invalidArray="Not an array"
+objectNotExportedNoRemoteSpecified="Not an object exported by this connection and no remote specified"
+notEnoughElementsToCreateCustomObject="Not enough elements to create custom object from serialized data ({0} < {1})."
+objectAlreadyExported="Object already exported"
+arraySentAsNonPrimitive="Primative array being sent as non-primative array."
+protocolVersionUnsupported="Protocol version {0} is unsupported"
+cannotIntrospectReturnType="Return type of Object[] cannot be introspected properly"
+mustImplementDeserializeMethod="Serializable classes must implement a deserialize method"
+mustSerializeNativeDBusTypes="Serializable classes must serialize to native DBus types"
+signalsMustBeMemberOfClass="Signals must be declared as a member of a class implementing DBusInterface which is the member of a package."
+spuriousReply="Spurious reply. No message with the given serial id was awaiting a reply."
+utf8NotSupported="System does not support UTF-8 encoding"
+methodDoesNotExist="The method `{0}.{1}' does not exist on this object."
+unconvertableType="Trying to marshall to unconvertable type (from {0} to {1})."
+transportReturnedEOF="Underlying transport returned EOF"
+waitingFor="Waiting for: "
+invalidReturnType="Wrong return type (failed to de-serialize correct types: {0} )"
+voidReturnType="Wrong return type (got void, expected a value)"
+tupleReturnType="Wrong return type (not expecting Tuple)"
+unknownAddress="unknown address type "
+isNotBetween="{0} is not between {1} and {2}."
diff --git a/federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory b/federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
new file mode 100644
index 0000000..d06ece1
--- /dev/null
+++ b/federation/sssd/src/main/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.federation.sssd.SSSDFederationProviderFactory
\ No newline at end of file
diff --git a/federation/sssd/src/test/java/cx/ath/matthew/unix/testclient.java b/federation/sssd/src/test/java/cx/ath/matthew/unix/testclient.java
new file mode 100644
index 0000000..2acef18
--- /dev/null
+++ b/federation/sssd/src/test/java/cx/ath/matthew/unix/testclient.java
@@ -0,0 +1,49 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2005
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+
+package cx.ath.matthew.unix;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+public class testclient {
+ public static void main(String args[]) throws IOException {
+ UnixSocket s = new UnixSocket(new UnixSocketAddress("testsock", true));
+ OutputStream os = s.getOutputStream();
+ PrintWriter o = new PrintWriter(os);
+ BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
+ String l;
+ while (null != (l = r.readLine())) {
+ byte[] buf = (l + "\n").getBytes();
+ os.write(buf, 0, buf.length);
+ }
+ s.close();
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_client.java b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_client.java
new file mode 100644
index 0000000..b71033d
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_client.java
@@ -0,0 +1,511 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.types.DBusMapType;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+public class cross_test_client implements DBus.Binding.TestClient, DBusSigHandler<DBus.Binding.TestSignals.Triggered> {
+ private DBusConnection conn;
+ private static Set<String> passed = new TreeSet<String>();
+ private static Map<String, List<String>> failed = new HashMap<String, List<String>>();
+ private static cross_test_client ctc;
+
+ static {
+ List<String> l = new Vector<String>();
+ l.add("Signal never arrived");
+ failed.put("org.freedesktop.DBus.Binding.TestSignals.Triggered", l);
+ l = new Vector<String>();
+ l.add("Method never called");
+ failed.put("org.freedesktop.DBus.Binding.TestClient.Response", l);
+ }
+
+ public cross_test_client(DBusConnection conn) {
+ this.conn = conn;
+ }
+
+ public boolean isRemote() {
+ return false;
+ }
+
+ public void handle(DBus.Binding.TestSignals.Triggered t) {
+ failed.remove("org.freedesktop.DBus.Binding.TestSignals.Triggered");
+ if (new UInt64(21389479283L).equals(t.a) && "/Test".equals(t.getPath()))
+ pass("org.freedesktop.DBus.Binding.TestSignals.Triggered");
+ else if (!new UInt64(21389479283L).equals(t.a))
+ fail("org.freedesktop.DBus.Binding.TestSignals.Triggered", "Incorrect signal content; expected 21389479283 got " + t.a);
+ else if (!"/Test".equals(t.getPath()))
+ fail("org.freedesktop.DBus.Binding.TestSignals.Triggered", "Incorrect signal source object; expected /Test got " + t.getPath());
+ }
+
+ public void Response(UInt16 a, double b) {
+ failed.remove("org.freedesktop.DBus.Binding.TestClient.Response");
+ if (a.equals(new UInt16(15)) && (b == 12.5))
+ pass("org.freedesktop.DBus.Binding.TestClient.Response");
+ else
+ fail("org.freedesktop.DBus.Binding.TestClient.Response", "Incorrect parameters; expected 15, 12.5 got " + a + ", " + b);
+ }
+
+ public static void pass(String test) {
+ passed.add(test.replaceAll("[$]", ""));
+ }
+
+ public static void fail(String test, String reason) {
+ test = test.replaceAll("[$]", "");
+ List<String> reasons = failed.get(test);
+ if (null == reasons) {
+ reasons = new Vector<String>();
+ failed.put(test, reasons);
+ }
+ reasons.add(reason);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void test(Class<? extends DBusInterface> iface, Object proxy, String method, Object rv, Object... parameters) {
+ try {
+ Method[] ms = iface.getMethods();
+ Method m = null;
+ for (Method t : ms) {
+ if (t.getName().equals(method))
+ m = t;
+ }
+ Object o = m.invoke(proxy, parameters);
+
+ String msg = "Incorrect return value; sent ( ";
+ if (null != parameters)
+ for (Object po : parameters)
+ if (null != po)
+ msg += collapseArray(po) + ",";
+ msg = msg.replaceAll(".$", ");");
+ msg += " expected " + collapseArray(rv) + " got " + collapseArray(o);
+
+ if (null != rv && rv.getClass().isArray()) {
+ compareArray(iface.getName() + "" + method, rv, o);
+ } else if (rv instanceof Map) {
+ if (o instanceof Map) {
+ Map<Object, Object> a = (Map<Object, Object>) o;
+ Map<Object, Object> b = (Map<Object, Object>) rv;
+ if (a.keySet().size() != b.keySet().size()) {
+ fail(iface.getName() + "" + method, msg);
+ } else for (Object k : a.keySet())
+ if (a.get(k) instanceof List) {
+ if (b.get(k) instanceof List)
+ if (setCompareLists((List<Object>) a.get(k), (List<Object>) b.get(k)))
+ ;
+ else
+ fail(iface.getName() + "" + method, msg);
+ else
+ fail(iface.getName() + "" + method, msg);
+ } else if (!a.get(k).equals(b.get(k))) {
+ fail(iface.getName() + "" + method, msg);
+ return;
+ }
+ pass(iface.getName() + "" + method);
+ } else
+ fail(iface.getName() + "" + method, msg);
+ } else {
+ if (o == rv || (o != null && o.equals(rv)))
+ pass(iface.getName() + "" + method);
+ else
+ fail(iface.getName() + "" + method, msg);
+ }
+ } catch (DBusExecutionException DBEe) {
+ DBEe.printStackTrace();
+ fail(iface.getName() + "" + method, "Error occurred during execution: " + DBEe.getClass().getName() + " " + DBEe.getMessage());
+ } catch (InvocationTargetException ITe) {
+ ITe.printStackTrace();
+ fail(iface.getName() + "" + method, "Error occurred during execution: " + ITe.getCause().getClass().getName() + " " + ITe.getCause().getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(iface.getName() + "" + method, "Error occurred during execution: " + e.getClass().getName() + " " + e.getMessage());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String collapseArray(Object array) {
+ if (null == array) return "null";
+ if (array.getClass().isArray()) {
+ String s = "{ ";
+ for (int i = 0; i < Array.getLength(array); i++)
+ s += collapseArray(Array.get(array, i)) + ",";
+ s = s.replaceAll(".$", " }");
+ return s;
+ } else if (array instanceof List) {
+ String s = "{ ";
+ for (Object o : (List<Object>) array)
+ s += collapseArray(o) + ",";
+ s = s.replaceAll(".$", " }");
+ return s;
+ } else if (array instanceof Map) {
+ String s = "{ ";
+ for (Object o : ((Map<Object, Object>) array).keySet())
+ s += collapseArray(o) + " => " + collapseArray(((Map<Object, Object>) array).get(o)) + ",";
+ s = s.replaceAll(".$", " }");
+ return s;
+ } else return array.toString();
+ }
+
+ public static <T> boolean setCompareLists(List<T> a, List<T> b) {
+ if (a.size() != b.size()) return false;
+ for (Object v : a)
+ if (!b.contains(v)) return false;
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static List<Variant<Object>> PrimitizeRecurse(Object a, Type t) {
+ List<Variant<Object>> vs = new Vector<Variant<Object>>();
+ if (t instanceof ParameterizedType) {
+ Class<Object> c = (Class<Object>) ((ParameterizedType) t).getRawType();
+ if (List.class.isAssignableFrom(c)) {
+ Object os;
+ if (a instanceof List)
+ os = ((List<Object>) a).toArray();
+ else
+ os = a;
+ Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
+ for (int i = 0; i < Array.getLength(os); i++)
+ vs.addAll(PrimitizeRecurse(Array.get(os, i), ts[0]));
+ } else if (Map.class.isAssignableFrom(c)) {
+ Object[] os = ((Map) a).keySet().toArray();
+ Object[] ks = ((Map) a).values().toArray();
+ Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
+ for (int i = 0; i < ks.length; i++)
+ vs.addAll(PrimitizeRecurse(ks[i], ts[0]));
+ for (int i = 0; i < os.length; i++)
+ vs.addAll(PrimitizeRecurse(os[i], ts[1]));
+ } else if (Struct.class.isAssignableFrom(c)) {
+ Object[] os = ((Struct) a).getParameters();
+ Type[] ts = ((ParameterizedType) t).getActualTypeArguments();
+ for (int i = 0; i < os.length; i++)
+ vs.addAll(PrimitizeRecurse(os[i], ts[i]));
+
+ } else if (Variant.class.isAssignableFrom(c)) {
+ vs.addAll(PrimitizeRecurse(((Variant) a).getValue(), ((Variant) a).getType()));
+ }
+ } else if (Variant.class.isAssignableFrom((Class) t))
+ vs.addAll(PrimitizeRecurse(((Variant) a).getValue(), ((Variant) a).getType()));
+ else if (t instanceof Class && ((Class) t).isArray()) {
+ Type t2 = ((Class) t).getComponentType();
+ for (int i = 0; i < Array.getLength(a); i++)
+ vs.addAll(PrimitizeRecurse(Array.get(a, i), t2));
+ } else vs.add(new Variant(a));
+
+ return vs;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static List<Variant<Object>> Primitize(Variant<Object> a) {
+ return PrimitizeRecurse(a.getValue(), a.getType());
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void primitizeTest(DBus.Binding.Tests tests, Object input) {
+ Variant<Object> in = new Variant<Object>(input);
+ List<Variant<Object>> vs = Primitize(in);
+ List<Variant<Object>> res;
+
+ try {
+
+ res = tests.Primitize(in);
+ if (setCompareLists(res, vs))
+ pass("org.freedesktop.DBus.Binding.Tests.Primitize");
+ else
+ fail("org.freedesktop.DBus.Binding.Tests.Primitize", "Wrong Return Value; expected " + collapseArray(vs) + " got " + collapseArray(res));
+
+ } catch (Exception e) {
+ if (Debug.debug) Debug.print(e);
+ fail("org.freedesktop.DBus.Binding.Tests.Primitize", "Exception occurred during test: (" + e.getClass().getName() + ") " + e.getMessage());
+ }
+ }
+
+ public static void doTests(DBus.Peer peer, DBus.Introspectable intro, DBus.Introspectable rootintro, DBus.Binding.Tests tests, DBus.Binding.SingleTests singletests) {
+ Random r = new Random();
+ int i;
+ test(DBus.Peer.class, peer, "Ping", null);
+
+ try {
+ if (intro.Introspect().startsWith("<!DOCTYPE")) pass("org.freedesktop.DBus.Introspectable.Introspect");
+ else
+ fail("org.freedesktop.DBus.Introspectable.Introspect", "Didn't get valid xml data back when introspecting /Test");
+ } catch (DBusExecutionException DBEe) {
+ if (Debug.debug) Debug.print(DBEe);
+ fail("org.freedesktop.DBus.Introspectable.Introspect", "Got exception during introspection on /Test (" + DBEe.getClass().getName() + "): " + DBEe.getMessage());
+ }
+
+ try {
+ if (rootintro.Introspect().startsWith("<!DOCTYPE")) pass("org.freedesktop.DBus.Introspectable.Introspect");
+ else
+ fail("org.freedesktop.DBus.Introspectable.Introspect", "Didn't get valid xml data back when introspecting /");
+ } catch (DBusExecutionException DBEe) {
+ if (Debug.debug) Debug.print(DBEe);
+ fail("org.freedesktop.DBus.Introspectable.Introspect", "Got exception during introspection on / (" + DBEe.getClass().getName() + "): " + DBEe.getMessage());
+ }
+
+ test(DBus.Binding.Tests.class, tests, "Identity", new Variant<Integer>(new Integer(1)), new Variant<Integer>(new Integer(1)));
+ test(DBus.Binding.Tests.class, tests, "Identity", new Variant<String>("Hello"), new Variant<String>("Hello"));
+
+ test(DBus.Binding.Tests.class, tests, "IdentityBool", false, false);
+ test(DBus.Binding.Tests.class, tests, "IdentityBool", true, true);
+
+ test(DBus.Binding.Tests.class, tests, "Invert", false, true);
+ test(DBus.Binding.Tests.class, tests, "Invert", true, false);
+
+ test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) 0, (byte) 0);
+ test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) 1, (byte) 1);
+ test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) -1, (byte) -1);
+ test(DBus.Binding.Tests.class, tests, "IdentityByte", Byte.MAX_VALUE, Byte.MAX_VALUE);
+ test(DBus.Binding.Tests.class, tests, "IdentityByte", Byte.MIN_VALUE, Byte.MIN_VALUE);
+ i = r.nextInt();
+ test(DBus.Binding.Tests.class, tests, "IdentityByte", (byte) i, (byte) i);
+
+ test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) 0, (short) 0);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) 1, (short) 1);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) -1, (short) -1);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt16", Short.MAX_VALUE, Short.MAX_VALUE);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt16", Short.MIN_VALUE, Short.MIN_VALUE);
+ i = r.nextInt();
+ test(DBus.Binding.Tests.class, tests, "IdentityInt16", (short) i, (short) i);
+
+ test(DBus.Binding.Tests.class, tests, "IdentityInt32", 0, 0);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt32", 1, 1);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt32", -1, -1);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt32", Integer.MAX_VALUE, Integer.MAX_VALUE);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt32", Integer.MIN_VALUE, Integer.MIN_VALUE);
+ i = r.nextInt();
+ test(DBus.Binding.Tests.class, tests, "IdentityInt32", i, i);
+
+
+ test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) 0, (long) 0);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) 1, (long) 1);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) -1, (long) -1);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt64", Long.MAX_VALUE, Long.MAX_VALUE);
+ test(DBus.Binding.Tests.class, tests, "IdentityInt64", Long.MIN_VALUE, Long.MIN_VALUE);
+ i = r.nextInt();
+ test(DBus.Binding.Tests.class, tests, "IdentityInt64", (long) i, (long) i);
+
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(0), new UInt16(0));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(1), new UInt16(1));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(UInt16.MAX_VALUE), new UInt16(UInt16.MAX_VALUE));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(UInt16.MIN_VALUE), new UInt16(UInt16.MIN_VALUE));
+ i = r.nextInt();
+ i = i > 0 ? i : -i;
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt16", new UInt16(i % UInt16.MAX_VALUE), new UInt16(i % UInt16.MAX_VALUE));
+
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(0), new UInt32(0));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(1), new UInt32(1));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(UInt32.MAX_VALUE), new UInt32(UInt32.MAX_VALUE));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(UInt32.MIN_VALUE), new UInt32(UInt32.MIN_VALUE));
+ i = r.nextInt();
+ i = i > 0 ? i : -i;
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt32", new UInt32(i % UInt32.MAX_VALUE), new UInt32(i % UInt32.MAX_VALUE));
+
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(0), new UInt64(0));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(1), new UInt64(1));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MAX_LONG_VALUE), new UInt64(UInt64.MAX_LONG_VALUE));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MAX_BIG_VALUE), new UInt64(UInt64.MAX_BIG_VALUE));
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(UInt64.MIN_VALUE), new UInt64(UInt64.MIN_VALUE));
+ i = r.nextInt();
+ i = i > 0 ? i : -i;
+ test(DBus.Binding.Tests.class, tests, "IdentityUInt64", new UInt64(i % UInt64.MAX_LONG_VALUE), new UInt64(i % UInt64.MAX_LONG_VALUE));
+
+ test(DBus.Binding.Tests.class, tests, "IdentityDouble", 0.0, 0.0);
+ test(DBus.Binding.Tests.class, tests, "IdentityDouble", 1.0, 1.0);
+ test(DBus.Binding.Tests.class, tests, "IdentityDouble", -1.0, -1.0);
+ test(DBus.Binding.Tests.class, tests, "IdentityDouble", Double.MAX_VALUE, Double.MAX_VALUE);
+ test(DBus.Binding.Tests.class, tests, "IdentityDouble", Double.MIN_VALUE, Double.MIN_VALUE);
+ i = r.nextInt();
+ test(DBus.Binding.Tests.class, tests, "IdentityDouble", (double) i, (double) i);
+
+ test(DBus.Binding.Tests.class, tests, "IdentityString", "", "");
+ test(DBus.Binding.Tests.class, tests, "IdentityString", "The Quick Brown Fox Jumped Over The Lazy Dog", "The Quick Brown Fox Jumped Over The Lazy Dog");
+ test(DBus.Binding.Tests.class, tests, "IdentityString", "ひらがなゲーム - かなぶん", "ひらがなゲーム - かなぶん");
+
+ testArray(DBus.Binding.Tests.class, tests, "IdentityBoolArray", Boolean.TYPE, null);
+ testArray(DBus.Binding.Tests.class, tests, "IdentityByteArray", Byte.TYPE, null);
+ testArray(DBus.Binding.Tests.class, tests, "IdentityInt16Array", Short.TYPE, null);
+ testArray(DBus.Binding.Tests.class, tests, "IdentityInt32Array", Integer.TYPE, null);
+ testArray(DBus.Binding.Tests.class, tests, "IdentityInt64Array", Long.TYPE, null);
+ testArray(DBus.Binding.Tests.class, tests, "IdentityDoubleArray", Double.TYPE, null);
+
+ testArray(DBus.Binding.Tests.class, tests, "IdentityArray", Variant.class, new Variant<String>("aoeu"));
+ testArray(DBus.Binding.Tests.class, tests, "IdentityUInt16Array", UInt16.class, new UInt16(12));
+ testArray(DBus.Binding.Tests.class, tests, "IdentityUInt32Array", UInt32.class, new UInt32(190));
+ testArray(DBus.Binding.Tests.class, tests, "IdentityUInt64Array", UInt64.class, new UInt64(103948));
+ testArray(DBus.Binding.Tests.class, tests, "IdentityStringArray", String.class, "asdf");
+
+ int[] is = new int[0];
+ test(DBus.Binding.Tests.class, tests, "Sum", 0L, is);
+ r = new Random();
+ int len = (r.nextInt() % 100) + 15;
+ len = (len < 0 ? -len : len) + 15;
+ is = new int[len];
+ long result = 0;
+ for (i = 0; i < len; i++) {
+ is[i] = r.nextInt();
+ result += is[i];
+ }
+ test(DBus.Binding.Tests.class, tests, "Sum", result, is);
+
+ byte[] bs = new byte[0];
+ test(DBus.Binding.SingleTests.class, singletests, "Sum", new UInt32(0), bs);
+ len = (r.nextInt() % 100);
+ len = (len < 0 ? -len : len) + 15;
+ bs = new byte[len];
+ int res = 0;
+ for (i = 0; i < len; i++) {
+ bs[i] = (byte) r.nextInt();
+ res += (bs[i] < 0 ? bs[i] + 256 : bs[i]);
+ }
+ test(DBus.Binding.SingleTests.class, singletests, "Sum", new UInt32(res % (UInt32.MAX_VALUE + 1)), bs);
+
+ test(DBus.Binding.Tests.class, tests, "DeStruct", new DBus.Binding.Triplet<String, UInt32, Short>("hi", new UInt32(12), new Short((short) 99)), new DBus.Binding.TestStruct("hi", new UInt32(12), new Short((short) 99)));
+
+ Map<String, String> in = new HashMap<String, String>();
+ Map<String, List<String>> out = new HashMap<String, List<String>>();
+ test(DBus.Binding.Tests.class, tests, "InvertMapping", out, in);
+
+ in.put("hi", "there");
+ in.put("to", "there");
+ in.put("from", "here");
+ in.put("in", "out");
+ List<String> l = new Vector<String>();
+ l.add("hi");
+ l.add("to");
+ out.put("there", l);
+ l = new Vector<String>();
+ l.add("from");
+ out.put("here", l);
+ l = new Vector<String>();
+ l.add("in");
+ out.put("out", l);
+ test(DBus.Binding.Tests.class, tests, "InvertMapping", out, in);
+
+ primitizeTest(tests, new Integer(1));
+ primitizeTest(tests,
+ new Variant<Variant<Variant<Variant<String>>>>(
+ new Variant<Variant<Variant<String>>>(
+ new Variant<Variant<String>>(
+ new Variant<String>("Hi")))));
+ primitizeTest(tests, new Variant<Map<String, String>>(in, new DBusMapType(String.class, String.class)));
+
+ test(DBus.Binding.Tests.class, tests, "Trigger", null, "/Test", new UInt64(21389479283L));
+
+ try {
+ ctc.conn.sendSignal(new DBus.Binding.TestClient.Trigger("/Test", new UInt16(15), 12.5));
+ } catch (DBusException DBe) {
+ if (Debug.debug) Debug.print(DBe);
+ throw new DBusExecutionException(DBe.getMessage());
+ }
+
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException Ie) {
+ }
+
+ test(DBus.Binding.Tests.class, tests, "Exit", null);
+ }
+
+ public static void testArray(Class<? extends DBusInterface> iface, Object proxy, String method, Class<? extends Object> arrayType, Object content) {
+ Object array = Array.newInstance(arrayType, 0);
+ test(iface, proxy, method, array, array);
+ Random r = new Random();
+ int l = (r.nextInt() % 100);
+ array = Array.newInstance(arrayType, (l < 0 ? -l : l) + 15);
+ if (null != content)
+ Arrays.fill((Object[]) array, content);
+ test(iface, proxy, method, array, array);
+ }
+
+ public static void compareArray(String test, Object a, Object b) {
+ if (!a.getClass().equals(b.getClass())) {
+ fail(test, "Incorrect return type; expected " + a.getClass() + " got " + b.getClass());
+ return;
+ }
+ boolean pass = false;
+
+ if (a instanceof Object[])
+ pass = Arrays.equals((Object[]) a, (Object[]) b);
+ else if (a instanceof byte[])
+ pass = Arrays.equals((byte[]) a, (byte[]) b);
+ else if (a instanceof boolean[])
+ pass = Arrays.equals((boolean[]) a, (boolean[]) b);
+ else if (a instanceof int[])
+ pass = Arrays.equals((int[]) a, (int[]) b);
+ else if (a instanceof short[])
+ pass = Arrays.equals((short[]) a, (short[]) b);
+ else if (a instanceof long[])
+ pass = Arrays.equals((long[]) a, (long[]) b);
+ else if (a instanceof double[])
+ pass = Arrays.equals((double[]) a, (double[]) b);
+
+ if (pass)
+ pass(test);
+ else {
+ String s = "Incorrect return value; expected ";
+ s += collapseArray(a);
+ s += " got ";
+ s += collapseArray(b);
+ fail(test, s);
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ /* init */
+ DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+ ctc = new cross_test_client(conn);
+ conn.exportObject("/Test", ctc);
+ conn.addSigHandler(DBus.Binding.TestSignals.Triggered.class, ctc);
+ DBus.Binding.Tests tests = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Binding.Tests.class);
+ DBus.Binding.SingleTests singletests = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Binding.SingleTests.class);
+ DBus.Peer peer = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Peer.class);
+ DBus.Introspectable intro = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/Test", DBus.Introspectable.class);
+
+ DBus.Introspectable rootintro = conn.getRemoteObject("org.freedesktop.DBus.Binding.TestServer", "/", DBus.Introspectable.class);
+
+ doTests(peer, intro, rootintro, tests, singletests);
+
+ /* report results */
+ for (String s : passed)
+ System.out.println(s + " pass");
+ int i = 1;
+ for (String s : failed.keySet())
+ for (String r : failed.get(s)) {
+ System.out.println(s + " fail " + i);
+ System.out.println("report " + i + ": " + r);
+ i++;
+ }
+
+ conn.disconnect();
+ } catch (DBusException DBe) {
+ DBe.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_server.java b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_server.java
new file mode 100644
index 0000000..61bba4a
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/cross_test_server.java
@@ -0,0 +1,342 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Vector;
+
+public class cross_test_server implements DBus.Binding.Tests, DBus.Binding.SingleTests, DBusSigHandler<DBus.Binding.TestClient.Trigger> {
+ private DBusConnection conn;
+ boolean run = true;
+ private Set<String> done = new TreeSet<String>();
+ private Set<String> notdone = new TreeSet<String>();
+
+ {
+ notdone.add("org.freedesktop.DBus.Binding.Tests.Identity");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityByte");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityBool");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityDouble");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityString");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityArray");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityByteArray");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityBoolArray");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16Array");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16Array");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32Array");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32Array");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64Array");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64Array");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityDoubleArray");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.IdentityStringArray");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.Sum");
+ notdone.add("org.freedesktop.DBus.Binding.SingleTests.Sum");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.InvertMapping");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.DeStruct");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.Primitize");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.Invert");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.Trigger");
+ notdone.add("org.freedesktop.DBus.Binding.Tests.Exit");
+ notdone.add("org.freedesktop.DBus.Binding.TestClient.Trigger");
+ }
+
+ public cross_test_server(DBusConnection conn) {
+ this.conn = conn;
+ }
+
+ public boolean isRemote() {
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ @DBus.Description("Returns whatever it is passed")
+ public <T> Variant<T> Identity(Variant<T> input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.Identity");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.Identity");
+ return new Variant(input.getValue());
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public byte IdentityByte(byte input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityByte");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityByte");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public boolean IdentityBool(boolean input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityBool");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityBool");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public short IdentityInt16(short input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt16");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public UInt16 IdentityUInt16(UInt16 input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt16");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public int IdentityInt32(int input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt32");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public UInt32 IdentityUInt32(UInt32 input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt32");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public long IdentityInt64(long input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt64");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public UInt64 IdentityUInt64(UInt64 input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt64");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public double IdentityDouble(double input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityDouble");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityDouble");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public String IdentityString(String input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityString");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityString");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public <T> Variant<T>[] IdentityArray(Variant<T>[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityArray");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityArray");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public byte[] IdentityByteArray(byte[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityByteArray");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityByteArray");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public boolean[] IdentityBoolArray(boolean[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityBoolArray");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityBoolArray");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public short[] IdentityInt16Array(short[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt16Array");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt16Array");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public UInt16[] IdentityUInt16Array(UInt16[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt16Array");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt16Array");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public int[] IdentityInt32Array(int[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt32Array");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt32Array");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public UInt32[] IdentityUInt32Array(UInt32[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt32Array");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt32Array");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public long[] IdentityInt64Array(long[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityInt64Array");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityInt64Array");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public UInt64[] IdentityUInt64Array(UInt64[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityUInt64Array");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityUInt64Array");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public double[] IdentityDoubleArray(double[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityDoubleArray");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityDoubleArray");
+ return input;
+ }
+
+ @DBus.Description("Returns whatever it is passed")
+ public String[] IdentityStringArray(String[] input) {
+ done.add("org.freedesktop.DBus.Binding.Tests.IdentityStringArray");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.IdentityStringArray");
+ return input;
+ }
+
+ @DBus.Description("Returns the sum of the values in the input list")
+ public long Sum(int[] a) {
+ done.add("org.freedesktop.DBus.Binding.Tests.Sum");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.Sum");
+ long sum = 0;
+ for (int b : a) sum += b;
+ return sum;
+ }
+
+ @DBus.Description("Returns the sum of the values in the input list")
+ public UInt32 Sum(byte[] a) {
+ done.add("org.freedesktop.DBus.Binding.SingleTests.Sum");
+ notdone.remove("org.freedesktop.DBus.Binding.SingleTests.Sum");
+ int sum = 0;
+ for (byte b : a) sum += (b < 0 ? b + 256 : b);
+ return new UInt32(sum % (UInt32.MAX_VALUE + 1));
+ }
+
+ @DBus.Description("Given a map of A => B, should return a map of B => a list of all the As which mapped to B")
+ public Map<String, List<String>> InvertMapping(Map<String, String> a) {
+ done.add("org.freedesktop.DBus.Binding.Tests.InvertMapping");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.InvertMapping");
+ HashMap<String, List<String>> m = new HashMap<String, List<String>>();
+ for (String s : a.keySet()) {
+ String b = a.get(s);
+ List<String> l = m.get(b);
+ if (null == l) {
+ l = new Vector<String>();
+ m.put(b, l);
+ }
+ l.add(s);
+ }
+ return m;
+ }
+
+ @DBus.Description("This method returns the contents of a struct as separate values")
+ public DBus.Binding.Triplet<String, UInt32, Short> DeStruct(DBus.Binding.TestStruct a) {
+ done.add("org.freedesktop.DBus.Binding.Tests.DeStruct");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.DeStruct");
+ return new DBus.Binding.Triplet<String, UInt32, Short>(a.a, a.b, a.c);
+ }
+
+ @DBus.Description("Given any compound type as a variant, return all the primitive types recursively contained within as an array of variants")
+ @SuppressWarnings("unchecked")
+ public List<Variant<Object>> Primitize(Variant<Object> a) {
+ done.add("org.freedesktop.DBus.Binding.Tests.Primitize");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.Primitize");
+ return cross_test_client.PrimitizeRecurse(a.getValue(), a.getType());
+ }
+
+ @DBus.Description("inverts it's input")
+ public boolean Invert(boolean a) {
+ done.add("org.freedesktop.DBus.Binding.Tests.Invert");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.Invert");
+ return !a;
+ }
+
+ @DBus.Description("triggers sending of a signal from the supplied object with the given parameter")
+ public void Trigger(String a, UInt64 b) {
+ done.add("org.freedesktop.DBus.Binding.Tests.Trigger");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.Trigger");
+ try {
+ conn.sendSignal(new DBus.Binding.TestSignals.Triggered(a, b));
+ } catch (DBusException DBe) {
+ throw new DBusExecutionException(DBe.getMessage());
+ }
+ }
+
+ public void Exit() {
+ done.add("org.freedesktop.DBus.Binding.Tests.Exit");
+ notdone.remove("org.freedesktop.DBus.Binding.Tests.Exit");
+ run = false;
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+
+ public void handle(DBus.Binding.TestClient.Trigger t) {
+ done.add("org.freedesktop.DBus.Binding.TestClient.Trigger");
+ notdone.remove("org.freedesktop.DBus.Binding.TestClient.Trigger");
+ try {
+ DBus.Binding.TestClient cb = conn.getRemoteObject(t.getSource(), "/Test", DBus.Binding.TestClient.class);
+ cb.Response(t.a, t.b);
+ } catch (DBusException DBe) {
+ throw new DBusExecutionException(DBe.getMessage());
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+ conn.requestBusName("org.freedesktop.DBus.Binding.TestServer");
+ cross_test_server cts = new cross_test_server(conn);
+ conn.addSigHandler(DBus.Binding.TestClient.Trigger.class, cts);
+ conn.exportObject("/Test", cts);
+ synchronized (cts) {
+ while (cts.run) {
+ try {
+ cts.wait();
+ } catch (InterruptedException Ie) {
+ }
+ }
+ }
+ for (String s : cts.done)
+ System.out.println(s + " ok");
+ for (String s : cts.notdone)
+ System.out.println(s + " untested");
+ conn.disconnect();
+ System.exit(0);
+ } catch (DBusException DBe) {
+ DBe.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
+
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/profile.java b/federation/sssd/src/test/java/org/freedesktop/dbus/profile.java
new file mode 100644
index 0000000..e6866a7
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/profile.java
@@ -0,0 +1,378 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Introspectable;
+import org.freedesktop.DBus.Peer;
+
+import java.util.HashMap;
+import java.util.Random;
+import java.util.Vector;
+
+class ProfileHandler implements DBusSigHandler<Profiler.ProfileSignal> {
+ public int c = 0;
+
+ public void handle(Profiler.ProfileSignal s) {
+ if (0 == (c++ % profile.SIGNAL_INNER)) System.out.print("-");
+ }
+}
+
+/**
+ * Profiling tests.
+ */
+public class profile {
+ public static final int SIGNAL_INNER = 100;
+ public static final int SIGNAL_OUTER = 100;
+ public static final int PING_INNER = 100;
+ public static final int PING_OUTER = 100;
+ public static final int BYTES = 2000000;
+ public static final int INTROSPECTION_OUTER = 100;
+ public static final int INTROSPECTION_INNER = 10;
+ public static final int STRUCT_OUTER = 100;
+ public static final int STRUCT_INNER = 10;
+ public static final int LIST_OUTER = 100;
+ public static final int LIST_INNER = 10;
+ public static final int LIST_LENGTH = 100;
+ public static final int MAP_OUTER = 100;
+ public static final int MAP_INNER = 10;
+ public static final int MAP_LENGTH = 100;
+ public static final int ARRAY_OUTER = 100;
+ public static final int ARRAY_INNER = 10;
+ public static final int ARRAY_LENGTH = 1000;
+ public static final int STRING_ARRAY_OUTER = 10;
+ public static final int STRING_ARRAY_INNER = 1;
+ public static final int STRING_ARRAY_LENGTH = 20000;
+
+ public static class Log {
+ private long last;
+ private int[] deltas;
+ private int current = 0;
+
+ public Log(int size) {
+ deltas = new int[size];
+ }
+
+ public void start() {
+ last = System.currentTimeMillis();
+ }
+
+ public void stop() {
+ deltas[current] = (int) (System.currentTimeMillis() - last);
+ current++;
+ }
+
+ public double mean() {
+ if (0 == current) return 0;
+ long sum = 0;
+ for (int i = 0; i < current; i++)
+ sum += deltas[i];
+ return sum /= current;
+ }
+
+ public long min() {
+ int m = Integer.MAX_VALUE;
+ for (int i = 0; i < current; i++)
+ if (deltas[i] < m) m = deltas[i];
+ return m;
+ }
+
+ public long max() {
+ int m = 0;
+ for (int i = 0; i < current; i++)
+ if (deltas[i] > m) m = deltas[i];
+ return m;
+ }
+
+ public double stddev() {
+ double mean = mean();
+ double sum = 0;
+ for (int i = 0; i < current; i++)
+ sum += (deltas[i] - mean) * (deltas[i] - mean);
+ return Math.sqrt(sum / (current - 1));
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ if (0 == args.length) {
+ System.out.println("You must specify a profile type.");
+ System.out.println("Syntax: profile <pings|arrays|introspect|maps|bytes|lists|structs|signals|rate|strings>");
+ System.exit(1);
+ }
+ DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+ conn.requestBusName("org.freedesktop.DBus.java.profiler");
+ if ("pings".equals(args[0])) {
+ int count = PING_INNER * PING_OUTER;
+ System.out.print("Sending " + count + " pings...");
+ Peer p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Peer.class);
+ Log l = new Log(count);
+ long t = System.currentTimeMillis();
+ for (int i = 0; i < PING_OUTER; i++) {
+ for (int j = 0; j < PING_INNER; j++) {
+ l.start();
+ p.Ping();
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ } else if ("strings".equals(args[0])) {
+ int count = STRING_ARRAY_INNER * STRING_ARRAY_OUTER;
+ System.out.print("Sending array of " + STRING_ARRAY_LENGTH + " strings " + count + " times.");
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+ String[] v = new String[STRING_ARRAY_LENGTH];
+ Random r = new Random();
+ for (int i = 0; i < STRING_ARRAY_LENGTH; i++) v[i] = "" + r.nextInt();
+ Log l = new Log(count);
+ long t = System.currentTimeMillis();
+ for (int i = 0; i < STRING_ARRAY_OUTER; i++) {
+ for (int j = 0; j < STRING_ARRAY_INNER; j++) {
+ l.start();
+ p.stringarray(v);
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ } else if ("arrays".equals(args[0])) {
+ int count = ARRAY_INNER * ARRAY_OUTER;
+ System.out.print("Sending array of " + ARRAY_LENGTH + " ints " + count + " times.");
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+ int[] v = new int[ARRAY_LENGTH];
+ Random r = new Random();
+ for (int i = 0; i < ARRAY_LENGTH; i++) v[i] = r.nextInt();
+ Log l = new Log(count);
+ long t = System.currentTimeMillis();
+ for (int i = 0; i < ARRAY_OUTER; i++) {
+ for (int j = 0; j < ARRAY_INNER; j++) {
+ l.start();
+ p.array(v);
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ } else if ("maps".equals(args[0])) {
+ int count = MAP_INNER * MAP_OUTER;
+ System.out.print("Sending map of " + MAP_LENGTH + " string=>strings " + count + " times.");
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+ HashMap<String, String> m = new HashMap<String, String>();
+ for (int i = 0; i < MAP_LENGTH; i++)
+ m.put("" + i, "hello");
+ Log l = new Log(count);
+ long t = System.currentTimeMillis();
+ for (int i = 0; i < MAP_OUTER; i++) {
+ for (int j = 0; j < MAP_INNER; j++) {
+ l.start();
+ p.map(m);
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ } else if ("lists".equals(args[0])) {
+ int count = LIST_OUTER * LIST_INNER;
+ System.out.print("Sending list of " + LIST_LENGTH + " strings " + count + " times.");
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+ Vector<String> v = new Vector<String>();
+ for (int i = 0; i < LIST_LENGTH; i++)
+ v.add("hello " + i);
+ Log l = new Log(count);
+ long t = System.currentTimeMillis();
+ for (int i = 0; i < LIST_OUTER; i++) {
+ for (int j = 0; j < LIST_INNER; j++) {
+ l.start();
+ p.list(v);
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ } else if ("structs".equals(args[0])) {
+ int count = STRUCT_OUTER * STRUCT_INNER;
+ System.out.print("Sending a struct " + count + " times.");
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+ ProfileStruct ps = new ProfileStruct("hello", new UInt32(18), 500L);
+ Log l = new Log(count);
+ long t = System.currentTimeMillis();
+ for (int i = 0; i < STRUCT_OUTER; i++) {
+ for (int j = 0; j < STRUCT_INNER; j++) {
+ l.start();
+ p.struct(ps);
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ } else if ("introspect".equals(args[0])) {
+ int count = INTROSPECTION_OUTER * INTROSPECTION_INNER;
+ System.out.print("Recieving introspection data " + count + " times.");
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Introspectable is = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Introspectable.class);
+ Log l = new Log(count);
+ long t = System.currentTimeMillis();
+ String s = null;
+ for (int i = 0; i < INTROSPECTION_OUTER; i++) {
+ for (int j = 0; j < INTROSPECTION_INNER; j++) {
+ l.start();
+ s = is.Introspect();
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ System.out.println("Introspect data: " + s);
+ } else if ("bytes".equals(args[0])) {
+ System.out.print("Sending " + BYTES + " bytes");
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+ byte[] bs = new byte[BYTES];
+ for (int i = 0; i < BYTES; i++)
+ bs[i] = (byte) i;
+ long t = System.currentTimeMillis();
+ p.bytes(bs);
+ System.out.println(" done in " + (System.currentTimeMillis() - t) + "ms.");
+ } else if ("rate".equals(args[0])) {
+ ProfilerInstance pi = new ProfilerInstance();
+ conn.exportObject("/Profiler", pi);
+ Profiler p = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Profiler.class);
+ Peer peer = conn.getRemoteObject("org.freedesktop.DBus.java.profiler", "/Profiler", Peer.class);
+ conn.changeThreadCount((byte) 1);
+
+ long start = System.currentTimeMillis();
+ int count = 0;
+ do {
+ p.Pong();
+ count++;
+ } while (count < 10000);
+ long end = System.currentTimeMillis();
+ System.out.println("No payload: " + ((count * 1000) / (end - start)) + " RT/second");
+ start = System.currentTimeMillis();
+ count = 0;
+ do {
+ p.Pong();
+ count++;
+ } while (count < 10000);
+ peer.Ping();
+ end = System.currentTimeMillis();
+ System.out.println("No payload, One way: " + ((count * 1000) / (end - start)) + " /second");
+ int len = 256;
+ while (len <= 32768) {
+ byte[] bs = new byte[len];
+ count = 0;
+ start = System.currentTimeMillis();
+ do {
+ p.bytes(bs);
+ count++;
+ } while (count < 1000);
+ end = System.currentTimeMillis();
+ long ms = end - start;
+ double cps = (count * 1000) / ms;
+ double rate = (len * cps) / (1024.0 * 1024.0);
+ System.out.println(len + " byte array) " + (count * len) + " bytes in " + ms + "ms (in " + count + " calls / " + (int) cps + " CPS): " + rate + "MB/s");
+ len <<= 1;
+ }
+ len = 256;
+ while (len <= 32768) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < len; i++) sb.append('a');
+ String s = sb.toString();
+ end = System.currentTimeMillis() + 500;
+ count = 0;
+ do {
+ p.string(s);
+ count++;
+ } while (count < 1000);
+ long ms = end - start;
+ double cps = (count * 1000) / ms;
+ double rate = (len * cps) / (1024.0 * 1024.0);
+ System.out.println(len + " string) " + (count * len) + " bytes in " + ms + "ms (in " + count + " calls / " + (int) cps + " CPS): " + rate + "MB/s");
+ len <<= 1;
+ }
+ } else if ("signals".equals(args[0])) {
+ int count = SIGNAL_OUTER * SIGNAL_INNER;
+ System.out.print("Sending " + count + " signals");
+ ProfileHandler ph = new ProfileHandler();
+ conn.addSigHandler(Profiler.ProfileSignal.class, ph);
+ Log l = new Log(count);
+ Profiler.ProfileSignal ps = new Profiler.ProfileSignal("/");
+ long t = System.currentTimeMillis();
+ for (int i = 0; i < SIGNAL_OUTER; i++) {
+ for (int j = 0; j < SIGNAL_INNER; j++) {
+ l.start();
+ conn.sendSignal(ps);
+ l.stop();
+ }
+ System.out.print("");
+ }
+ t = System.currentTimeMillis() - t;
+ System.out.println(" done.");
+ System.out.println("min/max/avg (ms): " + l.min() + "/" + l.max() + "/" + l.mean());
+ System.out.println("deviation: " + l.stddev());
+ System.out.println("Total time: " + t + "ms");
+ while (ph.c < count) try {
+ Thread.sleep(100);
+ } catch (InterruptedException Ie) {
+ }
+ ;
+ } else {
+ conn.disconnect();
+ System.out.println("Invalid profile ``" + args[0] + "''.");
+ System.out.println("Syntax: profile <pings|arrays|introspect|maps|bytes|lists|structs|signals>");
+ System.exit(1);
+ }
+ conn.disconnect();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/Profiler.java b/federation/sssd/src/test/java/org/freedesktop/dbus/Profiler.java
new file mode 100644
index 0000000..cd549d5
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/Profiler.java
@@ -0,0 +1,44 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+import java.util.Map;
+
+public interface Profiler extends DBusInterface {
+ public class ProfileSignal extends DBusSignal {
+ public ProfileSignal(String path) throws DBusException {
+ super(path);
+ }
+ }
+
+ public void array(int[] v);
+
+ public void stringarray(String[] v);
+
+ public void map(Map<String, String> m);
+
+ public void list(List<String> l);
+
+ public void bytes(byte[] b);
+
+ public void struct(ProfileStruct ps);
+
+ public void string(String s);
+
+ public void NoReply();
+
+ public void Pong();
+}
+
+
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/ProfilerInstance.java b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfilerInstance.java
new file mode 100644
index 0000000..530901f
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfilerInstance.java
@@ -0,0 +1,56 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import java.util.List;
+import java.util.Map;
+
+public class ProfilerInstance implements Profiler {
+ public boolean isRemote() {
+ return false;
+ }
+
+ public void array(int[] v) {
+ return;
+ }
+
+ public void stringarray(String[] v) {
+ return;
+ }
+
+ public void map(Map<String, String> m) {
+ return;
+ }
+
+ public void list(List<String> l) {
+ return;
+ }
+
+ public void bytes(byte[] b) {
+ return;
+ }
+
+ public void struct(ProfileStruct ps) {
+ return;
+ }
+
+ public void string(String s) {
+ return;
+ }
+
+ public void NoReply() {
+ return;
+ }
+
+ public void Pong() {
+ return;
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/ProfileStruct.java b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfileStruct.java
new file mode 100644
index 0000000..b86c137
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/ProfileStruct.java
@@ -0,0 +1,26 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public final class ProfileStruct extends Struct {
+ @Position(0)
+ public final String a;
+ @Position(1)
+ public final UInt32 b;
+ @Position(2)
+ public final long c;
+
+ public ProfileStruct(String a, UInt32 b, long c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/test.java b/federation/sssd/src/test/java/org/freedesktop/dbus/test.java
new file mode 100644
index 0000000..af6a736
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/test.java
@@ -0,0 +1,991 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus;
+import org.freedesktop.DBus.Error.MatchRuleInvalid;
+import org.freedesktop.DBus.Error.ServiceUnknown;
+import org.freedesktop.DBus.Error.UnknownObject;
+import org.freedesktop.DBus.Introspectable;
+import org.freedesktop.DBus.Peer;
+import org.freedesktop.DBus.Properties;
+import org.freedesktop.dbus.exceptions.DBusException;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+import org.freedesktop.dbus.exceptions.NotConnected;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.text.Collator;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+class testnewclass implements TestNewInterface {
+ public boolean isRemote() {
+ return false;
+ }
+
+ public String getName() {
+ return toString();
+ }
+}
+
+class testclass implements TestRemoteInterface, TestRemoteInterface2, TestSignalInterface, TestSignalInterface2, Properties {
+ private DBusConnection conn;
+
+ public testclass(DBusConnection conn) {
+ this.conn = conn;
+ }
+
+ public String Introspect() {
+ return "Not XML";
+ }
+
+ public int[][] teststructstruct(TestStruct3 in) {
+ List<List<Integer>> lli = in.b;
+ int[][] out = new int[lli.size()][];
+ for (int j = 0; j < out.length; j++) {
+ out[j] = new int[lli.get(j).size()];
+ for (int k = 0; k < out[j].length; k++)
+ out[j][k] = lli.get(j).get(k);
+ }
+ return out;
+ }
+
+ public float testfloat(float[] f) {
+ if (f.length < 4 ||
+ f[0] != 17.093f ||
+ f[1] != -23f ||
+ f[2] != 0.0f ||
+ f[3] != 31.42f)
+ test.fail("testfloat got incorrect array");
+ return f[0];
+ }
+
+ public void newpathtest(Path p) {
+ if (!p.toString().equals("/new/path/test"))
+ test.fail("new path test got wrong path");
+ }
+
+ public void waitawhile() {
+ System.out.println("Sleeping.");
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException Ie) {
+ }
+ System.out.println("Done sleeping.");
+ }
+
+ public <A> TestTuple<String, List<Integer>, Boolean> show(A in) {
+ System.out.println("Showing Stuff: " + in.getClass() + "(" + in + ")");
+ if (!(in instanceof Integer) || ((Integer) in).intValue() != 234)
+ test.fail("show received the wrong arguments");
+ DBusCallInfo info = DBusConnection.getCallInfo();
+ List<Integer> l = new Vector<Integer>();
+ l.add(1953);
+ return new TestTuple<String, List<Integer>, Boolean>(info.getSource(), l, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T dostuff(TestStruct foo) {
+ System.out.println("Doing Stuff " + foo);
+ System.out.println(" -- (" + foo.a.getClass() + ", " + foo.b.getClass() + ", " + foo.c.getClass() + ")");
+ if (!(foo instanceof TestStruct) ||
+ !(foo.a instanceof String) ||
+ !(foo.b instanceof UInt32) ||
+ !(foo.c instanceof Variant) ||
+ !"bar".equals(foo.a) ||
+ foo.b.intValue() != 52 ||
+ !(foo.c.getValue() instanceof Boolean) ||
+ ((Boolean) foo.c.getValue()).booleanValue() != true)
+ test.fail("dostuff received the wrong arguments");
+ return (T) foo.c.getValue();
+ }
+
+ /**
+ * Local classes MUST implement this to return false
+ */
+ public boolean isRemote() {
+ return false;
+ }
+
+ /**
+ * The method we are exporting to the Bus.
+ */
+ public List<Integer> sampleArray(List<String> ss, Integer[] is, long[] ls) {
+ System.out.println("Got an array:");
+ for (String s : ss)
+ System.out.println("--" + s);
+ if (ss.size() != 5 ||
+ !"hi".equals(ss.get(0)) ||
+ !"hello".equals(ss.get(1)) ||
+ !"hej".equals(ss.get(2)) ||
+ !"hey".equals(ss.get(3)) ||
+ !"aloha".equals(ss.get(4)))
+ test.fail("sampleArray, String array contents incorrect");
+ System.out.println("Got an array:");
+ for (Integer i : is)
+ System.out.println("--" + i);
+ if (is.length != 4 ||
+ is[0].intValue() != 1 ||
+ is[1].intValue() != 5 ||
+ is[2].intValue() != 7 ||
+ is[3].intValue() != 9)
+ test.fail("sampleArray, Integer array contents incorrect");
+ System.out.println("Got an array:");
+ for (long l : ls)
+ System.out.println("--" + l);
+ if (ls.length != 4 ||
+ ls[0] != 2 ||
+ ls[1] != 6 ||
+ ls[2] != 8 ||
+ ls[3] != 12)
+ test.fail("sampleArray, Integer array contents incorrect");
+ Vector<Integer> v = new Vector<Integer>();
+ v.add(-1);
+ v.add(-5);
+ v.add(-7);
+ v.add(-12);
+ v.add(-18);
+ return v;
+ }
+
+ public String getName() {
+ return "This Is A UTF-8 Name: س !!";
+ }
+
+ public String getNameAndThrow() throws TestException {
+ throw new TestException("test");
+ }
+
+ public boolean check() {
+ System.out.println("Being checked");
+ return false;
+ }
+
+ public <T> int frobnicate(List<Long> n, Map<String, Map<UInt16, Short>> m, T v) {
+ if (null == n)
+ test.fail("List was null");
+ if (n.size() != 3)
+ test.fail("List was wrong size (expected 3, actual " + n.size() + ")");
+ if (n.get(0) != 2L ||
+ n.get(1) != 5L ||
+ n.get(2) != 71L)
+ test.fail("List has wrong contents");
+ if (!(v instanceof Integer))
+ test.fail("v not an Integer");
+ if (((Integer) v) != 13)
+ test.fail("v is incorrect");
+ if (null == m)
+ test.fail("Map was null");
+ if (m.size() != 1)
+ test.fail("Map was wrong size");
+ if (!m.keySet().contains("stuff"))
+ test.fail("Incorrect key");
+ Map<UInt16, Short> mus = m.get("stuff");
+ if (null == mus)
+ test.fail("Sub-Map was null");
+ if (mus.size() != 3)
+ test.fail("Sub-Map was wrong size");
+ if (!(new Short((short) 5).equals(mus.get(new UInt16(4)))))
+ test.fail("Sub-Map has wrong contents");
+ if (!(new Short((short) 6).equals(mus.get(new UInt16(5)))))
+ test.fail("Sub-Map has wrong contents");
+ if (!(new Short((short) 7).equals(mus.get(new UInt16(6)))))
+ test.fail("Sub-Map has wrong contents");
+ return -5;
+ }
+
+ public DBusInterface getThis(DBusInterface t) {
+ if (!t.equals(this))
+ test.fail("Didn't get this properly");
+ return this;
+ }
+
+ public void throwme() throws TestException {
+ throw new TestException("test");
+ }
+
+ public TestSerializable<String> testSerializable(byte b, TestSerializable<String> s, int i) {
+ System.out.println("Recieving TestSerializable: " + s);
+ if (b != 12
+ || i != 13
+ || !(s.getInt() == 1)
+ || !(s.getString().equals("woo"))
+ || !(s.getVector().size() == 3)
+ || !(s.getVector().get(0) == 1)
+ || !(s.getVector().get(1) == 2)
+ || !(s.getVector().get(2) == 3))
+ test.fail("Error in recieving custom synchronisation");
+ return s;
+ }
+
+ public String recursionTest() {
+ try {
+ TestRemoteInterface tri = conn.getRemoteObject("foo.bar.Test", "/Test", TestRemoteInterface.class);
+ return tri.getName();
+ } catch (DBusException DBe) {
+ test.fail("Failed with error: " + DBe);
+ return "";
+ }
+ }
+
+ public int overload(String s) {
+ return 1;
+ }
+
+ public int overload(byte b) {
+ return 2;
+ }
+
+ public int overload() {
+ DBusCallInfo info = DBusConnection.getCallInfo();
+ if ("org.freedesktop.dbus.test.AlternateTestInterface".equals(info.getInterface()))
+ return 3;
+ else if ("org.freedesktop.dbus.test.TestRemoteInterface".equals(info.getInterface()))
+ return 4;
+ else
+ return -1;
+ }
+
+ public List<List<Integer>> checklist(List<List<Integer>> lli) {
+ return lli;
+ }
+
+ public TestNewInterface getNew() {
+ testnewclass n = new testnewclass();
+ try {
+ conn.exportObject("/new", n);
+ } catch (DBusException DBe) {
+ throw new DBusExecutionException(DBe.getMessage());
+ }
+ return n;
+ }
+
+ public void sig(Type[] s) {
+ if (s.length != 2
+ || !s[0].equals(Byte.class)
+ || !(s[1] instanceof ParameterizedType)
+ || !Map.class.equals(((ParameterizedType) s[1]).getRawType())
+ || ((ParameterizedType) s[1]).getActualTypeArguments().length != 2
+ || !String.class.equals(((ParameterizedType) s[1]).getActualTypeArguments()[0])
+ || !Integer.class.equals(((ParameterizedType) s[1]).getActualTypeArguments()[1]))
+ test.fail("Didn't send types correctly");
+ }
+
+ @SuppressWarnings("unchecked")
+ public void complexv(Variant<? extends Object> v) {
+ if (!"a{ss}".equals(v.getSig())
+ || !(v.getValue() instanceof Map)
+ || ((Map<Object, Object>) v.getValue()).size() != 1
+ || !"moo".equals(((Map<Object, Object>) v.getValue()).get("cow")))
+ test.fail("Didn't send variant correctly");
+ }
+
+ public void reg13291(byte[] as, byte[] bs) {
+ if (as.length != bs.length) test.fail("didn't receive identical byte arrays");
+ for (int i = 0; i < as.length; i++)
+ if (as[i] != bs[i]) test.fail("didn't receive identical byte arrays");
+ }
+
+ @SuppressWarnings("unchecked")
+ public <A> A Get(String interface_name, String property_name) {
+ return (A) new Path("/nonexistant/path");
+ }
+
+ public <A> void Set(String interface_name, String property_name, A value) {
+ }
+
+ public Map<String, Variant> GetAll(String interface_name) {
+ return new HashMap<String, Variant>();
+ }
+
+ public Path pathrv(Path a) {
+ return a;
+ }
+
+ public List<Path> pathlistrv(List<Path> a) {
+ return a;
+ }
+
+ public Map<Path, Path> pathmaprv(Map<Path, Path> a) {
+ return a;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Map<String, Variant> svm() {
+ HashMap<String, Variant> properties = new HashMap<String, Variant>();
+ HashMap<String, Variant<String>> parameters = new HashMap<String, Variant<String>>();
+
+ parameters.put("Name", new Variant<String>("Joe"));
+ parameters.put("Password", new Variant<String>("abcdef"));
+
+ properties.put("Parameters", new Variant(parameters, "a{sv}"));
+ return (Map<String, Variant>) properties;
+ }
+}
+
+/**
+ * Typed signal handler for renamed signal
+ */
+class renamedsignalhandler implements DBusSigHandler<TestSignalInterface2.TestRenamedSignal> {
+ /**
+ * Handling a signal
+ */
+ public void handle(TestSignalInterface2.TestRenamedSignal t) {
+ if (false == test.done5) {
+ test.done5 = true;
+ } else {
+ test.fail("SignalHandler R has been run too many times");
+ }
+ System.out.println("SignalHandler R Running");
+ System.out.println("string(" + t.value + ") int(" + t.number + ")");
+ if (!"Bar".equals(t.value) || !(new UInt32(42)).equals(t.number))
+ test.fail("Incorrect TestRenamedSignal parameters");
+ }
+}
+
+/**
+ * Empty signal handler
+ */
+class emptysignalhandler implements DBusSigHandler<TestSignalInterface.EmptySignal> {
+ /**
+ * Handling a signal
+ */
+ public void handle(TestSignalInterface.EmptySignal t) {
+ if (false == test.done7) {
+ test.done7 = true;
+ } else {
+ test.fail("SignalHandler E has been run too many times");
+ }
+ System.out.println("SignalHandler E Running");
+ }
+}
+
+/**
+ * Disconnect handler
+ */
+class disconnecthandler implements DBusSigHandler<DBus.Local.Disconnected> {
+ private DBusConnection conn;
+ private renamedsignalhandler sh;
+
+ public disconnecthandler(DBusConnection conn, renamedsignalhandler sh) {
+ this.conn = conn;
+ this.sh = sh;
+ }
+
+ /**
+ * Handling a signal
+ */
+ public void handle(DBus.Local.Disconnected t) {
+ if (false == test.done6) {
+ test.done6 = true;
+ System.out.println("Handling disconnect, unregistering handler");
+ try {
+ conn.removeSigHandler(TestSignalInterface2.TestRenamedSignal.class, sh);
+ } catch (DBusException DBe) {
+ DBe.printStackTrace();
+ test.fail("Disconnect handler threw an exception: " + DBe);
+ }
+ }
+ }
+}
+
+
+/**
+ * Typed signal handler
+ */
+class pathsignalhandler implements DBusSigHandler<TestSignalInterface.TestPathSignal> {
+ /**
+ * Handling a signal
+ */
+ public void handle(TestSignalInterface.TestPathSignal t) {
+ System.out.println("Path sighandler: " + t);
+ }
+}
+
+/**
+ * Typed signal handler
+ */
+class signalhandler implements DBusSigHandler<TestSignalInterface.TestSignal> {
+ /**
+ * Handling a signal
+ */
+ public void handle(TestSignalInterface.TestSignal t) {
+ if (false == test.done1) {
+ test.done1 = true;
+ } else {
+ test.fail("SignalHandler 1 has been run too many times");
+ }
+ System.out.println("SignalHandler 1 Running");
+ System.out.println("string(" + t.value + ") int(" + t.number + ")");
+ if (!"Bar".equals(t.value) || !(new UInt32(42)).equals(t.number))
+ test.fail("Incorrect TestSignal parameters");
+ }
+}
+
+/**
+ * Untyped signal handler
+ */
+class arraysignalhandler implements DBusSigHandler<TestSignalInterface.TestArraySignal> {
+ /**
+ * Handling a signal
+ */
+ public void handle(TestSignalInterface.TestArraySignal t) {
+ try {
+ if (false == test.done2) {
+ test.done2 = true;
+ } else {
+ test.fail("SignalHandler 2 has been run too many times");
+ }
+ System.out.println("SignalHandler 2 Running");
+ if (t.v.size() != 1)
+ test.fail("Incorrect TestArraySignal array length: should be 1, actually " + t.v.size());
+ System.out.println("Got a test array signal with Parameters: ");
+ for (String str : t.v.get(0).a)
+ System.out.println("--" + str);
+ System.out.println(t.v.get(0).b.getType());
+ System.out.println(t.v.get(0).b.getValue());
+ if (!(t.v.get(0).b.getValue() instanceof UInt64) ||
+ 567L != ((UInt64) t.v.get(0).b.getValue()).longValue() ||
+ t.v.get(0).a.size() != 5 ||
+ !"hi".equals(t.v.get(0).a.get(0)) ||
+ !"hello".equals(t.v.get(0).a.get(1)) ||
+ !"hej".equals(t.v.get(0).a.get(2)) ||
+ !"hey".equals(t.v.get(0).a.get(3)) ||
+ !"aloha".equals(t.v.get(0).a.get(4)))
+ test.fail("Incorrect TestArraySignal parameters");
+
+ if (t.m.keySet().size() != 2)
+ test.fail("Incorrect TestArraySignal map size: should be 2, actually " + t.m.keySet().size());
+ if (!(t.m.get(new UInt32(1)).b.getValue() instanceof UInt64) ||
+ 678L != ((UInt64) t.m.get(new UInt32(1)).b.getValue()).longValue() ||
+ !(t.m.get(new UInt32(42)).b.getValue() instanceof UInt64) ||
+ 789L != ((UInt64) t.m.get(new UInt32(42)).b.getValue()).longValue())
+ test.fail("Incorrect TestArraySignal parameters");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ test.fail("SignalHandler 2 threw an exception: " + e);
+ }
+ }
+}
+
+/**
+ * Object path signal handler
+ */
+class objectsignalhandler implements DBusSigHandler<TestSignalInterface.TestObjectSignal> {
+ public void handle(TestSignalInterface.TestObjectSignal s) {
+ if (false == test.done3) {
+ test.done3 = true;
+ } else {
+ test.fail("SignalHandler 3 has been run too many times");
+ }
+ System.out.println(s.otherpath);
+ }
+}
+
+/**
+ * handler which should never be called
+ */
+class badarraysignalhandler<T extends DBusSignal> implements DBusSigHandler<T> {
+ /**
+ * Handling a signal
+ */
+ public void handle(T s) {
+ test.fail("This signal handler shouldn't be called");
+ }
+}
+
+/**
+ * Callback handler
+ */
+class callbackhandler implements CallbackHandler<String> {
+ public void handle(String r) {
+ System.out.println("Handling callback: " + r);
+ Collator col = Collator.getInstance();
+ col.setDecomposition(Collator.FULL_DECOMPOSITION);
+ col.setStrength(Collator.PRIMARY);
+ if (0 != col.compare("This Is A UTF-8 Name: ﺱ !!", r))
+ test.fail("call with callback, wrong return value");
+ if (test.done4) test.fail("Already ran callback handler");
+ test.done4 = true;
+ }
+
+ public void handleError(DBusExecutionException e) {
+ System.out.println("Handling error callback: " + e + " message = '" + e.getMessage() + "'");
+ if (!(e instanceof TestException)) test.fail("Exception is of the wrong sort");
+ Collator col = Collator.getInstance();
+ col.setDecomposition(Collator.FULL_DECOMPOSITION);
+ col.setStrength(Collator.PRIMARY);
+ if (0 != col.compare("test", e.getMessage()))
+ test.fail("Exception has the wrong message");
+ if (test.done8) test.fail("Already ran callback error handler");
+ test.done8 = true;
+ }
+}
+
+/**
+ * This is a test program which sends and recieves a signal, implements, exports and calls a remote method.
+ */
+public class test {
+ public static boolean done1 = false;
+ public static boolean done2 = false;
+ public static boolean done3 = false;
+ public static boolean done4 = false;
+ public static boolean done5 = false;
+ public static boolean done6 = false;
+ public static boolean done7 = false;
+ public static boolean done8 = false;
+
+ public static void fail(String message) {
+ System.out.println("Test Failed: " + message);
+ System.err.println("Test Failed: " + message);
+ if (null != serverconn) serverconn.disconnect();
+ if (null != clientconn) clientconn.disconnect();
+ System.exit(1);
+ }
+
+ static DBusConnection serverconn = null;
+ static DBusConnection clientconn = null;
+
+ @SuppressWarnings("unchecked")
+ public static void main(String[] args) {
+ try {
+ System.out.println("Creating Connection");
+ serverconn = DBusConnection.getConnection(DBusConnection.SESSION);
+ clientconn = DBusConnection.getConnection(DBusConnection.SESSION);
+ serverconn.setWeakReferences(true);
+ clientconn.setWeakReferences(true);
+
+ System.out.println("Registering Name");
+ serverconn.requestBusName("foo.bar.Test");
+
+ /** This gets a remote object matching our bus name and exported object path. */
+ Peer peer = clientconn.getRemoteObject("foo.bar.Test", "/Test", Peer.class);
+ DBus dbus = clientconn.getRemoteObject("org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
+
+ System.out.print("Listening for signals...");
+ signalhandler sigh = new signalhandler();
+ renamedsignalhandler rsh = new renamedsignalhandler();
+ try {
+ /** This registers an instance of the test class as the signal handler for the TestSignal class. */
+ clientconn.addSigHandler(TestSignalInterface.EmptySignal.class, new emptysignalhandler());
+ clientconn.addSigHandler(TestSignalInterface.TestSignal.class, sigh);
+ clientconn.addSigHandler(TestSignalInterface2.TestRenamedSignal.class, rsh);
+ clientconn.addSigHandler(DBus.Local.Disconnected.class, new disconnecthandler(clientconn, rsh));
+ String source = dbus.GetNameOwner("foo.bar.Test");
+ clientconn.addSigHandler(TestSignalInterface.TestArraySignal.class, source, peer, new arraysignalhandler());
+ clientconn.addSigHandler(TestSignalInterface.TestObjectSignal.class, new objectsignalhandler());
+ clientconn.addSigHandler(TestSignalInterface.TestPathSignal.class, new pathsignalhandler());
+ badarraysignalhandler<TestSignalInterface.TestSignal> bash = new badarraysignalhandler<TestSignalInterface.TestSignal>();
+ clientconn.addSigHandler(TestSignalInterface.TestSignal.class, bash);
+ clientconn.removeSigHandler(TestSignalInterface.TestSignal.class, bash);
+ System.out.println("done");
+ } catch (MatchRuleInvalid MRI) {
+ test.fail("Failed to add handlers: " + MRI.getMessage());
+ } catch (DBusException DBe) {
+ test.fail("Failed to add handlers: " + DBe.getMessage());
+ }
+
+ System.out.println("Listening for Method Calls");
+ testclass tclass = new testclass(serverconn);
+ testclass tclass2 = new testclass(serverconn);
+ /** This exports an instance of the test class as the object /Test. */
+ serverconn.exportObject("/Test", tclass);
+ serverconn.exportObject("/BadTest", tclass);
+ serverconn.exportObject("/BadTest2", tclass2);
+ serverconn.addFallback("/FallbackTest", tclass);
+
+ // explicitly unexport object
+ serverconn.unExportObject("/BadTest");
+ // implicitly unexport object
+ tclass2 = null;
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ System.runFinalization();
+
+ System.out.println("Sending Signal");
+ /** This creates an instance of the Test Signal, with the given object path, signal name and parameters, and broadcasts in on the Bus. */
+ serverconn.sendSignal(new TestSignalInterface.TestSignal("/foo/bar/Wibble", "Bar", new UInt32(42)));
+ serverconn.sendSignal(new TestSignalInterface.EmptySignal("/foo/bar/Wibble"));
+ serverconn.sendSignal(new TestSignalInterface2.TestRenamedSignal("/foo/bar/Wibble", "Bar", new UInt32(42)));
+
+ System.out.println("These things are on the bus:");
+ String[] names = dbus.ListNames();
+ for (String name : names)
+ System.out.println("\t" + name);
+
+ System.out.println("Getting our introspection data");
+ /** This gets a remote object matching our bus name and exported object path. */
+ Introspectable intro = clientconn.getRemoteObject("foo.bar.Test", "/", Introspectable.class);
+ /** Get introspection data */
+ String data;/* = intro.Introspect();
+ if (null == data || !data.startsWith("<!DOCTYPE"))
+ fail("Introspection data invalid");
+ System.out.println("Got Introspection Data: \n"+data);*/
+ intro = clientconn.getRemoteObject("foo.bar.Test", "/Test", Introspectable.class);
+ /** Get introspection data */
+ data = intro.Introspect();
+ if (null == data || !data.startsWith("<!DOCTYPE"))
+ fail("Introspection data invalid");
+ System.out.println("Got Introspection Data: \n" + data);
+
+ // setup bus name set
+ Set<String> peers = serverconn.new PeerSet();
+ peers.add("org.freedesktop.DBus");
+ clientconn.requestBusName("test.testclient");
+ peers.add("test.testclient");
+ clientconn.releaseBusName("test.testclient");
+
+ System.out.println("Pinging ourselves");
+ /** Call ping. */
+ for (int i = 0; i < 10; i++) {
+ long then = System.currentTimeMillis();
+ peer.Ping();
+ long now = System.currentTimeMillis();
+ System.out.println("Ping returned in " + (now - then) + "ms.");
+ }
+
+ System.out.println("Calling Method0/1");
+ /** This gets a remote object matching our bus name and exported object path. */
+ TestRemoteInterface tri = (TestRemoteInterface) clientconn.getPeerRemoteObject("foo.bar.Test", "/Test");
+ System.out.println("Got Remote Object: " + tri);
+ /** Call the remote object and get a response. */
+ String rname = tri.getName();
+ System.out.println("Got Remote Name: " + rname);
+
+ Map<String, Variant> svmmap = tri.svm();
+ System.out.println(svmmap.toString());
+ if (!"{ Parameters => [{ Name => [Joe],Password => [abcdef] }] }".equals(svmmap.toString()))
+ fail("incorrect reply from svm");
+
+ Path path = new Path("/nonexistantwooooooo");
+ Path p = tri.pathrv(path);
+ System.out.println(path.toString() + " => " + p.toString());
+ if (!path.equals(p)) fail("pathrv incorrect");
+ List<Path> paths = new Vector<Path>();
+ paths.add(path);
+ List<Path> ps = tri.pathlistrv(paths);
+ System.out.println(paths.toString() + " => " + ps.toString());
+ if (!paths.equals(ps)) fail("pathlistrv incorrect");
+ Map<Path, Path> pathm = new HashMap<Path, Path>();
+ pathm.put(path, path);
+ Map<Path, Path> pm = tri.pathmaprv(pathm);
+ System.out.println(pathm.toString() + " => " + pm.toString());
+ System.out.println(pm.containsKey(path) + " " + pm.get(path) + " " + path.equals(pm.get(path)));
+ System.out.println(pm.containsKey(p) + " " + pm.get(p) + " " + p.equals(pm.get(p)));
+ for (Path q : pm.keySet()) {
+ System.out.println(q);
+ System.out.println(pm.get(q));
+ }
+ if (!pm.containsKey(path) || !path.equals(pm.get(path))) fail("pathmaprv incorrect");
+
+ serverconn.sendSignal(new TestSignalInterface.TestPathSignal("/Test", path, paths, pathm));
+
+ Collator col = Collator.getInstance();
+ col.setDecomposition(Collator.FULL_DECOMPOSITION);
+ col.setStrength(Collator.PRIMARY);
+ if (0 != col.compare("This Is A UTF-8 Name: ﺱ !!", rname))
+ fail("getName return value incorrect");
+ System.out.println("sending it to sleep");
+ tri.waitawhile();
+ System.out.println("testing floats");
+ if (17.093f != tri.testfloat(new float[]{17.093f, -23f, 0.0f, 31.42f}))
+ fail("testfloat returned the wrong thing");
+ System.out.println("Structs of Structs");
+ List<List<Integer>> lli = new Vector<List<Integer>>();
+ List<Integer> li = new Vector<Integer>();
+ li.add(1);
+ li.add(2);
+ li.add(3);
+ lli.add(li);
+ lli.add(li);
+ lli.add(li);
+ TestStruct3 ts3 = new TestStruct3(new TestStruct2(new Vector<String>(), new Variant<Integer>(0)), lli);
+ int[][] out = tri.teststructstruct(ts3);
+ if (out.length != 3) fail("teststructstruct returned the wrong thing: " + Arrays.deepToString(out));
+ for (int[] o : out)
+ if (o.length != 3
+ || o[0] != 1
+ || o[1] != 2
+ || o[2] != 3) fail("teststructstruct returned the wrong thing: " + Arrays.deepToString(out));
+
+ System.out.println("frobnicating");
+ List<Long> ls = new Vector<Long>();
+ ls.add(2L);
+ ls.add(5L);
+ ls.add(71L);
+ Map<UInt16, Short> mus = new HashMap<UInt16, Short>();
+ mus.put(new UInt16(4), (short) 5);
+ mus.put(new UInt16(5), (short) 6);
+ mus.put(new UInt16(6), (short) 7);
+ Map<String, Map<UInt16, Short>> msmus = new HashMap<String, Map<UInt16, Short>>();
+ msmus.put("stuff", mus);
+ int rint = tri.frobnicate(ls, msmus, 13);
+ if (-5 != rint)
+ fail("frobnicate return value incorrect");
+
+ System.out.println("Doing stuff asynchronously with callback");
+ clientconn.callWithCallback(tri, "getName", new callbackhandler());
+ System.out.println("Doing stuff asynchronously with callback, which throws an error");
+ clientconn.callWithCallback(tri, "getNameAndThrow", new callbackhandler());
+
+ /** call something that throws */
+ try {
+ System.out.println("Throwing stuff");
+ tri.throwme();
+ test.fail("Method Execution should have failed");
+ } catch (TestException Te) {
+ System.out.println("Remote Method Failed with: " + Te.getClass().getName() + " " + Te.getMessage());
+ if (!Te.getMessage().equals("test"))
+ test.fail("Error message was not correct");
+ }
+
+ /* Test type signatures */
+ Vector<Type> ts = new Vector<Type>();
+ Marshalling.getJavaType("ya{si}", ts, -1);
+ tri.sig(ts.toArray(new Type[0]));
+
+ tri.newpathtest(new Path("/new/path/test"));
+
+ /** Try and call an invalid remote object */
+ try {
+ System.out.println("Calling Method2");
+ tri = clientconn.getRemoteObject("foo.bar.NotATest", "/Moofle", TestRemoteInterface.class);
+ System.out.println("Got Remote Name: " + tri.getName());
+ test.fail("Method Execution should have failed");
+ } catch (ServiceUnknown SU) {
+ System.out.println("Remote Method Failed with: " + SU.getClass().getName() + " " + SU.getMessage());
+ }
+
+ /** Try and call an invalid remote object */
+ try {
+ System.out.println("Calling Method3");
+ tri = clientconn.getRemoteObject("foo.bar.Test", "/Moofle", TestRemoteInterface.class);
+ System.out.println("Got Remote Name: " + tri.getName());
+ test.fail("Method Execution should have failed");
+ } catch (UnknownObject UO) {
+ System.out.println("Remote Method Failed with: " + UO.getClass().getName() + " " + UO.getMessage());
+ }
+
+ /** Try and call an explicitly unexported object */
+ try {
+ System.out.println("Calling Method4");
+ tri = clientconn.getRemoteObject("foo.bar.Test", "/BadTest", TestRemoteInterface.class);
+ System.out.println("Got Remote Name: " + tri.getName());
+ test.fail("Method Execution should have failed");
+ } catch (UnknownObject UO) {
+ System.out.println("Remote Method Failed with: " + UO.getClass().getName() + " " + UO.getMessage());
+ }
+
+ /** Try and call an implicitly unexported object */
+ try {
+ System.out.println("Calling Method5");
+ tri = clientconn.getRemoteObject("foo.bar.Test", "/BadTest2", TestRemoteInterface.class);
+ System.out.println("Got Remote Name: " + tri.getName());
+ test.fail("Method Execution should have failed");
+ } catch (UnknownObject UO) {
+ System.out.println("Remote Method Failed with: " + UO.getClass().getName() + " " + UO.getMessage());
+ }
+
+ System.out.println("Calling Method6");
+ tri = clientconn.getRemoteObject("foo.bar.Test", "/FallbackTest/0/1", TestRemoteInterface.class);
+ intro = clientconn.getRemoteObject("foo.bar.Test", "/FallbackTest/0/4", Introspectable.class);
+ System.out.println("Got Fallback Name: " + tri.getName());
+ System.out.println("Fallback Introspection Data: \n" + intro.Introspect());
+
+ System.out.println("Testing Properties returning Paths");
+ Properties prop = clientconn.getRemoteObject("foo.bar.Test", "/Test", Properties.class);
+ Path prv = (Path) prop.Get("foo.bar", "foo");
+ System.out.println("Got path " + prv);
+ System.out.println("Calling Method7--9");
+ /** This gets a remote object matching our bus name and exported object path. */
+ TestRemoteInterface2 tri2 = clientconn.getRemoteObject("foo.bar.Test", "/Test", TestRemoteInterface2.class);
+ System.out.print("Calling the other introspect method: ");
+ String intro2 = tri2.Introspect();
+ System.out.println(intro2);
+ if (0 != col.compare("Not XML", intro2))
+ fail("Introspect return value incorrect");
+
+ /** Call the remote object and get a response. */
+ TestTuple<String, List<Integer>, Boolean> rv = tri2.show(234);
+ System.out.println("Show returned: " + rv);
+ if (!serverconn.getUniqueName().equals(rv.a) ||
+ 1 != rv.b.size() ||
+ 1953 != rv.b.get(0) ||
+ true != rv.c.booleanValue())
+ fail("show return value incorrect (" + rv.a + "," + rv.b + "," + rv.c + ")");
+
+ System.out.println("Doing stuff asynchronously");
+ DBusAsyncReply<Boolean> stuffreply = (DBusAsyncReply<Boolean>) clientconn.callMethodAsync(tri2, "dostuff", new TestStruct("bar", new UInt32(52), new Variant<Boolean>(new Boolean(true))));
+
+ System.out.println("Checking bools");
+ if (tri2.check()) fail("bools are broken");
+
+ List<String> l = new Vector<String>();
+ l.add("hi");
+ l.add("hello");
+ l.add("hej");
+ l.add("hey");
+ l.add("aloha");
+ System.out.println("Sampling Arrays:");
+ List<Integer> is = tri2.sampleArray(l, new Integer[]{1, 5, 7, 9}, new long[]{2, 6, 8, 12});
+ System.out.println("sampleArray returned an array:");
+ for (Integer i : is)
+ System.out.println("--" + i);
+ if (is.size() != 5 ||
+ is.get(0).intValue() != -1 ||
+ is.get(1).intValue() != -5 ||
+ is.get(2).intValue() != -7 ||
+ is.get(3).intValue() != -12 ||
+ is.get(4).intValue() != -18)
+ fail("sampleArray return value incorrect");
+
+ System.out.println("Get This");
+ if (!tclass.equals(tri2.getThis(tri2)))
+ fail("Didn't get the correct this");
+
+ Boolean b = stuffreply.getReply();
+ System.out.println("Do stuff replied " + b);
+ if (true != b.booleanValue())
+ fail("dostuff return value incorrect");
+
+ System.out.print("Sending Array Signal...");
+ /** This creates an instance of the Test Signal, with the given object path, signal name and parameters, and broadcasts in on the Bus. */
+ List<TestStruct2> tsl = new Vector<TestStruct2>();
+ tsl.add(new TestStruct2(l, new Variant<UInt64>(new UInt64(567))));
+ Map<UInt32, TestStruct2> tsm = new HashMap<UInt32, TestStruct2>();
+ tsm.put(new UInt32(1), new TestStruct2(l, new Variant<UInt64>(new UInt64(678))));
+ tsm.put(new UInt32(42), new TestStruct2(l, new Variant<UInt64>(new UInt64(789))));
+ serverconn.sendSignal(new TestSignalInterface.TestArraySignal("/Test", tsl, tsm));
+
+ System.out.println("done");
+
+ System.out.print("testing custom serialization...");
+ Vector<Integer> v = new Vector<Integer>();
+ v.add(1);
+ v.add(2);
+ v.add(3);
+ TestSerializable<String> s = new TestSerializable<String>(1, "woo", v);
+ s = tri2.testSerializable((byte) 12, s, 13);
+ System.out.print("returned: " + s);
+ if (s.getInt() != 1 ||
+ !s.getString().equals("woo") ||
+ s.getVector().size() != 3 ||
+ s.getVector().get(0) != 1 ||
+ s.getVector().get(1) != 2 ||
+ s.getVector().get(2) != 3)
+ fail("Didn't get back the same TestSerializable");
+
+ System.out.println("done");
+
+ System.out.print("testing complex variants...");
+ Map m = new HashMap();
+ m.put("cow", "moo");
+ tri2.complexv(new Variant(m, "a{ss}"));
+ System.out.println("done");
+
+ System.out.print("testing recursion...");
+
+ if (0 != col.compare("This Is A UTF-8 Name: ﺱ !!", tri2.recursionTest())) fail("recursion test failed");
+
+ System.out.println("done");
+
+ System.out.print("testing method overloading...");
+ tri = clientconn.getRemoteObject("foo.bar.Test", "/Test", TestRemoteInterface.class);
+ if (1 != tri2.overload("foo")) test.fail("wrong overloaded method called");
+ if (2 != tri2.overload((byte) 0)) test.fail("wrong overloaded method called");
+ if (3 != tri2.overload()) test.fail("wrong overloaded method called");
+ if (4 != tri.overload()) test.fail("wrong overloaded method called");
+ System.out.println("done");
+
+ System.out.print("reg13291...");
+ byte[] as = new byte[10];
+ for (int i = 0; i < 10; i++)
+ as[i] = (byte) (100 - i);
+ tri.reg13291(as, as);
+ System.out.println("done");
+
+ System.out.print("Testing nested lists...");
+ lli = new Vector<List<Integer>>();
+ li = new Vector<Integer>();
+ li.add(1);
+ lli.add(li);
+ List<List<Integer>> reti = tri2.checklist(lli);
+ if (reti.size() != 1 ||
+ reti.get(0).size() != 1 ||
+ reti.get(0).get(0) != 1)
+ test.fail("Failed to check nested lists");
+ System.out.println("done");
+
+ System.out.print("Testing dynamic object creation...");
+ TestNewInterface tni = tri2.getNew();
+ System.out.print(tni.getName() + " ");
+ System.out.println("done");
+
+ /* send an object in a signal */
+ serverconn.sendSignal(new TestSignalInterface.TestObjectSignal("/foo/bar/Wibble", tclass));
+
+ /** Pause while we wait for the DBus messages to go back and forth. */
+ Thread.sleep(1000);
+
+ // check that bus name set has been trimmed
+ if (peers.size() != 1) fail("peers hasn't been trimmed");
+ if (!peers.contains("org.freedesktop.DBus")) fail("peers contains the wrong name");
+
+ System.out.println("Checking for outstanding errors");
+ DBusExecutionException DBEe = serverconn.getError();
+ if (null != DBEe) throw DBEe;
+ DBEe = clientconn.getError();
+ if (null != DBEe) throw DBEe;
+
+ System.out.println("Disconnecting");
+ /** Disconnect from the bus. */
+ clientconn.disconnect();
+ serverconn.disconnect();
+
+ System.out.println("Trying to do things after disconnection");
+
+ /** Remove sig handler */
+ clientconn.removeSigHandler(TestSignalInterface.TestSignal.class, sigh);
+
+ /** Call a method when disconnected */
+ try {
+ System.out.println("getName() suceeded and returned: " + tri.getName());
+ fail("Should not succeed when disconnected");
+ } catch (NotConnected NC) {
+ System.out.println("getName() failed with exception " + NC);
+ }
+ clientconn = null;
+ serverconn = null;
+
+ if (!done1) fail("Signal handler 1 failed to be run");
+ if (!done2) fail("Signal handler 2 failed to be run");
+ if (!done3) fail("Signal handler 3 failed to be run");
+ if (!done4) fail("Callback handler failed to be run");
+ if (!done5) fail("Signal handler R failed to be run");
+ if (!done6) fail("Disconnect handler failed to be run");
+ if (!done7) fail("Signal handler E failed to be run");
+ if (!done8) fail("Error callback handler failed to be run");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Unexpected Exception Occurred: " + e);
+ }
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/test_low_level.java b/federation/sssd/src/test/java/org/freedesktop/dbus/test_low_level.java
new file mode 100644
index 0000000..71699eb
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/test_low_level.java
@@ -0,0 +1,50 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import cx.ath.matthew.debug.Debug;
+
+public class test_low_level {
+ public static void main(String[] args) throws Exception {
+ Debug.setHexDump(true);
+ String addr = System.getenv("DBUS_SESSION_BUS_ADDRESS");
+ Debug.print(addr);
+ BusAddress address = new BusAddress(addr);
+ Debug.print(address);
+
+ Transport conn = new Transport(address);
+
+ Message m = new MethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "Hello", (byte) 0, null);
+ conn.mout.writeMessage(m);
+ m = conn.min.readMessage();
+ Debug.print(m.getClass());
+ Debug.print(m);
+ m = conn.min.readMessage();
+ Debug.print(m.getClass());
+ Debug.print(m);
+ m = conn.min.readMessage();
+ Debug.print("" + m);
+ m = new MethodCall("org.freedesktop.DBus", "/", null, "Hello", (byte) 0, null);
+ conn.mout.writeMessage(m);
+ m = conn.min.readMessage();
+ Debug.print(m);
+
+ m = new MethodCall("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "RequestName", (byte) 0, "su", "org.testname", 0);
+ conn.mout.writeMessage(m);
+ m = conn.min.readMessage();
+ Debug.print(m);
+ m = new DBusSignal(null, "/foo", "org.foo", "Foo", null);
+ conn.mout.writeMessage(m);
+ m = conn.min.readMessage();
+ Debug.print(m);
+ conn.disconnect();
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestException.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestException.java
new file mode 100644
index 0000000..98335c8
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestException.java
@@ -0,0 +1,22 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.dbus.exceptions.DBusExecutionException;
+
+@Description("A test exception to throw over DBus")
+@SuppressWarnings("serial")
+public class TestException extends DBusExecutionException {
+ public TestException(String message) {
+ super(message);
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestNewInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestNewInterface.java
new file mode 100644
index 0000000..6395787
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestNewInterface.java
@@ -0,0 +1,24 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+
+/**
+ * A sample remote interface which exports one method.
+ */
+public interface TestNewInterface extends DBusInterface {
+ /**
+ * A simple method with no parameters which returns a String
+ */
+ @Description("Simple test method")
+ public String getName();
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface.java
new file mode 100644
index 0000000..6fec592
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface.java
@@ -0,0 +1,68 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.DBus.Method;
+
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A sample remote interface which exports one method.
+ */
+public interface TestRemoteInterface extends DBusInterface {
+ /**
+ * A simple method with no parameters which returns a String
+ */
+ @Description("Simple test method")
+ public String getName();
+
+ public String getNameAndThrow();
+
+ @Description("Test of nested maps")
+ public <T> int frobnicate(List<Long> n, Map<String, Map<UInt16, Short>> m, T v);
+
+ @Description("Throws a TestException when called")
+ public void throwme() throws TestException;
+
+ @Description("Waits then doesn't return")
+ @Method.NoReply()
+ public void waitawhile();
+
+ @Description("Interface-overloaded method")
+ public int overload();
+
+ @Description("Testing Type Signatures")
+ public void sig(Type[] s);
+
+ @Description("Testing object paths as Path objects")
+ public void newpathtest(Path p);
+
+ @Description("Testing the float type")
+ public float testfloat(float[] f);
+
+ @Description("Testing structs of structs")
+ public int[][] teststructstruct(TestStruct3 in);
+
+ @Description("Regression test for #13291")
+ public void reg13291(byte[] as, byte[] bs);
+
+ public Map<String, Variant> svm();
+
+ /* test lots of things involving Path */
+ public Path pathrv(Path a);
+
+ public List<Path> pathlistrv(List<Path> a);
+
+ public Map<Path, Path> pathmaprv(Map<Path, Path> a);
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface2.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface2.java
new file mode 100644
index 0000000..7039fe1
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestRemoteInterface2.java
@@ -0,0 +1,62 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+
+import java.util.List;
+
+@Description("An example remote interface")
+@DBusInterfaceName("org.freedesktop.dbus.test.AlternateTestInterface")
+public interface TestRemoteInterface2 extends DBusInterface {
+ @Description("Test multiple return values and implicit variant parameters.")
+ public <A> TestTuple<String, List<Integer>, Boolean> show(A in);
+
+ @Description("Test passing structs and explicit variants, returning implicit variants")
+ public <T> T dostuff(TestStruct foo);
+
+ @Description("Test arrays, boxed arrays and lists.")
+ public List<Integer> sampleArray(List<String> l, Integer[] is, long[] ls);
+
+ @Description("Test passing objects as object paths.")
+ public DBusInterface getThis(DBusInterface t);
+
+ @Description("Test bools work")
+ @DBusMemberName("checkbool")
+ public boolean check();
+
+ @Description("Test Serializable Object")
+ public TestSerializable<String> testSerializable(byte b, TestSerializable<String> s, int i);
+
+ @Description("Call another method on itself from within a call")
+ public String recursionTest();
+
+ @Description("Parameter-overloaded method (string)")
+ public int overload(String s);
+
+ @Description("Parameter-overloaded method (byte)")
+ public int overload(byte b);
+
+ @Description("Parameter-overloaded method (void)")
+ public int overload();
+
+ @Description("Nested List Check")
+ public List<List<Integer>> checklist(List<List<Integer>> lli);
+
+ @Description("Get new objects as object paths.")
+ public TestNewInterface getNew();
+
+ @Description("Test Complex Variants")
+ public void complexv(Variant<? extends Object> v);
+
+ @Description("Test Introspect on a different interface")
+ public String Introspect();
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestSerializable.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSerializable.java
new file mode 100644
index 0000000..0a8275a
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSerializable.java
@@ -0,0 +1,57 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+import java.util.Vector;
+
+public class TestSerializable<A> implements DBusSerializable {
+ private int a;
+ private String b;
+ private Vector<Integer> c;
+
+ public TestSerializable(int a, A b, Vector<Integer> c) {
+ this.a = a;
+ this.b = b.toString();
+ this.c = c;
+ }
+
+ public TestSerializable() {
+ }
+
+ public void deserialize(int a, String b, List<Integer> c) {
+ this.a = a;
+ this.b = b;
+ this.c = new Vector<Integer>(c);
+ }
+
+ public Object[] serialize() throws DBusException {
+ return new Object[]{a, b, c};
+ }
+
+ public int getInt() {
+ return a;
+ }
+
+ public String getString() {
+ return b;
+ }
+
+ public Vector<Integer> getVector() {
+ return c;
+ }
+
+ public String toString() {
+ return "TestSerializable{" + a + "," + b + "," + c + "}";
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface.java
new file mode 100644
index 0000000..518a5db
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface.java
@@ -0,0 +1,89 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A sample signal with two parameters
+ */
+@Description("Test interface containing signals")
+public interface TestSignalInterface extends DBusInterface {
+ @Description("Test basic signal")
+ public static class TestSignal extends DBusSignal {
+ public final String value;
+ public final UInt32 number;
+
+ /**
+ * Create a signal.
+ */
+ public TestSignal(String path, String value, UInt32 number) throws DBusException {
+ super(path, value, number);
+ this.value = value;
+ this.number = number;
+ }
+ }
+
+ public static class StringSignal extends DBusSignal {
+ public final String aoeu;
+
+ public StringSignal(String path, String aoeu) throws DBusException {
+ super(path, aoeu);
+ this.aoeu = aoeu;
+ }
+ }
+
+ public static class EmptySignal extends DBusSignal {
+ public EmptySignal(String path) throws DBusException {
+ super(path);
+ }
+ }
+
+ @Description("Test signal with arrays")
+ public static class TestArraySignal extends DBusSignal {
+ public final List<TestStruct2> v;
+ public final Map<UInt32, TestStruct2> m;
+
+ public TestArraySignal(String path, List<TestStruct2> v, Map<UInt32, TestStruct2> m) throws DBusException {
+ super(path, v, m);
+ this.v = v;
+ this.m = m;
+ }
+ }
+
+ @Description("Test signal sending an object path")
+ @DBusMemberName("TestSignalObject")
+ public static class TestObjectSignal extends DBusSignal {
+ public final DBusInterface otherpath;
+
+ public TestObjectSignal(String path, DBusInterface otherpath) throws DBusException {
+ super(path, otherpath);
+ this.otherpath = otherpath;
+ }
+ }
+
+ public static class TestPathSignal extends DBusSignal {
+ public final Path otherpath;
+ public final List<Path> pathlist;
+ public final Map<Path, Path> pathmap;
+
+ public TestPathSignal(String path, Path otherpath, List<Path> pathlist, Map<Path, Path> pathmap) throws DBusException {
+ super(path, otherpath, pathlist, pathmap);
+ this.otherpath = otherpath;
+ this.pathlist = pathlist;
+ this.pathmap = pathmap;
+ }
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface2.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface2.java
new file mode 100644
index 0000000..9324b40
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestSignalInterface2.java
@@ -0,0 +1,36 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.DBus.Description;
+import org.freedesktop.dbus.exceptions.DBusException;
+
+/**
+ * A sample signal with two parameters
+ */
+@Description("Test interface containing signals")
+@DBusInterfaceName("some.other.interface.Name")
+public interface TestSignalInterface2 extends DBusInterface {
+ @Description("Test basic signal")
+ public static class TestRenamedSignal extends DBusSignal {
+ public final String value;
+ public final UInt32 number;
+
+ /**
+ * Create a signal.
+ */
+ public TestRenamedSignal(String path, String value, UInt32 number) throws DBusException {
+ super(path, value, number);
+ this.value = value;
+ this.number = number;
+ }
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct.java
new file mode 100644
index 0000000..09f42fc
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct.java
@@ -0,0 +1,26 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public final class TestStruct extends Struct {
+ @Position(0)
+ public final String a;
+ @Position(1)
+ public final UInt32 b;
+ @Position(2)
+ public final Variant<? extends Object> c;
+
+ public TestStruct(String a, UInt32 b, Variant<? extends Object> c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct2.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct2.java
new file mode 100644
index 0000000..efd0d87
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct2.java
@@ -0,0 +1,27 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+
+public final class TestStruct2 extends Struct {
+ @Position(0)
+ public final List<String> a;
+ @Position(1)
+ public final Variant<? extends Object> b;
+
+ public TestStruct2(List<String> a, Variant<? extends Object> b) throws DBusException {
+ this.a = a;
+ this.b = b;
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct3.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct3.java
new file mode 100644
index 0000000..d457053
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestStruct3.java
@@ -0,0 +1,27 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+import java.util.List;
+
+public final class TestStruct3 extends Struct {
+ @Position(0)
+ public final TestStruct2 a;
+ @Position(1)
+ public final List<List<Integer>> b;
+
+ public TestStruct3(TestStruct2 a, List<List<Integer>> b) throws DBusException {
+ this.a = a;
+ this.b = b;
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TestTuple.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TestTuple.java
new file mode 100644
index 0000000..4adb0d8
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TestTuple.java
@@ -0,0 +1,26 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public final class TestTuple<A, B, C> extends Tuple {
+ @Position(0)
+ public final A a;
+ @Position(1)
+ public final B b;
+ @Position(2)
+ public final C c;
+
+ public TestTuple(A a, B b, C c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_client.java b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_client.java
new file mode 100644
index 0000000..75f4bd8
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_client.java
@@ -0,0 +1,43 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public class two_part_test_client {
+ public static class two_part_test_object implements TwoPartObject {
+ public boolean isRemote() {
+ return false;
+ }
+
+ public String getName() {
+ System.out.println("client name");
+ return toString();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("get conn");
+ DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+ System.out.println("get remote");
+ TwoPartInterface remote = conn.getRemoteObject("org.freedesktop.dbus.test.two_part_server", "/", TwoPartInterface.class);
+ System.out.println("get object");
+ TwoPartObject o = remote.getNew();
+ System.out.println("get name");
+ System.out.println(o.getName());
+ two_part_test_object tpto = new two_part_test_object();
+ conn.exportObject("/TestObject", tpto);
+ conn.sendSignal(new TwoPartInterface.TwoPartSignal("/FromObject", tpto));
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException Ie) {
+ }
+ conn.disconnect();
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_server.java b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_server.java
new file mode 100644
index 0000000..c0b1ded
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/two_part_test_server.java
@@ -0,0 +1,62 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public class two_part_test_server implements TwoPartInterface, DBusSigHandler<TwoPartInterface.TwoPartSignal> {
+ public class two_part_test_object implements TwoPartObject {
+ public boolean isRemote() {
+ return false;
+ }
+
+ public String getName() {
+ System.out.println("give name");
+ return toString();
+ }
+ }
+
+ private DBusConnection conn;
+
+ public two_part_test_server(DBusConnection conn) {
+ this.conn = conn;
+ }
+
+ public boolean isRemote() {
+ return false;
+ }
+
+ public TwoPartObject getNew() {
+ TwoPartObject o = new two_part_test_object();
+ System.out.println("export new");
+ try {
+ conn.exportObject("/12345", o);
+ } catch (Exception e) {
+ }
+ System.out.println("give new");
+ return o;
+ }
+
+ public void handle(TwoPartInterface.TwoPartSignal s) {
+ System.out.println("Got: " + s.o);
+ }
+
+ public static void main(String[] args) throws Exception {
+ DBusConnection conn = DBusConnection.getConnection(DBusConnection.SESSION);
+ conn.requestBusName("org.freedesktop.dbus.test.two_part_server");
+ two_part_test_server server = new two_part_test_server(conn);
+ conn.exportObject("/", server);
+ conn.addSigHandler(TwoPartInterface.TwoPartSignal.class, server);
+ while (true) try {
+ Thread.sleep(10000);
+ } catch (InterruptedException Ie) {
+ }
+ }
+}
+
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartInterface.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartInterface.java
new file mode 100644
index 0000000..242dcb2
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartInterface.java
@@ -0,0 +1,26 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+import org.freedesktop.dbus.exceptions.DBusException;
+
+public interface TwoPartInterface extends DBusInterface {
+ public TwoPartObject getNew();
+
+ public class TwoPartSignal extends DBusSignal {
+ public final TwoPartObject o;
+
+ public TwoPartSignal(String path, TwoPartObject o) throws DBusException {
+ super(path, o);
+ this.o = o;
+ }
+ }
+}
diff --git a/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartObject.java b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartObject.java
new file mode 100644
index 0000000..8f03bbc
--- /dev/null
+++ b/federation/sssd/src/test/java/org/freedesktop/dbus/TwoPartObject.java
@@ -0,0 +1,15 @@
+/*
+ D-Bus Java Implementation
+ Copyright (c) 2005-2006 Matthew Johnson
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of either the GNU Lesser General Public License Version 2 or the
+ Academic Free Licence Version 2.1.
+
+ Full licence texts are included in the COPYING file with this program.
+*/
+package org.freedesktop.dbus;
+
+public interface TwoPartObject extends DBusInterface {
+ public String getName();
+}
diff --git a/federation/sssd/src/test/java/org/jvnet/libpam/InteractiveTester.java b/federation/sssd/src/test/java/org/jvnet/libpam/InteractiveTester.java
new file mode 100644
index 0000000..47fef18
--- /dev/null
+++ b/federation/sssd/src/test/java/org/jvnet/libpam/InteractiveTester.java
@@ -0,0 +1,95 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class InteractiveTester extends TestCase {
+ public InteractiveTester(String testName) {
+ super(testName);
+ }
+
+ public void testPositiveCase() throws Exception {
+ for (int i = 0; i < 1000; i++)
+ testOne();
+ }
+
+ public void testOne() throws Exception {
+ UnixUser u = new PAM("sshd").authenticate(System.getProperty("user.name"), System.getProperty("password"));
+ if (!printOnce) {
+ System.out.println(u.getUID());
+ System.out.println(u.getGroups());
+ printOnce = true;
+ }
+ }
+
+ public void testGetGroups() throws Exception {
+ System.out.println(new PAM("sshd").getGroupsOfUser(System.getProperty("user.name")));
+ }
+
+ public void testConcurrent() throws Exception {
+ ExecutorService es = Executors.newFixedThreadPool(10);
+ Set<Future<?>> result = new HashSet<Future<?>>();
+ for (int i = 0; i < 1000; i++) {
+ result.add(es.submit(new Callable<Object>() {
+ public Object call() throws Exception {
+ testOne();
+ return null;
+ }
+ }));
+ }
+ // wait for completion
+ for (Future<?> f : result) {
+ f.get();
+ }
+ es.shutdown();
+ }
+
+ public void testNegative() throws Exception {
+ try {
+ new PAM("sshd").authenticate("bogus", "bogus");
+ fail("expected a failure");
+ } catch (PAMException e) {
+ // yep
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ UnixUser u = new PAM("sshd").authenticate(args[0], args[1]);
+ System.out.println(u.getUID());
+ System.out.println(u.getGroups());
+ System.out.println(u.getGecos());
+ System.out.println(u.getDir());
+ System.out.println(u.getShell());
+ }
+
+ private boolean printOnce;
+}
diff --git a/federation/sssd/src/test/java/org/jvnet/libpam/UnixUserTest.java b/federation/sssd/src/test/java/org/jvnet/libpam/UnixUserTest.java
new file mode 100644
index 0000000..4b3e5f5
--- /dev/null
+++ b/federation/sssd/src/test/java/org/jvnet/libpam/UnixUserTest.java
@@ -0,0 +1,52 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2014, R. Tyler Croy
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.jvnet.libpam;
+
+import junit.framework.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class UnixUserTest {
+ private UnixUser user = null;
+
+ @Before
+ public void setUp() throws PAMException {
+ user = new UnixUser("root");
+ }
+
+ @Test
+ public void testGetUserName() {
+ Assert.assertEquals("root", user.getUserName());
+ }
+
+ @Test
+ public void testGetDir() {
+ Assert.assertNotNull(user.getDir());
+ }
+
+ @Test
+ public void testGetUID() {
+ Assert.assertEquals(0, user.getUID());
+ }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
index 2b5d35c..16b155b 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
@@ -43,6 +43,7 @@ import java.util.Set;
@NamedQuery(name="getAttributesByNameAndValue", query="select attr from UserAttributeEntity attr where attr.name = :name and attr.value = :value"),
@NamedQuery(name="deleteUserAttributesByRealm", query="delete from UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId)"),
@NamedQuery(name="deleteUserAttributesByNameAndUser", query="delete from UserAttributeEntity attr where attr.user.id = :userId and attr.name = :name"),
+ @NamedQuery(name="deleteUserAttributesOtherThan", query="delete from UserAttributeEntity attr where attr.user.id = :userId and attr.id <> :attrId"),
@NamedQuery(name="deleteUserAttributesByRealmAndLink", query="delete from UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
})
@Table(name="USER_ATTRIBUTE")
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 2ea12fd..49bcac6 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -125,29 +125,32 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
@Override
public void setSingleAttribute(String name, String value) {
- boolean found = false;
+ String firstExistingAttrId = null;
List<UserAttributeEntity> toRemove = new ArrayList<>();
for (UserAttributeEntity attr : user.getAttributes()) {
if (attr.getName().equals(name)) {
- if (!found) {
+ if (firstExistingAttrId == null) {
attr.setValue(value);
- found = true;
+ firstExistingAttrId = attr.getId();
} else {
toRemove.add(attr);
}
}
}
- for (UserAttributeEntity attr : toRemove) {
- em.remove(attr);
- user.getAttributes().remove(attr);
- }
+ if (firstExistingAttrId != null) {
+ // Remove attributes through HQL to avoid StaleUpdateException
+ Query query = em.createNamedQuery("deleteUserAttributesOtherThan");
+ query.setParameter("attrId", firstExistingAttrId);
+ query.setParameter("userId", user.getId());
+ int numUpdated = query.executeUpdate();
- if (found) {
- return;
- }
+ // Remove attribute from local entity
+ user.getAttributes().removeAll(toRemove);
+ } else {
- persistAttributeValue(name, value);
+ persistAttributeValue(name, value);
+ }
}
@Override
@@ -178,6 +181,15 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
query.setParameter("name", name);
query.setParameter("userId", user.getId());
int numUpdated = query.executeUpdate();
+
+ // KEYCLOAK-3494 : Also remove attributes from local user entity
+ List<UserAttributeEntity> toRemove = new ArrayList<>();
+ for (UserAttributeEntity attr : user.getAttributes()) {
+ if (attr.getName().equals(name)) {
+ toRemove.add(attr);
+ }
+ }
+ user.getAttributes().removeAll(toRemove);
}
@Override
pom.xml 12(+12 -0)
diff --git a/pom.xml b/pom.xml
index 7208837..48e8a65 100755
--- a/pom.xml
+++ b/pom.xml
@@ -94,6 +94,7 @@
<mariadb.version>1.3.7</mariadb.version>
<servlet.api.30.version>1.0.2.Final</servlet.api.30.version>
<twitter4j.version>4.0.4</twitter4j.version>
+ <jna.version>4.1.0</jna.version>
<!-- Test -->
<greenmail.version>1.3.1b</greenmail.version>
@@ -685,6 +686,17 @@
<artifactId>keycloak-kerberos-federation</artifactId>
<version>${project.version}</version>
</dependency>
+ <!-- Dependencies for RHEL IdM -->
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-sssd-federation</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ <version>${jna.version}</version>
+ </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-ldap-federation</artifactId>
diff --git a/server-spi/src/main/java/org/keycloak/models/Constants.java b/server-spi/src/main/java/org/keycloak/models/Constants.java
index 916565a..42982f6 100755
--- a/server-spi/src/main/java/org/keycloak/models/Constants.java
+++ b/server-spi/src/main/java/org/keycloak/models/Constants.java
@@ -50,5 +50,5 @@ public interface Constants {
String KEY = "key";
// Prefix for user attributes used in various "context"data maps
- public static final String USER_ATTRIBUTES_PREFIX = "user.attributes.";
+ String USER_ATTRIBUTES_PREFIX = "user.attributes.";
}
diff --git a/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java b/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java
index acb1514..857bfc0 100755
--- a/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java
+++ b/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountBean.java
@@ -18,6 +18,7 @@
package org.keycloak.forms.account.freemarker.model;
import org.jboss.logging.Logger;
+import org.keycloak.models.Constants;
import org.keycloak.models.UserModel;
import javax.ws.rs.core.MultivaluedMap;
@@ -55,8 +56,8 @@ public class AccountBean {
if (profileFormData != null) {
for (String key : profileFormData.keySet()) {
- if (key.startsWith("user.attributes.")) {
- String attribute = key.substring("user.attributes.".length());
+ if (key.startsWith(Constants.USER_ATTRIBUTES_PREFIX)) {
+ String attribute = key.substring(Constants.USER_ATTRIBUTES_PREFIX.length());
attributes.put(attribute, profileFormData.getFirst(key));
}
}
testsuite/integration/pom.xml 8(+8 -0)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index aca1d78..92187bc 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -166,6 +166,14 @@
<groupId>org.keycloak</groupId>
<artifactId>federation-properties-example</artifactId>
</dependency>
+
+ <!-- Dependency on services from integration-arquillian -->
+ <dependency>
+ <groupId>org.keycloak.testsuite</groupId>
+ <artifactId>integration-arquillian-testsuite-providers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
index 7683d0c..f6a85e4 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
@@ -45,8 +45,8 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.Urls;
-import org.keycloak.testsuite.DummyUserFederationProviderFactory;
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
+import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java
index 5d327f4..3831787 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncDummyUserFederationProviderFactory.java
@@ -32,7 +32,7 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserFederationSyncResult;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.testsuite.DummyUserFederationProviderFactory;
+import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
index 84a901a..efa688c 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java
@@ -36,7 +36,7 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserFederationSyncResult;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.UsersSyncManager;
-import org.keycloak.testsuite.DummyUserFederationProviderFactory;
+import org.keycloak.testsuite.federation.DummyUserFederationProviderFactory;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.timer.TimerProvider;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
index b3ad0c4..2fb2aaf 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
@@ -17,6 +17,7 @@
package org.keycloak.testsuite.model;
+import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
@@ -151,14 +152,17 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
}
- // KEYCLOAK-3296
+ // KEYCLOAK-3296 , KEYCLOAK-3494
@Test
public void removeUserAttribute() throws Exception {
RealmModel realm = realmManager.createRealm("original");
KeycloakSession session = realmManager.getSession();
- UserModel user = session.users().addUser(realm, "john");
- user.setSingleAttribute("foo", "val1");
+ UserModel john = session.users().addUser(realm, "john");
+ john.setSingleAttribute("foo", "val1");
+
+ UserModel john2 = session.users().addUser(realm, "john2");
+ john2.setAttribute("foo", Arrays.asList("val1", "val2"));
final KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
commit();
@@ -182,12 +186,18 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
UserModel john = session.users().getUserByUsername("john", realm);
String attrVal = john.getFirstAttribute("foo");
+ UserModel john2 = session.users().getUserByUsername("john2", realm);
+ String attrVal2 = john2.getFirstAttribute("foo");
+
// Wait until it's read in both threads
readAttrLatch.countDown();
readAttrLatch.await();
- // Remove user attribute in both threads
+ // KEYCLOAK-3296 : Remove user attribute in both threads
john.removeAttribute("foo");
+
+ // KEYCLOAK-3494 : Set single attribute in both threads
+ john2.setSingleAttribute("foo", "bar");
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
index 4b3f78e..e2af241 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
@@ -211,6 +211,31 @@ public class UserModelTest extends AbstractModelTest {
Assert.assertEquals("val23", attrVals.get(0));
}
+ // KEYCLOAK-3494
+ @Test
+ public void testUpdateUserAttribute() throws Exception {
+ RealmModel realm = realmManager.createRealm("original");
+ UserModel user = session.users().addUser(realm, "user");
+
+ user.setSingleAttribute("key1", "value1");
+
+ commit();
+
+ realm = realmManager.getRealmByName("original");
+ user = session.users().getUserByUsername("user", realm);
+
+ // Update attribute
+ List<String> attrVals = new ArrayList<>(Arrays.asList( "val2" ));
+ user.setAttribute("key1", attrVals);
+ Map<String, List<String>> allAttrVals = user.getAttributes();
+
+ // Ensure same transaction is able to see updated value
+ Assert.assertEquals(1, allAttrVals.size());
+ Assert.assertEquals(allAttrVals.get("key1"), Arrays.asList("val2"));
+
+ commit();
+ }
+
@Test
public void testSearchByString() {
RealmModel realm = realmManager.createRealm("original");
diff --git a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
index 1b4de73..d4a16d3 100755
--- a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
+++ b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.models.UserFederationProviderFactory
@@ -15,5 +15,4 @@
# limitations under the License.
#
-org.keycloak.testsuite.DummyUserFederationProviderFactory
org.keycloak.testsuite.federation.sync.SyncDummyUserFederationProviderFactory
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl
index f32c036..664eecb 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-server-subsystem.xsl
@@ -36,6 +36,11 @@
</provider>
</spi>
</xsl:variable>
+ <xsl:variable name="themeModuleDefinition">
+ <modules>
+ <module>org.keycloak.testsuite.integration-arquillian-testsuite-providers</module>
+ </modules>
+ </xsl:variable>
<!--inject provider-->
<xsl:template match="//*[local-name()='providers']/*[local-name()='provider']">
@@ -46,6 +51,14 @@
<xsl:text>module:org.keycloak.testsuite.integration-arquillian-testsuite-providers</xsl:text>
</provider>
</xsl:template>
+
+ <!--inject provider for themes -->
+ <xsl:template match="//*[local-name()='theme']">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ <xsl:copy-of select="$themeModuleDefinition"/>
+ </xsl:copy>
+ </xsl:template>
<!--inject truststore-->
<xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $nsKS)]">
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json
new file mode 100644
index 0000000..03978db
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/keycloak-themes.json
@@ -0,0 +1,6 @@
+{
+ "themes": [{
+ "name" : "address",
+ "types": [ "admin", "account", "login" ]
+ }]
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl
new file mode 100755
index 0000000..d2a6af1
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/account.ftl
@@ -0,0 +1,114 @@
+<#import "template.ftl" as layout>
+<@layout.mainLayout active='account' bodyClass='user'; section>
+
+ <div class="row">
+ <div class="col-md-10">
+ <h2>${msg("editAccountHtmlTtile")}</h2>
+ </div>
+ <div class="col-md-2 subtitle">
+ <span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
+ </div>
+ </div>
+
+ <form action="${url.accountUrl}" class="form-horizontal" method="post">
+
+ <input type="hidden" id="stateChecker" name="stateChecker" value="${stateChecker}">
+
+ <div class="form-group ${messagesPerField.printIfExists('username','has-error')}">
+ <div class="col-sm-2 col-md-2">
+ <label for="username" class="control-label">${msg("username")}</label> <#if realm.editUsernameAllowed><span class="required">*</span></#if>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="username" name="username" <#if !realm.editUsernameAllowed>disabled="disabled"</#if> value="${(account.username!'')?html}"/>
+ </div>
+ </div>
+
+ <div class="form-group ${messagesPerField.printIfExists('email','has-error')}">
+ <div class="col-sm-2 col-md-2">
+ <label for="email" class="control-label">${msg("email")}</label> <span class="required">*</span>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="email" name="email" autofocus value="${(account.email!'')?html}"/>
+ </div>
+ </div>
+
+ <div class="form-group ${messagesPerField.printIfExists('firstName','has-error')}">
+ <div class="col-sm-2 col-md-2">
+ <label for="firstName" class="control-label">${msg("firstName")}</label> <span class="required">*</span>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="firstName" name="firstName" value="${(account.firstName!'')?html}"/>
+ </div>
+ </div>
+
+ <div class="form-group ${messagesPerField.printIfExists('lastName','has-error')}">
+ <div class="col-sm-2 col-md-2">
+ <label for="lastName" class="control-label">${msg("lastName")}</label> <span class="required">*</span>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="lastName" name="lastName" value="${(account.lastName!'')?html}"/>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="col-sm-2 col-md-2">
+ <label for="user.attributes.street" class="control-label">${msg("street")}</label>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="user.attributes.street" name="user.attributes.street" value="${(account.attributes.street!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-2 col-md-2">
+ <label for="user.attributes.locality" class="control-label">${msg("locality")}</label>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="user.attributes.locality" name="user.attributes.locality" value="${(account.attributes.locality!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-2 col-md-2">
+ <label for="user.attributes.region" class="control-label">${msg("region")}</label>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="user.attributes.region" name="user.attributes.region" value="${(account.attributes.region!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-2 col-md-2">
+ <label for="user.attributes.postal_code" class="control-label">${msg("postal_code")}</label>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(account.attributes.postal_code!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-2 col-md-2">
+ <label for="user.attributes.country" class="control-label">${msg("country")}</label>
+ </div>
+
+ <div class="col-sm-10 col-md-10">
+ <input type="text" class="form-control" id="user.attributes.country" name="user.attributes.country" value="${(account.attributes.country!'')?html}"/>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
+ <div class="">
+ <#if url.referrerURI??><a href="${url.referrerURI}">${msg("backToApplication")}/a></#if>
+ <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Save">${msg("doSave")}</button>
+ <button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="Cancel">${msg("doCancel")}</button>
+ </div>
+ </div>
+ </div>
+ </form>
+
+</@layout.mainLayout>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties
new file mode 100644
index 0000000..3e50437
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/account/theme.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+parent=keycloak
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html
new file mode 100755
index 0000000..af512de
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/resources/partials/user-attributes.html
@@ -0,0 +1,72 @@
+<!--
+ ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+ ~ and other contributors as indicated by the @author tags.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+ <ol class="breadcrumb">
+ <li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
+ <li>{{user.username}}</li>
+ </ol>
+
+ <kc-tabs-user></kc-tabs-user>
+
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageUsers">
+ <div class="form-group clearfix block">
+ <label class="col-md-2 control-label" for="street">Street</label>
+ <div class="col-md-6">
+ <input ng-model="user.attributes.street" class="form-control" type="text" name="street" id="street" />
+ </div>
+ <kc-tooltip>Street address.</kc-tooltip>
+ </div>
+ <div class="form-group clearfix block">
+ <label class="col-md-2 control-label" for="locality">City or Locality</label>
+ <div class="col-md-6">
+ <input ng-model="user.attributes.locality" class="form-control" type="text" name="locality" id="locality" />
+ </div>
+ <kc-tooltip>City or locality.</kc-tooltip>
+ </div>
+ <div class="form-group clearfix block">
+ <label class="col-md-2 control-label" for="region">State, Province, or Region</label>
+ <div class="col-md-6">
+ <input ng-model="user.attributes.region" class="form-control" type="text" name="region" id="region" />
+ </div>
+ <kc-tooltip>State, province, prefecture, or region.</kc-tooltip>
+ </div>
+ <div class="form-group clearfix block">
+ <label class="col-md-2 control-label" for="postal_code">Zip or Postal code</label>
+ <div class="col-md-6">
+ <input ng-model="user.attributes.postal_code" class="form-control" type="text" name="postal_code" id="postal_code" />
+ </div>
+ <kc-tooltip>Zip code or postal code.</kc-tooltip>
+ </div>
+ <div class="form-group clearfix block">
+ <label class="col-md-2 control-label" for="country">Country</label>
+ <div class="col-md-6">
+ <input ng-model="user.attributes.country" class="form-control" type="text" name="country" id="country" />
+ </div>
+ <kc-tooltip>Country name.</kc-tooltip>
+ </div>
+
+ <div class="form-group" data-ng-show="access.manageUsers">
+ <div class="col-md-10 col-md-offset-2">
+ <button kc-save data-ng-disabled="!changed">Save</button>
+ <button kc-reset data-ng-disabled="!changed">Cancel</button>
+ </div>
+ </div>
+ </form>
+</div>
+
+<kc-menu></kc-menu>
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties
new file mode 100644
index 0000000..3e50437
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/admin/theme.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+parent=keycloak
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl
new file mode 100755
index 0000000..e02a340
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/login-update-profile.ftl
@@ -0,0 +1,95 @@
+<#import "template.ftl" as layout>
+<@layout.registrationLayout; section>
+ <#if section = "title">
+ ${msg("loginProfileTitle")}
+ <#elseif section = "header">
+ ${msg("loginProfileTitle")}
+ <#elseif section = "form">
+ <form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('email',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" id="email" name="email" value="${(user.email!'')?html}" class="${properties.kcInputClass!}" />
+ </div>
+ </div>
+
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('firstName',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" id="firstName" name="firstName" value="${(user.firstName!'')?html}" class="${properties.kcInputClass!}" />
+ </div>
+ </div>
+
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('lastName',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" id="lastName" name="lastName" value="${(user.lastName!'')?html}" class="${properties.kcInputClass!}" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.street" class="${properties.kcLabelClass!}">${msg("street")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.street" name="user.attributes.street" value="${(user.attributes.street!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.locality" class="${properties.kcLabelClass!}">${msg("locality")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.locality" name="user.attributes.locality" value="${(user.attributes.locality!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.region" class="${properties.kcLabelClass!}">${msg("region")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.region" name="user.attributes.region" value="${(user.attributes.region!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${msg("postal_code")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(user.attributes.postal_code!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.country" class="${properties.kcLabelClass!}">${msg("country")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.country" name="user.attributes.country" value="${(user.attributes.country!'')?html}"/>
+ </div>
+ </div>
+
+
+ <div class="${properties.kcFormGroupClass!}">
+ <div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
+ <div class="${properties.kcFormOptionsWrapperClass!}">
+ </div>
+ </div>
+
+ <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
+ <input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
+ </div>
+ </div>
+ </form>
+ </#if>
+</@layout.registrationLayout>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl
new file mode 100755
index 0000000..3247305
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/register.ftl
@@ -0,0 +1,131 @@
+<#import "template.ftl" as layout>
+<@layout.registrationLayout; section>
+ <#if section = "title">
+ ${msg("registerWithTitle",(realm.name!''))}
+ <#elseif section = "header">
+ ${msg("registerWithTitleHtml",(realm.name!''))}
+ <#elseif section = "form">
+ <form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post">
+ <#if !realm.registrationEmailAsUsername>
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('username',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="username" class="${properties.kcLabelClass!}">${msg("username")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" id="username" class="${properties.kcInputClass!}" name="username" value="${(register.formData.username!'')?html}" />
+ </div>
+ </div>
+ </#if>
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('firstName',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="firstName" class="${properties.kcLabelClass!}">${msg("firstName")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" id="firstName" class="${properties.kcInputClass!}" name="firstName" value="${(register.formData.firstName!'')?html}" />
+ </div>
+ </div>
+
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('lastName',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="lastName" class="${properties.kcLabelClass!}">${msg("lastName")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" id="lastName" class="${properties.kcInputClass!}" name="lastName" value="${(register.formData.lastName!'')?html}" />
+ </div>
+ </div>
+
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('email',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="email" class="${properties.kcLabelClass!}">${msg("email")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" id="email" class="${properties.kcInputClass!}" name="email" value="${(register.formData.email!'')?html}" />
+ </div>
+ </div>
+
+ <#if passwordRequired>
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('password',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="password" id="password" class="${properties.kcInputClass!}" name="password" />
+ </div>
+ </div>
+
+ <div class="${properties.kcFormGroupClass!} ${messagesPerField.printIfExists('password-confirm',properties.kcFormGroupErrorClass!)}">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="password-confirm" class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label>
+ </div>
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="password" id="password-confirm" class="${properties.kcInputClass!}" name="password-confirm" />
+ </div>
+ </div>
+ </#if>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.street" class="${properties.kcLabelClass!}">${msg("street")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.street" name="user.attributes.street" value="${(register.formData['user.attributes.street']!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.locality" class="${properties.kcLabelClass!}">${msg("locality")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.locality" name="user.attributes.locality" value="${(register.formData['user.attributes.locality']!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.region" class="${properties.kcLabelClass!}">${msg("region")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.region" name="user.attributes.region" value="${(register.formData['user.attributes.region']!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${msg("postal_code")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(register.formData['user.attributes.postal_code']!'')?html}"/>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="${properties.kcLabelWrapperClass!}">
+ <label for="user.attributes.country" class="${properties.kcLabelClass!}">${msg("country")}</label>
+ </div>
+
+ <div class="${properties.kcInputWrapperClass!}">
+ <input type="text" class="${properties.kcInputClass!}" id="user.attributes.country" name="user.attributes.country" value="${(register.formData['user.attributes.country']!'')?html}"/>
+ </div>
+ </div>
+ <#if recaptchaRequired??>
+ <div class="form-group">
+ <div class="${properties.kcInputWrapperClass!}">
+ <div class="g-recaptcha" data-size="compact" data-sitekey="${recaptchaSiteKey}"></div>
+ </div>
+ </div>
+ </#if>
+
+ <div class="${properties.kcFormGroupClass!}">
+ <div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
+ <div class="${properties.kcFormOptionsWrapperClass!}">
+ <span><a href="${url.loginUrl}">${msg("backToLogin")}</a></span>
+ </div>
+ </div>
+
+ <div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
+ <input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doRegister")}"/>
+ </div>
+ </div>
+ </form>
+ </#if>
+</@layout.registrationLayout>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties
new file mode 100644
index 0000000..3e50437
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/theme/address/login/theme.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+parent=keycloak
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
index 2159c2f..2a77847 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
@@ -17,7 +17,9 @@
package org.keycloak.testsuite.pages;
+import org.keycloak.models.Constants;
import org.keycloak.services.resources.RealmsResource;
+import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@@ -96,6 +98,14 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
submitButton.click();
}
+ public void updateAttribute(String attrName, String attrValue) {
+ WebElement attrElement = findAttributeInputElement(attrName);
+ attrElement.clear();
+ attrElement.sendKeys(attrValue);
+ submitButton.click();
+ }
+
+
public void clickCancel() {
cancelButton.click();
}
@@ -117,6 +127,11 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
return emailInput.getAttribute("value");
}
+ public String getAttribute(String attrName) {
+ WebElement attrElement = findAttributeInputElement(attrName);
+ return attrElement.getAttribute("value");
+ }
+
public boolean isCurrent() {
return driver.getTitle().contains("Account Management") && driver.getPageSource().contains("Edit Account");
}
@@ -140,4 +155,9 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
public boolean isPasswordUpdateSupported() {
return driver.getPageSource().contains(getPath() + "/password");
}
+
+ private WebElement findAttributeInputElement(String attrName) {
+ String attrId = Constants.USER_ATTRIBUTES_PREFIX + attrName;
+ return driver.findElement(By.id(attrId));
+ }
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/CustomThemeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/CustomThemeTest.java
new file mode 100644
index 0000000..810d9c2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/CustomThemeTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.account.custom;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventType;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.account.AccountTest;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CustomThemeTest extends TestRealmKeycloakTest {
+
+ @Override
+ public void configureTestRealm(RealmRepresentation testRealm) {
+ testRealm.setAccountTheme("address");
+
+ UserRepresentation user2 = UserBuilder.create()
+ .enabled(true)
+ .username("test-user-no-access@localhost")
+ .email("test-user-no-access@localhost")
+ .password("password")
+ .build();
+
+ RealmBuilder.edit(testRealm)
+ .user(user2);
+ }
+
+ @Rule
+ public AssertEvents events = new AssertEvents(this);
+
+ @Page
+ protected LoginPage loginPage;
+
+ @Page
+ protected AccountUpdateProfilePage profilePage;
+
+ // KEYCLOAK-3494
+ @Test
+ public void changeProfile() throws Exception {
+ profilePage.open();
+ loginPage.login("test-user@localhost", "password");
+
+ events.expectLogin().client("account").detail(Details.REDIRECT_URI, AccountTest.ACCOUNT_REDIRECT).assertEvent();
+
+ Assert.assertEquals("test-user@localhost", profilePage.getEmail());
+ Assert.assertEquals("", profilePage.getAttribute("street"));
+
+ profilePage.updateAttribute("street", "Elm 1");
+ Assert.assertEquals("Elm 1", profilePage.getAttribute("street"));
+
+ profilePage.updateAttribute("street", "Elm 2");
+ Assert.assertEquals("Elm 2", profilePage.getAttribute("street"));
+
+ events.expectAccount(EventType.UPDATE_PROFILE).assertEvent();
+ }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
index 8cef8a1..7a939c3 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
@@ -51,7 +51,7 @@ public class UserFederationTest extends AbstractAdminTest {
@Test
public void testProviderFactories() {
List<UserFederationProviderFactoryRepresentation> providerFactories = userFederation().getProviderFactories();
- Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable");
+ Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable", "sssd");
// Builtin provider without properties
UserFederationProviderFactoryRepresentation ldapProvider = userFederation().getProviderFactory("ldap");