aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamian Minkov <damencho@jitsi.org>2010-08-10 07:23:45 +0000
committerDamian Minkov <damencho@jitsi.org>2010-08-10 07:23:45 +0000
commit9c1c17dff9ae4b6a803b48e5203311a0f3f94b08 (patch)
tree72fdd92f39cd0012ee2312c9596399a5fd2b07b1
parent411c4d9f013331950967665d41b103be6ebe8cba (diff)
downloadjitsi-9c1c17dff9ae4b6a803b48e5203311a0f3f94b08.zip
jitsi-9c1c17dff9ae4b6a803b48e5203311a0f3f94b08.tar.gz
jitsi-9c1c17dff9ae4b6a803b48e5203311a0f3f94b08.tar.bz2
Merge changes from branch/gsoc10/xcap and patch sent to dev mailinglist with subject "XCAP tests" which represents the work of Grigorii Balutsel on the "XCAP Support" GSoC 2010 project into trunk.
-rw-r--r--build.xml49
-rw-r--r--lib/accounts.properties.template7
-rw-r--r--lib/bundle/httpcore.jarbin173054 -> 0 bytes
-rw-r--r--lib/felix.client.run.properties3
-rw-r--r--lib/felix.unit.test.properties3
-rw-r--r--lib/installer-exclude/httpclient-4.0-beta2.jarbin276220 -> 0 bytes
-rw-r--r--lib/installer-exclude/httpclient-4.0.1.jarbin0 -> 291039 bytes
-rw-r--r--resources/languages/resources.properties9
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java121
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java159
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java474
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java450
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java143
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ServerStoredContactListSipImpl.java1234
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf41
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/BaseHttpXCapClient.java483
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/HttpXCapClient.java105
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/PresContentClient.java88
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/PresRulesClient.java64
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/ResourceListsClient.java81
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapCapsClient.java39
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClient.java41
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClientImpl.java751
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapException.java63
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapHttpResponse.java115
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResource.java77
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResourceId.java118
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/ParsingException.java63
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/StringUtils.java95
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/XmlUtils.java299
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ActionsType.java86
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ConditionsType.java63
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ExceptType.java83
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/IdentityType.java109
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ManyType.java104
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/OneType.java91
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RuleType.java141
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RulesetType.java74
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/SphereType.java55
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/TransfomationsType.java120
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ValidityType.java75
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/common-policy.xsd106
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/ContentType.java173
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DataType.java60
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DescriptionType.java114
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/EncodingType.java60
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/MimeType.java60
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/PresContentParser.java476
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/pres-content.xsd144
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideAllAttributes.java22
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideDevicePermission.java78
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvidePersonPermission.java82
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideServicePermission.java86
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/SubHandlingType.java70
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/UnknownBooleanPermission.java100
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/pres-rules.xsd124
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/DisplayNameType.java86
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryRefType.java129
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryType.java149
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ExternalType.java106
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ListType.java202
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsParser.java716
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsType.java38
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/resource-lists.xsd81
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/AuidsType.java38
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/ExtensionsType.java38
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/NamespacesType.java38
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsParser.java324
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsType.java112
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/xcap-caps.xsd69
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/BaseXCapError.java50
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotDeleteType.java28
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotInsertType.java29
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ConstraintFailureType.java29
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ExtensionType.java51
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NoParentType.java64
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotUtf8Type.java28
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotWellFormedType.java28
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlAttValueType.java28
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlFragType.java29
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/SchemaValidationErrorType.java28
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/UniquenessFailureType.java118
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapError.java22
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorParser.java514
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorType.java42
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/xcap-error.xsd187
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/xcap/utils/StreamUtils.java66
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java257
-rwxr-xr-xsrc/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java111
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java28
-rw-r--r--src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java59
-rw-r--r--src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java6
-rw-r--r--test/net/java/sip/communicator/slick/protocol/sip/SipProtocolProviderServiceLick.java13
-rw-r--r--test/net/java/sip/communicator/slick/protocol/sip/TestAccountInstallation.java21
-rw-r--r--test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfo.java356
-rw-r--r--test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfoData.java175
-rw-r--r--test/net/java/sip/communicator/slick/protocol/sip/TestXCapParse.java503
-rw-r--r--test/net/java/sip/communicator/slick/protocol/sip/sip.provider.slick.manifest.mf13
98 files changed, 12623 insertions, 317 deletions
diff --git a/build.xml b/build.xml
index 099600f..359bd8f 100644
--- a/build.xml
+++ b/build.xml
@@ -897,6 +897,7 @@
bundle-plugin-icqaccregwizz,bundle-plugin-jabberaccregwizz,
bundle-plugin-msnaccregwizz,bundle-plugin-sipaccregwizz,
bundle-plugin-yahooaccregwizz,bundle-plugin-aimaccregwizz,
+ bundle-httpcore,bundle-httpclient,
bundle-version,bundle-version-impl,bundle-shutdown-timeout,
bundle-growlnotification,bundle-swingnotification,bundle-galagonotification,
bundle-sparkle, bundle-plugin-branding, bundle-audionotifier,
@@ -1909,7 +1910,7 @@ javax.swing.event, javax.swing.border"/>
<!--BUNDLE-HTTPCORE -->
<target name="bundle-httpcore">
- <jar compress="true" destfile="lib/bundle/httpcore.jar"
+ <jar compress="true" destfile="${bundles.dest}/httpcore.jar"
filesetmanifest="merge">
<zipfileset src="${lib.noinst}/httpcore-4.0.1.jar" prefix=""/>
<manifest>
@@ -1935,6 +1936,52 @@ org.apache.http.util"/>
</jar>
</target>
+ <!--BUNDLE-HTTPCLIENT -->
+ <target name="bundle-httpclient">
+ <jar compress="true" destfile="${bundles.dest}/httpclient.jar"
+ filesetmanifest="merge">
+ <zipfileset src="${lib.noinst}/httpclient-4.0.1.jar" prefix=""/>
+ <manifest>
+ <attribute name="Export-Package"
+ value="org.apache.http.annotation,
+org.apache.http.auth,
+org.apache.http.auth.params,
+org.apache.http.client,
+org.apache.http.client.entity,
+org.apache.http.client.methods,
+org.apache.http.client.params,
+org.apache.http.client.protocol,
+org.apache.http.client.utils,
+org.apache.http.conn,
+org.apache.http.conn.params,
+org.apache.http.conn.routing,
+org.apache.http.conn.scheme,
+org.apache.http.conn.ssl,
+org.apache.http.conn.util,
+org.apache.http.impl.client"/>
+ <attribute name="Import-Package"
+ value="org.apache.commons.logging,
+javax.net.ssl,
+javax.security.auth.x500,
+org.apache.http,
+org.apache.http.entity,
+org.apache.http.impl,
+org.apache.http.impl.entity,
+org.apache.http.impl.io,
+org.apache.http.io,
+org.apache.http.message,
+org.apache.http.params,
+org.apache.http.protocol,
+org.apache.http.util"/>
+ <attribute name="Bundle-Name"
+ value="Apache HttpComponents Client"/>
+ <attribute name="Bundle-Description"
+ value="A set of low level HTTP transport components."/>
+ <attribute name="System-Bundle" value="yes"/>
+ </manifest>
+ </jar>
+ </target>
+
<!-- BUNDLE-NOTIFICATION -->
<target name="bundle-notification">
<!-- Creates a bundle for the notifications.-->
diff --git a/lib/accounts.properties.template b/lib/accounts.properties.template
index 5dd1ac9..4e3b537 100644
--- a/lib/accounts.properties.template
+++ b/lib/accounts.properties.template
@@ -85,6 +85,9 @@ accounts.sip.account1.PROXY_ADDRESS=
# (Optional)
accounts.sip.account1.PROXY_PORT=
+# The XCAP server uri
+# (Optional)
+accounts.sip.account1.XCAP_SERVER=
# ACCOUNT 2
# The user id needed to log onto the server specified in the SERVER_ADDRESS
@@ -113,6 +116,10 @@ accounts.sip.account2.PROXY_ADDRESS=
# (Optional)
accounts.sip.account2.PROXY_PORT=
+# The XCAP server uri
+# (Optional)
+accounts.sip.account2.XCAP_SERVER=
+
# This will be the contact list which we will use to test persistent storing
# of sip protocol
accounts.sip.CONTACT_LIST=
diff --git a/lib/bundle/httpcore.jar b/lib/bundle/httpcore.jar
deleted file mode 100644
index 0dc8446..0000000
--- a/lib/bundle/httpcore.jar
+++ /dev/null
Binary files differ
diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties
index 4a7081e..d373ab8 100644
--- a/lib/felix.client.run.properties
+++ b/lib/felix.client.run.properties
@@ -57,7 +57,8 @@ felix.auto.start.49= \
reference:file:sc-bundles/zrtp4j.jar \
reference:file:sc-bundles/protocol.jar \
reference:file:sc-bundles/protocol-media.jar \
- reference:file:lib/bundle/httpcore.jar \
+ reference:file:sc-bundles/httpcore.jar \
+ reference:file:sc-bundles/httpclient.jar \
reference:file:sc-bundles/globalproxyconfig.jar
#the contact list service depends on protocol.jar
diff --git a/lib/felix.unit.test.properties b/lib/felix.unit.test.properties
index 36becac..7d6585b 100644
--- a/lib/felix.unit.test.properties
+++ b/lib/felix.unit.test.properties
@@ -69,7 +69,8 @@ felix.auto.start.5= \
reference:file:sc-bundles/zrtp4j.jar \
reference:file:sc-bundles/protocol.jar \
reference:file:sc-bundles/protocol-media.jar \
- reference:file:lib/bundle/httpcore.jar
+ reference:file:sc-bundles/httpcore.jar \
+ reference:file:sc-bundles/httpclient.jar
felix.auto.start.6= \
reference:file:sc-bundles/contactlist.jar \
diff --git a/lib/installer-exclude/httpclient-4.0-beta2.jar b/lib/installer-exclude/httpclient-4.0-beta2.jar
deleted file mode 100644
index e773ccc..0000000
--- a/lib/installer-exclude/httpclient-4.0-beta2.jar
+++ /dev/null
Binary files differ
diff --git a/lib/installer-exclude/httpclient-4.0.1.jar b/lib/installer-exclude/httpclient-4.0.1.jar
new file mode 100644
index 0000000..e9c961f
--- /dev/null
+++ b/lib/installer-exclude/httpclient-4.0.1.jar
Binary files differ
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties
index 93b529b..74f2156 100644
--- a/resources/languages/resources.properties
+++ b/resources/languages/resources.properties
@@ -727,6 +727,15 @@ plugin.sipaccregwizz.DISPLAY_NAME=Display name
plugin.sipaccregwizz.EXISTING_ACCOUNT=Existing SIP account
plugin.sipaccregwizz.CREATE_ACCOUNT=Create a free SIP account
plugin.sipaccregwizz.CREATE_ACCOUNT_TITLE=Create account
+plugin.sipaccregwizz.XCAP_OPTIONS=XCAP Options
+plugin.sipaccregwizz.XCAP_ENABLE=Enable XCAP stored contacts
+plugin.sipaccregwizz.XCAP_USE_SIP_CREDETIALS=Use SIP credetials
+plugin.sipaccregwizz.XCAP_USE_SIP_CREDETIALS_SUMMARY=XCAP use SIP credetials
+plugin.sipaccregwizz.XCAP_USER=User
+plugin.sipaccregwizz.XCAP_USER_SUMMARY=XCAP user
+plugin.sipaccregwizz.XCAP_PASSWORD=Password
+plugin.sipaccregwizz.XCAP_SERVER_URI=Server uri
+plugin.sipaccregwizz.XCAP_SERVER_URI_SUMMARY=XCAP server uri
# ssh accregwizz
plugin.sshaccregwizz.PROTOCOL_NAME=SSH
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java
index 64739dc..5df0050 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ContactGroupSipImpl.java
@@ -6,10 +6,13 @@
*/
package net.java.sip.communicator.impl.protocol.sip;
-import java.util.*;
-
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists.*;
import net.java.sip.communicator.service.protocol.*;
+import org.w3c.dom.*;
+import javax.xml.namespace.*;
+import java.util.*;
+
/**
* A simple, straightforward implementation of a SIP ContactGroup. Since
* the SIP protocol is not a real one, we simply store all group details
@@ -19,17 +22,13 @@ import net.java.sip.communicator.service.protocol.*;
* the encapsulated object.
*
* @author Emil Ivov
+ * @author Grigorii Balutsel
*/
public class ContactGroupSipImpl
implements ContactGroup
{
/**
- * The name of this SIP contact group.
- */
- private String groupName = null;
-
- /**
* The list of this group's members.
*/
private Vector<Contact> contacts = new Vector<Contact>();
@@ -37,8 +36,7 @@ public class ContactGroupSipImpl
/**
* The list of sub groups belonging to this group.
*/
- private Vector<ContactGroup> subGroups
- = new Vector<ContactGroup>();
+ private Vector<ContactGroup> subGroups = new Vector<ContactGroup>();
/**
* The group that this group belongs to (or null if this is the root group).
@@ -75,6 +73,11 @@ public class ContactGroupSipImpl
private static final String UID_SUFFIX = ".uid";
/**
+ * The XCAP equivalent of SIP contact group.
+ */
+ private final ListType list;
+
+ /**
* Creates a ContactGroupSipImpl with the specified name.
*
* @param groupName the name of the group.
@@ -84,12 +87,53 @@ public class ContactGroupSipImpl
String groupName,
ProtocolProviderServiceSipImpl parentProvider)
{
- this.groupName = groupName;
- this.uid = groupName + UID_SUFFIX;
+ this.list = new ListType();
+ this.list.setName(groupName);
+ this.uid = list.getName() + UID_SUFFIX;
this.parentProvider = parentProvider;
}
/**
+ * Gets the list.
+ *
+ * @return the list.
+ */
+ ListType getList()
+ {
+ return list;
+ }
+
+ /**
+ * Sets the list custom attributes.
+ *
+ * @param otherAttributes the custom attributes.
+ */
+ void setOtherAttributes(Map<QName, String> otherAttributes)
+ {
+ this.list.setAnyAttributes(otherAttributes);
+ }
+
+ /**
+ * Sets the list custom elements.
+ *
+ * @param any the custom elemets.
+ */
+ void setAny(List<Element> any)
+ {
+ this.list.setAny(any);
+ }
+
+ /**
+ * Sets the list name.
+ *
+ * @param newName the name.
+ */
+ void setName(String newName)
+ {
+ this.list.setName(newName);
+ }
+
+ /**
* Determines whether the group may contain subgroups or not.
*
* @return always true in this implementation.
@@ -129,6 +173,10 @@ public class ContactGroupSipImpl
{
this.contacts.add(contactToAdd);
contactToAdd.setParentGroup(this);
+ if(contactToAdd.isPersistent())
+ {
+ this.list.getEntries().add(contactToAdd.getEntry());
+ }
}
/**
@@ -155,16 +203,6 @@ public class ContactGroupSipImpl
}
/**
- * Adds the specified contact group to the contained by this group.
- * @param subgroup the ContactGroupSipImpl to add as a subgroup to this group.
- */
- public void addSubgroup(ContactGroupSipImpl subgroup)
- {
- this.subGroups.add(subgroup);
- subgroup.setParentGroup(this);
- }
-
- /**
* Sets the group that is the new parent of this group
* @param parent ContactGroupSipImpl
*/
@@ -185,6 +223,20 @@ public class ContactGroupSipImpl
}
/**
+ * Adds the specified contact group to the contained by this group.
+ * @param subgroup the ContactGroupSipImpl to add as a subgroup to this group.
+ */
+ public void addSubgroup(ContactGroupSipImpl subgroup)
+ {
+ this.subGroups.add(subgroup);
+ subgroup.setParentGroup(this);
+ if(subgroup.isPersistent())
+ {
+ this.list.getLists().add(subgroup.getList());
+ }
+ }
+
+ /**
* Removes the specified contact group from the this group's subgroups.
* @param subgroup the ContactGroupSipImpl subgroup to remove.
*/
@@ -192,6 +244,10 @@ public class ContactGroupSipImpl
{
this.subGroups.remove(subgroup);
subgroup.setParentGroup(null);
+ if(subgroup.isPersistent())
+ {
+ this.list.getLists().remove(subgroup.getList());
+ }
}
/**
@@ -253,8 +309,6 @@ public class ContactGroupSipImpl
return null;
}
-
-
/**
* Returns the <tt>Contact</tt> with the specified address or identifier.
*
@@ -268,11 +322,10 @@ public class ContactGroupSipImpl
while (contactsIter.hasNext())
{
ContactSipImpl contact = (ContactSipImpl) contactsIter.next();
- if (contact.getAddress().equals(id))
+ if (contact.getUri().equals(id) || contact.getAddress().equals(id))
{
return contact;
}
-
}
return null;
}
@@ -305,10 +358,8 @@ public class ContactGroupSipImpl
{
return contactGroup;
}
-
}
return null;
-
}
/**
@@ -318,16 +369,7 @@ public class ContactGroupSipImpl
*/
public String getGroupName()
{
- return this.groupName;
- }
-
- /**
- * Sets this group a new name.
- * @param newGrpName a String containing the new name of this group.
- */
- public void setGroupName(String newGrpName)
- {
- this.groupName = newGrpName;
+ return this.list.getName();
}
/**
@@ -349,6 +391,10 @@ public class ContactGroupSipImpl
public void removeContact(ContactSipImpl contact)
{
this.contacts.remove(contact);
+ if(contact.isPersistent())
+ {
+ this.list.getEntries().remove(contact.getEntry());
+ }
}
/**
@@ -386,7 +432,6 @@ public class ContactGroupSipImpl
return null;
}
-
/**
* Returns a String representation of this group and the contacts it
* contains (may turn out to be a relatively long string).
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java
index 4e226cf..853b8a5 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ContactSipImpl.java
@@ -6,35 +6,26 @@
*/
package net.java.sip.communicator.impl.protocol.sip;
-import javax.sip.address.*;
-
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists.*;
import net.java.sip.communicator.service.protocol.*;
+import org.w3c.dom.*;
+import javax.sip.address.*;
+import javax.xml.namespace.*;
+import java.net.URI;
+import java.util.*;
+
/**
- * A simple, straightforward implementation of a SIP Contact. Since the SIP
- * protocol is not a real one, we simply store all contact details in class
- * fields. You should know that when implementing a real protocol, the contact
- * implementation would rather encapsulate contact objects from the protocol
- * stack and group property values should be returned after consulting the
- * encapsulated object.
+ * A simple, straightforward implementation of a SIP Contact.
*
* @author Emil Ivov
* @author Benoit Pradelle
* @author Lubomir Marinov
+ * @author Grigorii Balutsel
*/
public class ContactSipImpl
implements Contact
-{
-
- /**
- * The id of the contact.
- */
- private final Address sipAddress;
-
- /**
- * The display name of the contact.
- */
- private String displayName = null;
+{
/**
* The provider that created us.
@@ -52,6 +43,16 @@ public class ContactSipImpl
private PresenceStatus presenceStatus;
/**
+ * The image uri.
+ */
+ private URI imageUri;
+
+ /**
+ * The image content.
+ */
+ private byte[] image;
+
+ /**
* Determines whether this contact is persistent, i.e. member of the contact
* list or whether it is here only temporarily.
*/
@@ -70,6 +71,16 @@ public class ContactSipImpl
private boolean isResolvable = true;
/**
+ * The XCAP equivalent of SIP contact group.
+ */
+ private final EntryType entry;
+
+ /**
+ * The SIP contact identifier.
+ */
+ private final Address sipAddress;
+
+ /**
* Creates an instance of a meta contact with the specified string used
* as a name and identifier.
*
@@ -82,19 +93,33 @@ public class ContactSipImpl
ProtocolProviderServiceSipImpl parentProvider)
{
this.sipAddress = contactAddress;
-
- displayName = contactAddress.getDisplayName();
-
- if(displayName == null || displayName.trim().length() == 0)
- displayName = getAddress();
-
+ this.entry = new EntryType(contactAddress.getURI().toString());
this.parentProvider = parentProvider;
-
this.presenceStatus = parentProvider.getSipStatusEnum()
.getStatus(SipStatusEnum.UNKNOWN);
}
/**
+ * Gets the entry.
+ *
+ * @return the entry
+ */
+ EntryType getEntry()
+ {
+ return entry;
+ }
+
+ /**
+ * Gets the entry's uri.
+ *
+ * @return the entry' uri.
+ */
+ public String getUri()
+ {
+ return entry.getUri();
+ }
+
+ /**
* This method is only called when the contact is added to a new
* <tt>ContactGroupSipImpl</tt> by the
* <tt>ContactGroupSipImpl</tt> itself.
@@ -114,8 +139,7 @@ public class ContactSipImpl
*/
public String getAddress()
{
- SipURI sipURI = (SipURI)sipAddress.getURI();
-
+ SipURI sipURI = (SipURI) sipAddress.getURI();
return sipURI.getUser() + "@" + sipURI.getHost();
}
@@ -129,7 +153,6 @@ public class ContactSipImpl
return sipAddress;
}
-
/**
* Returns a String that could be used by any user interacting modules
* for referring to this contact.
@@ -139,7 +162,11 @@ public class ContactSipImpl
*/
public String getDisplayName()
{
- return (displayName == null) ? getAddress() : displayName;
+ if(this.entry.getDisplayName() != null)
+ {
+ return this.entry.getDisplayName().getValue();
+ }
+ return getAddress();
}
/**
@@ -150,18 +177,82 @@ public class ContactSipImpl
*/
public void setDisplayName(String displayName)
{
- this.displayName = displayName;
+ DisplayNameType displayNameType = new DisplayNameType();
+ displayNameType.setValue(displayName);
+ this.entry.setDisplayName(displayNameType);
+ }
+
+ /**
+ * Sets a String that could be used by any user interacting modules for
+ * referring to this contact.
+ *
+ * @param displayName a human readable name to use for this contact.
+ */
+ public void setDisplayName(DisplayNameType displayName)
+ {
+ this.entry.setDisplayName(displayName);
+ }
+
+ /**
+ * Sets the entry custom attributes.
+ *
+ * @param otherAttributes the custom attributes.
+ */
+ void setOtherAttributes(Map<QName, String> otherAttributes)
+ {
+ this.entry.setAnyAttributes(otherAttributes);
+ }
+
+ /**
+ * Sets the entry custom elements.
+ *
+ * @param any the custom elemets.
+ */
+ void setAny(List<Element> any)
+ {
+ this.entry.setAny(any);
+ }
+
+ /**
+ * Gets the image uri.
+ *
+ * @return the image uri.
+ */
+ URI getImageUri()
+ {
+ return imageUri;
+ }
+
+ /**
+ * Sets the image uri.
+ *
+ * @param imageUri the image uri.
+ */
+ void setImageUri(URI imageUri)
+ {
+ this.imageUri = imageUri;
}
/**
- * Returns a byte array containing an image (most often a photo or an
- * avatar) that the contact uses as a representation.
+ * Gets a byte array containing an image (most often a photo or an avatar)
+ * that the contact uses as a representation.
*
* @return byte[] an image representing the contact.
*/
public byte[] getImage()
{
- return null;
+ return image;
+ }
+
+ /**
+ * Sets a byte array containing an image (most often a photo or an avatar)
+ * that the contact uses as a representation.
+ *
+ * @param image an image representing the contact.
+ */
+ void setImage(byte[] image)
+ {
+ this.image = image;
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java
index 259d6af..7ad72b5 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetPresenceSipImpl.java
@@ -6,9 +6,12 @@
*/
package net.java.sip.communicator.impl.protocol.sip;
-import java.io.*;
-import java.text.*;
-import java.util.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.xml.*;
+import org.w3c.dom.*;
import javax.sip.*;
import javax.sip.address.*;
@@ -18,13 +21,10 @@ import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
-
-import org.w3c.dom.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-import net.java.sip.communicator.util.xml.*;
+import java.io.*;
+import java.net.URI;
+import java.text.*;
+import java.util.*;
/**
* Sip presence implementation (SIMPLE).
@@ -34,6 +34,7 @@ import net.java.sip.communicator.util.xml.*;
* @author Benoit Pradelle
* @author Lubomir Marinov
* @author Emil Ivov
+ * @author Grigorii Balutsel
*/
public class OperationSetPresenceSipImpl
extends AbstractOperationSetPersistentPresence<ProtocolProviderServiceSipImpl>
@@ -46,10 +47,8 @@ public class OperationSetPresenceSipImpl
private static final Logger logger
= Logger.getLogger(OperationSetPresenceSipImpl.class);
- /**
- * The root of the SIP contact list.
- */
- private final ContactGroupSipImpl contactListRoot;
+
+ private ServerStoredContactListSipImpl ssContactList;
/**
* The currently active status message.
@@ -189,6 +188,8 @@ public class OperationSetPresenceSipImpl
private static final String NS_BUSY_ELT = "rpid:busy";
private static final String OTP_ELEMENT = "on-the-phone";
private static final String NS_OTP_ELT = "rpid:on-the-phone";
+ private static final String STATUS_ICON_ELEMENT = "status-icon";
+ private static final String NS_STATUS_ICON_ELT = "rpid:status-icon";
// namespace wildcard
private static final String ANY_NS = "*";
@@ -226,7 +227,10 @@ public class OperationSetPresenceSipImpl
{
super(provider);
- this.contactListRoot = new ContactGroupSipImpl("RootGroup", provider);
+ //this.contactListRoot = new ContactGroupSipImpl("RootGroup", provider);
+ this.ssContactList = new ServerStoredContactListSipImpl(provider, this);
+
+ //this.ssContactList.addGroupListener();
//add our registration listener
this.parentProvider.addRegistrationStateChangeListener(this);
@@ -300,6 +304,31 @@ public class OperationSetPresenceSipImpl
}
/**
+ * Registers a listener that would receive events upong changes in server
+ * stored groups.
+ *
+ * @param listener a ServerStoredGroupChangeListener impl that would receive
+ * events upong group changes.
+ */
+ public void addServerStoredGroupChangeListener(
+ ServerStoredGroupListener listener)
+ {
+ ssContactList.addGroupListener(listener);
+ }
+
+ /**
+ * Removes the specified group change listener so that it won't receive
+ * any further events.
+ *
+ * @param listener the ServerStoredGroupChangeListener to remove
+ */
+ public void removeServerStoredGroupChangeListener(
+ ServerStoredGroupListener listener)
+ {
+ ssContactList.removeGroupListener(listener);
+ }
+
+ /**
* Returns a PresenceStatus instance representing the state this provider is
* currently in. Note that PresenceStatus instances returned by this method
* MUST adequately represent all possible states that a provider might
@@ -339,26 +368,29 @@ public class OperationSetPresenceSipImpl
*/
public ContactGroup getServerStoredContactListRoot()
{
- return this.contactListRoot;
+ return this.ssContactList.getRootGroup();
}
/**
* Creates a group with the specified name and parent in the server
* stored contact list.
*
- * @param parent the group where the new group should be created
+ * @param parentGroup the group where the new group should be created
* @param groupName the name of the new group to create.
*/
- public void createServerStoredContactGroup(ContactGroup parent,
+ public void createServerStoredContactGroup(ContactGroup parentGroup,
String groupName)
+ throws OperationFailedException
{
- ContactGroupSipImpl newGroup = new ContactGroupSipImpl(groupName,
- this.parentProvider);
-
- ((ContactGroupSipImpl) parent).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(newGroup,
- ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ if (!(parentGroup instanceof ContactGroupSipImpl))
+ {
+ String errorMessage = String.format(
+ "Group %1s does not seem to belong to this protocol's " +
+ "contact list", parentGroup.getGroupName());
+ throw new IllegalArgumentException(errorMessage);
+ }
+ ContactGroupSipImpl sipGroup = (ContactGroupSipImpl) parentGroup;
+ ssContactList.createGroup(sipGroup, groupName, true);
}
/**
@@ -382,25 +414,17 @@ public class OperationSetPresenceSipImpl
public ContactGroup createUnresolvedContactGroup(String groupUID,
String persistentData, ContactGroup parentGroup)
{
- ContactGroupSipImpl newGroup = new ContactGroupSipImpl(
- ContactGroupSipImpl.createNameFromUID(groupUID),
- this.parentProvider);
- newGroup.setResolved(false);
-
//if parent is null then we're adding under root.
if(parentGroup == null)
{
parentGroup = getServerStoredContactListRoot();
}
-
- ((ContactGroupSipImpl) parentGroup).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
-
- return newGroup;
+ String groupName = ContactGroupSipImpl.createNameFromUID(groupUID);
+ return ssContactList.createUnresolvedContactGroup(
+ (ContactGroupSipImpl) parentGroup, groupName);
}
+
/**
* Renames the specified group from the server stored contact list.
*
@@ -410,11 +434,14 @@ public class OperationSetPresenceSipImpl
public void renameServerStoredContactGroup(ContactGroup group,
String newName)
{
- ((ContactGroupSipImpl) group).setGroupName(newName);
-
- this.fireServerStoredGroupEvent(
- (ContactGroupSipImpl) group,
- ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
+ if (!(group instanceof ContactGroupSipImpl))
+ {
+ String errorMessage = String.format(
+ "Group %1s does not seem to belong to this protocol's " +
+ "contact list", group.getGroupName());
+ throw new IllegalArgumentException(errorMessage);
+ }
+ ssContactList.renameGroup((ContactGroupSipImpl) group, newName);
}
/**
@@ -429,17 +456,19 @@ public class OperationSetPresenceSipImpl
ContactGroup newParent)
{
if (!(contactToMove instanceof ContactSipImpl))
+ {
return;
-
- ContactSipImpl sipContact = (ContactSipImpl) contactToMove;
- ContactGroupSipImpl parentSipGroup
- = (ContactGroupSipImpl) sipContact.getParentContactGroup();
-
- parentSipGroup.removeContact(sipContact);
-
- ((ContactGroupSipImpl) newParent).addContact(sipContact);
-
- fireSubscriptionMovedEvent(contactToMove, parentSipGroup, newParent);
+ }
+ try
+ {
+ ssContactList.moveContactToGroup((ContactSipImpl) contactToMove,
+ (ContactGroupSipImpl) newParent);
+ }
+ catch (OperationFailedException ex)
+ {
+ throw new IllegalStateException(
+ "Failed to move contact " + contactToMove.getAddress(), ex);
+ }
}
/**
@@ -451,22 +480,16 @@ public class OperationSetPresenceSipImpl
* protocol's contact list.
*/
public void removeServerStoredContactGroup(ContactGroup group)
- throws IllegalArgumentException
{
- ContactGroupSipImpl sipGroup = (ContactGroupSipImpl) group;
- ContactGroupSipImpl parent = contactListRoot.findGroupParent(sipGroup);
-
- if(parent == null){
- throw new IllegalArgumentException(
- "group " + group
- + " does not seem to belong to this protocol's contact list.");
+ if (!(group instanceof ContactGroupSipImpl))
+ {
+ String errorMessage = String.format(
+ "Group %1s does not seem to belong to this protocol's " +
+ "contact list", group.getGroupName());
+ throw new IllegalArgumentException(errorMessage);
}
-
- parent.removeSubGroup(sipGroup);
-
- fireServerStoredGroupEvent(
- sipGroup,
- ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
+ ContactGroupSipImpl sipGroup = (ContactGroupSipImpl) group;
+ ssContactList.removeGroup(sipGroup);
}
/**
@@ -881,7 +904,7 @@ public class OperationSetPresenceSipImpl
IllegalStateException,
OperationFailedException
{
- subscribe(this.contactListRoot, contactIdentifier);
+ subscribe(this.ssContactList.getRootGroup(), contactIdentifier);
}
/**
@@ -908,9 +931,16 @@ public class OperationSetPresenceSipImpl
IllegalStateException,
OperationFailedException
{
- if (logger.isDebugEnabled())
- logger.debug("let's subscribe " + contactIdentifier);
+ assertConnected();
+ if (!(parentGroup instanceof ContactGroupSipImpl))
+ {
+ String errorMessage = String.format(
+ "Group %1s does not seem to belong to this protocol's " +
+ "contact list",
+ parentGroup.getGroupName());
+ throw new IllegalArgumentException(errorMessage);
+ }
//if the contact is already in the contact list
ContactSipImpl contact = resolveContactID(contactIdentifier);
@@ -927,40 +957,15 @@ public class OperationSetPresenceSipImpl
// we will remove it as we will created again
// this is the case when making a non persistent contact to
// a persistent one
- ContactGroupSipImpl oldParentGroup =
- (ContactGroupSipImpl)contact.getParentContactGroup();
- oldParentGroup.removeContact(contact);
- fireSubscriptionEvent(contact, oldParentGroup,
- SubscriptionEvent.SUBSCRIPTION_REMOVED);
+ ssContactList.removeContact(contact);
}
}
-
- Address contactAddress;
- try
- {
- contactAddress
- = parentProvider.parseAddressString(contactIdentifier);
- }
- catch (ParseException exc)
+ contact = ssContactList.createContact((ContactGroupSipImpl) parentGroup,
+ contactIdentifier, true);
+ if (this.presenceEnabled)
{
- throw new IllegalArgumentException(
- contactIdentifier + " is not a valid string.", exc);
+ subscriber.subscribe(new PresenceSubscriberSubscription(contact));
}
-
- // create a new contact, marked as resolvable and non resolved
- contact = new ContactSipImpl(contactAddress, this.parentProvider);
- ((ContactGroupSipImpl) parentGroup).addContact(contact);
-
- fireSubscriptionEvent(contact,
- parentGroup,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- // do not query the presence state
- if (this.presenceEnabled == false)
- return;
-
- assertConnected();
- subscriber.subscribe(new PresenceSubscriberSubscription(contact));
}
/**
@@ -1003,28 +1008,19 @@ public class OperationSetPresenceSipImpl
assertConnected();
if (!(contact instanceof ContactSipImpl))
- throw
- new IllegalArgumentException(
- "the contact is not a SIP contact");
-
- ContactSipImpl sipcontact = (ContactSipImpl) contact;
-
+ {
+ throw new IllegalArgumentException("The contact is not a SIP " +
+ "contact");
+ }
+ ContactSipImpl sipContact = (ContactSipImpl) contact;
/**
* Does not assert if there is no subscription cause if the user
* becomes offline he has terminated the subscription and so we have
* no subscription of this contact but we wont to remove it.
* Does not assert on connected cause have already has made the check.
*/
- unsubscribe(sipcontact, false);
-
- ((ContactGroupSipImpl) sipcontact.getParentContactGroup())
- .removeContact(sipcontact);
-
- // inform the listeners
- fireSubscriptionEvent(
- sipcontact,
- sipcontact.getParentContactGroup(),
- SubscriptionEvent.SUBSCRIPTION_REMOVED);
+ unsubscribe(sipContact, false);
+ ssContactList.removeContact(sipContact);
}
/**
@@ -1542,7 +1538,7 @@ public class OperationSetPresenceSipImpl
*/
public ContactSipImpl findContactByID(String contactID)
{
- return this.contactListRoot.findContactByID(contactID);
+ return this.ssContactList.getRootGroup().findContactByID(contactID);
}
/**
@@ -1647,29 +1643,8 @@ public class OperationSetPresenceSipImpl
String persistentData,
ContactGroup parent)
{
- Address contactAddress;
- try
- {
- contactAddress = parentProvider.parseAddressString(addressStr);
- }
- catch (ParseException exc)
- {
- throw new IllegalArgumentException(
- addressStr + " is not a valid string.", exc);
- }
-
- ContactSipImpl contact = new ContactSipImpl(contactAddress,
- this.parentProvider);
-
- contact.setResolved(false);
-
- ((ContactGroupSipImpl) parent).addContact(contact);
-
- fireSubscriptionEvent(contact,
- parent,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- return contact;
+ return ssContactList.createUnresolvedContact((ContactGroupSipImpl)
+ parent, addressStr);
}
/**
@@ -1684,37 +1659,25 @@ public class OperationSetPresenceSipImpl
*/
public ContactSipImpl createVolatileContact(Address contactAddress)
{
- // First create the new volatile contact;
- ContactSipImpl newVolatileContact
- = new ContactSipImpl(contactAddress, this.parentProvider);
- newVolatileContact.setDisplayName(contactAddress.getDisplayName());
- newVolatileContact.setPersistent(false);
-
- // Check whether a volatile group already exists and if not create one
- ContactGroupSipImpl theVolatileGroup = getNonPersistentGroup();
-
- // if the parent volatile group is null then we create it
- if (theVolatileGroup == null)
+ try
{
- theVolatileGroup = new ContactGroupSipImpl(
- "NotInContactList",
- this.parentProvider);
- theVolatileGroup.setResolved(false);
- theVolatileGroup.setPersistent(false);
-
- this.contactListRoot.addSubgroup(theVolatileGroup);
-
- fireServerStoredGroupEvent(theVolatileGroup
- , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ // Check whether a volatile group already exists and if not create one
+ ContactGroupSipImpl volatileGroup = getNonPersistentGroup();
+ // if the parent volatile group is null then we create it
+ if (volatileGroup == null)
+ {
+ ContactGroupSipImpl rootGroup =
+ this.ssContactList.getRootGroup();
+ volatileGroup = ssContactList
+ .createGroup(rootGroup, "NotInContactList", false);
+ }
+ return ssContactList.createContact(volatileGroup,
+ contactAddress.getURI().toString(), false);
+ }
+ catch (OperationFailedException ex)
+ {
+ return null;
}
-
- //now add the volatile contact inside it
- theVolatileGroup.addContact(newVolatileContact);
- fireSubscriptionEvent(newVolatileContact
- , theVolatileGroup
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- return newVolatileContact;
}
/**
@@ -1929,6 +1892,17 @@ public class OperationSetPresenceSipImpl
Element activities = doc.createElement(NS_ACTIVITY_ELT);
person.appendChild(activities);
+ // <status-icon>
+ XCapClient xCapClient = parentProvider.getXCapClient();
+ if (xCapClient.isConnected() && xCapClient.isPresContentSupported())
+ {
+ Element statusIcon = doc.createElement(NS_STATUS_ICON_ELT);
+ URI imageUri = xCapClient.getPresContentImageUri(
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ statusIcon.setTextContent(imageUri.toString());
+ person.appendChild(statusIcon);
+ }
+
// the correct activity
if (contact.getPresenceStatus()
.equals(sipStatusEnum.getStatus(SipStatusEnum.AWAY)))
@@ -2046,6 +2020,7 @@ public class OperationSetPresenceSipImpl
// ignore namespaces here
PresenceStatus personStatus = null;
+ URI personStatusIcon = null;
NodeList personList = presence.getElementsByTagNameNS(ANY_NS,
PERSON_ELEMENT);
@@ -2110,6 +2085,43 @@ public class OperationSetPresenceSipImpl
break;
}
}
+ NodeList statusIconList = person.getElementsByTagNameNS(ANY_NS,
+ STATUS_ICON_ELEMENT);
+ if (statusIconList.getLength() > 0)
+ {
+ Element statusIcon;
+ Node statusIconNode = statusIconList.item(0);
+ if (statusIconNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ statusIcon = (Element) statusIconNode;
+ String content = getTextContent(statusIcon);
+ if (content != null && content.trim().length() != 0)
+ {
+ try
+ {
+ personStatusIcon = URI.create(content);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ logger.error("Person's status icon uri: " +
+ content + " is invalid");
+ }
+ }
+ }
+ }
+ }
+
+ if(personStatusIcon != null)
+ {
+ String contactID =
+ XMLUtils.getAttribute(presNode, ENTITY_ATTRIBUTE);
+
+ if (contactID.startsWith("pres:"))
+ {
+ contactID = contactID.substring("pres:".length());
+ }
+ Contact contact = resolveContactID(contactID);
+ updateContactIcon((ContactSipImpl) contact, personStatusIcon);
}
// Vector containing the list of status to set for each contact in
@@ -2397,6 +2409,61 @@ public class OperationSetPresenceSipImpl
}
/**
+ * Checks whether to URIs are equal with safe null check.
+ * @param uri1 to be compared.
+ * @param uri2 to be compared.
+ * @return if uri1 is equal to uri2.
+ */
+ public static boolean isEquals(URI uri1, URI uri2) {
+ return (uri1 == null && uri2 == null)
+ || (uri1 != null && uri1.equals(uri2));
+ }
+
+ /**
+ * Changes the Contact image
+ * @param contact
+ * @param imageUri
+ */
+ private void updateContactIcon(ContactSipImpl contact, URI imageUri)
+ {
+ if(isEquals(contact.getImageUri(), imageUri))
+ {
+ return;
+ }
+ byte[] oldImage = contact.getImage();
+ byte[] newImage = new byte[0];
+ if(imageUri != null)
+ {
+ XCapClient xCapClient = parentProvider.getXCapClient();
+ if(xCapClient.isConnected())
+ {
+ try
+ {
+ newImage = xCapClient.getImage(imageUri);
+ }
+ catch (XCapException e)
+ {
+ String errorMessage = String.format(
+ "Error while getting icon %1s for the contact %2s",
+ imageUri, contact.getUri());
+ logger.error(errorMessage, e);
+ }
+ }
+ else
+ {
+ return;
+ }
+ }
+ contact.setImageUri(imageUri);
+ contact.setImage(newImage);
+ fireContactPropertyChangeEvent(
+ ContactPropertyChangeEvent.PROPERTY_IMAGE,
+ contact,
+ oldImage,
+ newImage);
+ }
+
+ /**
* Secured call to XMLUtils.getText (no null returned but an empty string)
*
* @param node the node with which call <tt>XMLUtils.getText()</tt>
@@ -2732,6 +2799,39 @@ public class OperationSetPresenceSipImpl
}
/**
+ * Will wait for every SUBSCRIBE, NOTIFY and PUBLISH transaction
+ * to finish before continuing the unsubscription
+ */
+ private void stopEvents()
+ {
+ for (byte i = 0; i < 10; i++)
+ {
+ synchronized (waitedCallIds)
+ {
+ if (waitedCallIds.size() == 0)
+ {
+ break;
+ }
+ }
+ synchronized (this)
+ {
+ try
+ {
+ // Wait 5 s. max
+ wait(500);
+ }
+ catch (InterruptedException e)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("abnormal behavior, may cause unnecessary CPU use", e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
* The method is called by a ProtocolProvider implementation whenever
* a change in the registration state of the corresponding provider had
* occurred. The method is particularly interested in events stating
@@ -2743,11 +2843,12 @@ public class OperationSetPresenceSipImpl
*/
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
- if(evt.getNewState() == RegistrationState.UNREGISTERING)
+ if (evt.getNewState().equals(RegistrationState.UNREGISTERING))
{
// stop any task associated with the timer
cancelTimer();
-
+ // Destroy XCAP contacts
+ ssContactList.destroy();
// this will not be called by anyone else, so call it
// the method will terminate every active subscription
try
@@ -2759,39 +2860,18 @@ public class OperationSetPresenceSipImpl
{
logger.error("can't set the offline mode", e);
}
-
- // we wait for every SUBSCRIBE, NOTIFY and PUBLISH transaction
- // to finish before continuing the unsubscription
- for (byte i = 0; i < 10; i++)
- { // wait 5 s. max
- synchronized (waitedCallIds)
- {
- if (waitedCallIds.size() == 0)
- {
- break;
- }
- }
-
- synchronized (this)
- {
- try
- {
- wait(500);
- }
- catch (InterruptedException e)
- {
- if (logger.isDebugEnabled())
- logger.debug("abnormal behavior, may cause " +
- "unnecessary CPU use", e);
- }
- }
- }
+ stopEvents();
}
else if (evt.getNewState().equals(
RegistrationState.REGISTERED))
{
if (logger.isDebugEnabled())
+ {
logger.debug("enter registered state");
+ }
+
+ // Init XCAP contacts
+ ssContactList.init();
/*
* If presence support is enabled and the keep-alive method
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
new file mode 100644
index 0000000..05df409
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
@@ -0,0 +1,450 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import java.util.*;
+
+/**
+ * SIP server stored account information. Supports the user avatar during
+ * pres-content specification.
+ *
+ * @author Grigorii Balutsel
+ */
+public class OperationSetServerStoredAccountInfoSipImpl
+ implements OperationSetServerStoredAccountInfo,
+ RegistrationStateChangeListener
+{
+ /**
+ * Logger class.
+ */
+ private static final Logger logger =
+ Logger.getLogger(OperationSetServerStoredAccountInfoSipImpl.class);
+
+ /**
+ * The provider that is on top of us.
+ */
+ private ProtocolProviderServiceSipImpl provider;
+
+ /**
+ * Current image.
+ */
+ private ImageDetail accountImage;
+
+ /**
+ * Flag whether account image is loaded.
+ */
+ private boolean isAccountImageLoaded = false;
+
+ /**
+ * Creates this op.set.
+ * @param provider the parent provider.
+ */
+ public OperationSetServerStoredAccountInfoSipImpl(
+ ProtocolProviderServiceSipImpl provider)
+ {
+ this.provider = provider;
+ this.provider.addRegistrationStateChangeListener(this);
+ }
+
+ /**
+ * Returns an iterator over all details of the specified class.
+ *
+ * @param detailClass one of the detail classes defined in the
+ * ServerStoredDetails class, indicating the kind of
+ * details we're interested in.
+ * @return a java.util.Iterator over all details that are instances or
+ * descendants of the specified class.
+ */
+ public Iterator<GenericDetail> getDetailsAndDescendants(
+ Class<? extends GenericDetail> detailClass)
+ {
+ List<GenericDetail> result = new Vector<GenericDetail>();
+ if (ImageDetail.class.isAssignableFrom(detailClass) &&
+ isImageDetailSupported())
+ {
+ ImageDetail imageDetail = getAccountImage();
+ if (imageDetail != null)
+ {
+ result.add(getAccountImage());
+ }
+ }
+ return result.iterator();
+ }
+
+ /**
+ * Returns an iterator over all details that are instances of exactly the
+ * same class as the one specified.
+ *
+ * @param detailClass one of the detail classes defined in the
+ * ServerStoredDetails class, indicating the kind of
+ * details we're interested in.
+ * @return a java.util.Iterator over all details of specified class.
+ */
+ public Iterator<GenericDetail> getDetails(
+ Class<? extends GenericDetail> detailClass)
+ {
+ List<GenericDetail> result = new ArrayList<GenericDetail>();
+ if (ImageDetail.class.isAssignableFrom(detailClass) &&
+ isImageDetailSupported())
+ {
+ ImageDetail imageDetail = getAccountImage();
+ if (imageDetail != null)
+ {
+ result.add(getAccountImage());
+ }
+ }
+ return result.iterator();
+ }
+
+ /**
+ * Returns all details currently available and set for our account.
+ *
+ * @return a java.util.Iterator over all details currently set our account.
+ */
+ public Iterator<GenericDetail> getAllAvailableDetails()
+ {
+ List<GenericDetail> details = new ArrayList<GenericDetail>();
+ if (isImageDetailSupported())
+ {
+ ImageDetail imageDetail = getAccountImage();
+ if (imageDetail != null)
+ {
+ details.add(getAccountImage());
+ }
+ }
+ return details.iterator();
+ }
+
+ /**
+ * Returns all detail Class-es that the underlying implementation supports
+ * setting.
+ *
+ * @return a java.util.Iterator over all detail classes supported by the
+ * implementation.
+ */
+ public Iterator<Class<? extends GenericDetail>> getSupportedDetailTypes()
+ {
+ List<Class<? extends GenericDetail>> result =
+ new Vector<Class<? extends GenericDetail>>();
+ if (isImageDetailSupported())
+ {
+ result.add(ImageDetail.class);
+ }
+ return result.iterator();
+ }
+
+ /**
+ * Determines whether a detail class represents a detail supported by the
+ * underlying implementation or not.
+ *
+ * @param detailClass the class the support for which we'd like to
+ * determine.
+ * @return true if the underlying implementation supports setting details of
+ * this type and false otherwise.
+ */
+ public boolean isDetailClassSupported(
+ Class<? extends GenericDetail> detailClass)
+ {
+ return ImageDetail.class.isAssignableFrom(detailClass) &&
+ isImageDetailSupported();
+ }
+
+ /**
+ * The method returns the number of instances supported for a particular
+ * detail type.
+ *
+ * @return int the maximum number of detail instances.
+ */
+ public int getMaxDetailInstances(Class<? extends GenericDetail> detailClass)
+ {
+ if (ImageDetail.class.isAssignableFrom(detailClass) &&
+ isImageDetailSupported())
+ {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * Adds the specified detail to the list of details registered on-line
+ * for this account.
+ *
+ * @param detail the detail that we'd like registered on the server.
+ * @throws IllegalArgumentException if such a detail already exists
+ * and its max instances number has
+ * been atteined or if the underlying
+ * implementation does not support
+ * setting details of the
+ * corresponding class.
+ * @throws OperationFailedException with code Network Failure if
+ * putting the new value online has
+ * failed.
+ * @throws ArrayIndexOutOfBoundsException if the number of instances
+ * currently registered by the
+ * application is already equal to
+ * the maximum number of supported
+ * instances.
+ */
+ public void addDetail(GenericDetail detail)
+ throws IllegalArgumentException, OperationFailedException,
+ ArrayIndexOutOfBoundsException
+ {
+ if (!isDetailClassSupported(detail.getClass()))
+ {
+ throw new IllegalArgumentException(
+ "Implementation does not support such details " +
+ detail.getClass());
+ }
+ List<GenericDetail> alreadySetDetails = new Vector<GenericDetail>();
+ Iterator<GenericDetail> iter = getDetails(detail.getClass());
+ while (iter.hasNext())
+ {
+ alreadySetDetails.add(iter.next());
+ }
+ if (alreadySetDetails.size() >=
+ getMaxDetailInstances(detail.getClass()))
+ {
+ throw new ArrayIndexOutOfBoundsException(
+ "Max count for this detail is already reached");
+ }
+ if (ImageDetail.class.isAssignableFrom(detail.getClass()) &&
+ isImageDetailSupported())
+ {
+ ImageDetail imageDetail = (ImageDetail) detail;
+ putImageDetail(imageDetail);
+ accountImage = imageDetail;
+ isAccountImageLoaded = true;
+ }
+ }
+
+ /**
+ * Removes the specified detail from the list of details stored online for
+ * this account.
+ *
+ * @param detail the detail to remove
+ * @return true if the specified detail existed and was successfully removed
+ * and false otherwise.
+ * @throws OperationFailedException with code Network Failure if removing
+ * the detail from the server has failed
+ */
+ public boolean removeDetail(GenericDetail detail)
+ throws OperationFailedException
+ {
+ boolean isFound = false;
+ Iterator<?> iter = getAllAvailableDetails();
+ while (iter.hasNext())
+ {
+ GenericDetail item = (GenericDetail) iter.next();
+ if (item.equals(detail))
+ {
+ isFound = true;
+ }
+ }
+ // Current detail value does not exist
+ if (!isFound)
+ {
+ return false;
+ }
+ if (ImageDetail.class.isAssignableFrom(detail.getClass()) &&
+ isImageDetailSupported())
+ {
+ deleteImageDetail();
+ accountImage = null;
+ }
+ return true;
+ }
+
+ /**
+ * Replaces the currentDetailValue detail with newDetailValue and returns
+ * true if the operation was a success or false if currentDetailValue did
+ * not previously exist (in this case an additional call to addDetail is
+ * required).
+ *
+ * @param currentDetailValue the detail value we'd like to replace.
+ * @param newDetailValue the value of the detail that we'd like to
+ * replace currentDetailValue with.
+ * @return
+ * @throws ClassCastException if newDetailValue is not an instance of
+ * the same class as currentDetailValue.
+ * @throws OperationFailedException with code Network Failure if putting the
+ * new value back online has failed
+ */
+ public boolean replaceDetail(
+ GenericDetail currentDetailValue,
+ GenericDetail newDetailValue)
+ throws ClassCastException, OperationFailedException
+ {
+ if (!newDetailValue.getClass().equals(currentDetailValue.getClass()))
+ {
+ throw new ClassCastException(
+ "New value to be replaced is not as the current one");
+ }
+ // If values are the same no change
+ if (currentDetailValue.equals(newDetailValue))
+ {
+ return true;
+ }
+ removeDetail(currentDetailValue);
+ addDetail(newDetailValue);
+ return true;
+ }
+
+ /**
+ * Determines if image details is supported.
+ *
+ * @return true if supported, false otherwise.
+ */
+ private boolean isImageDetailSupported()
+ {
+ XCapClient xCapClient = provider.getXCapClient();
+ return xCapClient != null &&
+ xCapClient.isConnected() &&
+ xCapClient.isPresContentSupported();
+ }
+
+ /**
+ * Gets the user avatar from the server or returns cached value.
+ *
+ * @return the image detail.
+ */
+ private ImageDetail getAccountImage()
+ {
+ if (isAccountImageLoaded)
+ {
+ return accountImage;
+ }
+ isAccountImageLoaded = true;
+ try
+ {
+ accountImage = getImageDetail();
+ }
+ catch (OperationFailedException e)
+ {
+ if (logger.isInfoEnabled())
+ {
+ logger.info("Avatar image cannot be loaded", e);
+ }
+ }
+ return accountImage;
+ }
+
+ /**
+ * Gets image detail from the XCAP server.
+ *
+ * @return the image detail.
+ * @throws OperationFailedException if there is some error during operation.
+ */
+ private ImageDetail getImageDetail() throws OperationFailedException
+ {
+ ImageDetail imageDetail;
+ XCapClient xCapClient = provider.getXCapClient();
+ try
+ {
+ ContentType presContent = xCapClient.getPresContent(
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ if (presContent == null)
+ {
+ return null;
+ }
+ String description = null;
+ byte[] content = null;
+ if (presContent.getDescription().size() > 0)
+ {
+ description = presContent.getDescription().get(0).getValue();
+ }
+ if (presContent.getData() != null)
+ {
+ content = Base64.decode(presContent.getData().getValue());
+ }
+ imageDetail = new ImageDetail(description, content);
+ }
+ catch (XCapException e)
+ {
+ throw new OperationFailedException("Cannot get image detail",
+ OperationFailedException.NETWORK_FAILURE);
+ }
+ return imageDetail;
+ }
+
+ /**
+ * Puts the image detail to the XCAP server.
+ *
+ * @param imageDetail the image detail.
+ * @throws OperationFailedException if there is some error during operation.
+ */
+ private void putImageDetail(ImageDetail imageDetail)
+ throws OperationFailedException
+ {
+ XCapClient xCapClient = provider.getXCapClient();
+ ContentType presContent = new ContentType();
+ MimeType mimeType = new MimeType();
+ mimeType.setValue("image/png");
+ presContent.setMimeType(mimeType);
+ EncodingType encoding = new EncodingType();
+ encoding.setValue("base64");
+ presContent.setEncoding(encoding);
+ String encodedImageContent =
+ new String(Base64.encode(imageDetail.getBytes()));
+ DataType data = new DataType();
+ data.setValue(encodedImageContent);
+ presContent.setData(data);
+ try
+ {
+ xCapClient.putPresContent(presContent,
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ }
+ catch (XCapException e)
+ {
+ throw new OperationFailedException("Cannot put image detail",
+ OperationFailedException.NETWORK_FAILURE);
+ }
+ }
+
+ /**
+ * Deletes the image detail from the XCAP server.
+ *
+ * @throws OperationFailedException if there is some error during operation.
+ */
+ private void deleteImageDetail()
+ throws OperationFailedException
+ {
+ XCapClient xCapClient = provider.getXCapClient();
+ try
+ {
+ xCapClient.deletePresContent(
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ }
+ catch (XCapException e)
+ {
+ throw new OperationFailedException("Cannot delete image detail",
+ OperationFailedException.NETWORK_FAILURE);
+ }
+ }
+
+ /**
+ * Lister method for protocol provider registration event. If state is
+ * UNREGISTERED or CONNECTION_FAILED it will clear the cache.
+ *
+ * @param evt the event describing the status change.
+ */
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ if (evt.getNewState().equals(RegistrationState.UNREGISTERED) ||
+ evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))
+ {
+ isAccountImageLoaded = false;
+ accountImage = null;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
index 12caa30..672c3db 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
@@ -6,26 +6,25 @@
*/
package net.java.sip.communicator.impl.protocol.sip;
-import java.net.*;
-import java.text.*;
-import java.util.*;
-
-import javax.sip.*;
-import javax.sip.address.*;
-import javax.sip.header.*;
-import javax.sip.message.*;
-
-import org.osgi.framework.*;
-
+import gov.nist.javax.sip.address.*;
+import gov.nist.javax.sip.header.*;
+import gov.nist.javax.sip.message.*;
import net.java.sip.communicator.impl.protocol.sip.security.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.service.version.Version; // avoid ambiguity with org.osgi.framework.Version
+import net.java.sip.communicator.service.version.Version;
import net.java.sip.communicator.util.*;
+import org.osgi.framework.*;
-import gov.nist.javax.sip.header.*;
-import gov.nist.javax.sip.address.*;
-import gov.nist.javax.sip.message.*;
+import javax.sip.*;
+import javax.sip.address.*;
+import javax.sip.header.*;
+import javax.sip.message.*;
+import java.net.*;
+import java.net.URI;
+import java.text.*;
+import java.util.*;
/**
* A SIP implementation of the Protocol Provider Service.
@@ -33,6 +32,7 @@ import gov.nist.javax.sip.message.*;
* @author Emil Ivov
* @author Lubomir Marinov
* @author Alan Kelly
+ * @author Grigorii Balutsel
*/
public class ProtocolProviderServiceSipImpl
extends AbstractProtocolProviderService
@@ -132,6 +132,41 @@ public class ProtocolProviderServiceSipImpl
public static final String KEEP_ALIVE_INTERVAL = "KEEP_ALIVE_INTERVAL";
/**
+ * The name of the property under which the user may specify whether to use
+ * or not XCAP.
+ */
+ public static final String XCAP_ENABLE = "XCAP_ENABLE";
+
+ /**
+ * The name of the property under which the user may specify whether to use
+ * original sip creadetials for the XCAP.
+ */
+ public static final String XCAP_USE_SIP_CREDETIALS =
+ "XCAP_USE_SIP_CREDETIALS";
+
+ /**
+ * The name of the property under which the user may specify the XCAP server
+ * uri.
+ */
+ public static final String XCAP_SERVER_URI = "XCAP_SERVER_URI";
+
+ /**
+ * The name of the property under which the user may specify the XCAP user.
+ */
+ public static final String XCAP_USER = "XCAP_USER";
+
+ /**
+ * The name of the property under which the user may specify the XCAP user
+ * password.
+ */
+ public static final String XCAP_PASSWORD = "XCAP_PASSWORD";
+
+ /**
+ * Presence content for image.
+ */
+ public static final String PRES_CONTENT_IMAGE_NAME = "sip_communicator";
+
+ /**
* The default maxForwards header that we use in our requests.
*/
private MaxForwardsHeader maxForwardsHeader = null;
@@ -186,6 +221,21 @@ public class ProtocolProviderServiceSipImpl
private SipStatusEnum sipStatusEnum;
/**
+ * The XCAP client.
+ */
+ private final XCapClient xCapClient = new XCapClientImpl();
+
+ /**
+ * Gets the XCAP client.
+ *
+ * @return the XCAP client.
+ */
+ public XCapClient getXCapClient()
+ {
+ return xCapClient;
+ }
+
+ /**
* Returns the AccountID that uniquely identifies the account represented by
* this instance of the ProtocolProviderService.
* @return the id of the account represented by this provider.
@@ -251,6 +301,64 @@ public class ProtocolProviderServiceSipImpl
return this.registeredEvents;
}
+
+ public void fireRegistrationStateChanged(RegistrationState oldState,
+ RegistrationState newState,
+ int reasonCode,
+ String reason)
+ {
+ if (newState.equals(RegistrationState.REGISTERED))
+ {
+ try
+ {
+ boolean enableXCap =
+ accountID.getAccountPropertyBoolean(XCAP_ENABLE, true);
+ boolean useSipCredetials =
+ accountID.getAccountPropertyBoolean(
+ XCAP_USE_SIP_CREDETIALS, true);
+ String serverUri =
+ accountID.getAccountPropertyString(XCAP_SERVER_URI);
+ String user;
+ String password;
+ if (useSipCredetials)
+ {
+ user = accountID.getAccountPropertyString(
+ ProtocolProviderFactory.USER_ID);
+ password = SipActivator.getProtocolProviderFactory().
+ loadPassword(accountID);
+ }
+ else
+ {
+ user = accountID.getAccountPropertyString(XCAP_USER);
+ password = accountID.getAccountPropertyString(XCAP_PASSWORD);
+ }
+ // Connect to xcap server
+ Address userAddress = parseAddressString(user);
+ if(enableXCap && serverUri != null)
+ {
+ URI uri = new URI(serverUri.trim());
+ if(uri.getHost() != null && uri.getPath() != null)
+ {
+ xCapClient.connect(uri, userAddress, password);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ logger.error("Error while connecting to XCAP server. " +
+ "Contact list won't be saved", e);
+ }
+ }
+ else if (newState.equals(RegistrationState.UNREGISTERING) ||
+ newState.equals(RegistrationState.CONNECTION_FAILED))
+ {
+ xCapClient.dicsonnect();
+ }
+
+ super.fireRegistrationStateChanged(oldState, newState, reasonCode,
+ reason);
+ }
+
/**
* Starts the registration process. Connection details such as
* registration server, user name/number are provided through the
@@ -480,6 +588,11 @@ public class ProtocolProviderServiceSipImpl
new OperationSetTypingNotificationsSipImpl(
this,
opSetBasicIM));
+ // init avatar
+ addSupportedOperationSet(
+ OperationSetServerStoredAccountInfo.class,
+ new OperationSetServerStoredAccountInfoSipImpl(this));
+
}
// OperationSetVideoTelephony
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ServerStoredContactListSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ServerStoredContactListSipImpl.java
new file mode 100644
index 0000000..6ee87cc
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ServerStoredContactListSipImpl.java
@@ -0,0 +1,1234 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import javax.sip.address.*;
+import java.text.*;
+import java.util.*;
+
+/**
+ * Encapsulates XCapClient, it's resposible for generate corresponding
+ * sip-communicator events to all action that are made with XCAP contacts and
+ * groups.
+ *
+ * @author Grigorii Balutsel
+ */
+public class ServerStoredContactListSipImpl
+{
+ /**
+ * Logger class
+ */
+ private static final Logger logger =
+ Logger.getLogger(ServerStoredContactListSipImpl.class);
+
+ /**
+ * Root group name.
+ */
+ private static String ROOT_GROUP_NAME = "RootGroup";
+
+ /**
+ * "White" rule identifier.
+ */
+ private static String WHITE_RULE_ID = "sip_communicator";
+
+ /**
+ * The provider that is on top of us.
+ */
+ private final ProtocolProviderServiceSipImpl sipProvider;
+
+ /**
+ * The operation set that created us and that we could use when dispatching
+ * subscription events.
+ */
+ private final AbstractOperationSetPersistentPresence<ProtocolProviderServiceSipImpl>
+ parentOperationSet;
+
+ /**
+ * Listeners that would receive event notifications for changes in group
+ * names or other properties, removal or creation of groups.
+ */
+ private final Vector<ServerStoredGroupListener> serverStoredGroupListeners;
+
+ /**
+ * The root contact group. The container for all SIP contacts and groups.
+ */
+ private final ContactGroupSipImpl rootGroup;
+
+ /**
+ * Current presence rules.
+ */
+ private RulesetType presRules;
+
+ /**
+ * Current "white" rule.
+ */
+ private RuleType whiteRule;
+
+ /**
+ * Creates a ServerStoredContactList wrapper for the specified BuddyList.
+ *
+ * @param sipProvider the provider that has instantiated us.
+ * @param parentOperationSet the operation set that created us and that
+ * we could use for dispatching subscription events
+ */
+ ServerStoredContactListSipImpl(
+ ProtocolProviderServiceSipImpl sipProvider,
+ AbstractOperationSetPersistentPresence<ProtocolProviderServiceSipImpl>
+ parentOperationSet)
+ {
+ this.sipProvider = sipProvider;
+ this.parentOperationSet = parentOperationSet;
+ this.serverStoredGroupListeners =
+ new Vector<ServerStoredGroupListener>();
+ this.rootGroup = new ContactGroupSipImpl(ROOT_GROUP_NAME, sipProvider);
+ }
+
+ /**
+ * Returns the root group of the contact list.
+ *
+ * @return the root ContactGroup for the ContactList.
+ */
+ public ContactGroupSipImpl getRootGroup()
+ {
+ return rootGroup;
+ }
+
+ /**
+ * Registers the specified group listener so that it would receive events
+ * on group modification/creation/destruction.
+ *
+ * @param listener the ServerStoredGroupListener to register for group
+ * events.
+ */
+ public void addGroupListener(ServerStoredGroupListener listener)
+ {
+ synchronized (serverStoredGroupListeners)
+ {
+ if (!serverStoredGroupListeners.contains(listener))
+ {
+ this.serverStoredGroupListeners.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes the specified group listener so that it won't receive further
+ * events on group modification/creation/destruction.
+ *
+ * @param listener the ServerStoredGroupListener to unregister.
+ */
+ public void removeGroupListener(ServerStoredGroupListener listener)
+ {
+ synchronized (serverStoredGroupListeners)
+ {
+ this.serverStoredGroupListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Creates the corresponding event and notifies all
+ * <tt>ServerStoredGroupListener</tt>s that the source group has been
+ * removed, changed, renamed or whatever happened to it.
+ *
+ * @param group the ContactGroup that has been created/modified/removed.
+ * @param eventID the id of the event to generate.
+ */
+ void fireGroupEvent(ContactGroup group, int eventID)
+ {
+ ServerStoredGroupEvent event = new ServerStoredGroupEvent(
+ group,
+ eventID,
+ parentOperationSet.getServerStoredContactListRoot(),
+ sipProvider,
+ parentOperationSet);
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("Will dispatch the following group event: " + event);
+ }
+ Iterable<ServerStoredGroupListener> listeners;
+ synchronized (serverStoredGroupListeners)
+ {
+ listeners =
+ new ArrayList<ServerStoredGroupListener>(
+ serverStoredGroupListeners);
+ }
+ for (ServerStoredGroupListener listener : listeners)
+ {
+ if (eventID == ServerStoredGroupEvent.GROUP_REMOVED_EVENT)
+ {
+ listener.groupRemoved(event);
+ }
+ else if (eventID == ServerStoredGroupEvent.GROUP_RENAMED_EVENT)
+ {
+ listener.groupNameChanged(event);
+ }
+ else if (eventID == ServerStoredGroupEvent.GROUP_CREATED_EVENT)
+ {
+ listener.groupCreated(event);
+ }
+ else if (eventID == ServerStoredGroupEvent.GROUP_RESOLVED_EVENT)
+ {
+ listener.groupResolved(event);
+ }
+ }
+ }
+
+ /**
+ * Creates a non resolved contact for the specified address and inside the
+ * specified group. The newly created contact would be added to the local
+ * contact list as a standard contact but when an event is received from the
+ * server concerning this contact, then it will be reused and only its
+ * isResolved field would be updated instead of creating the whole contact
+ * again. If creation is successfull event will be fired.
+ *
+ * @param parentGroup the group where the unersolved contact is to be
+ * created.
+ * @param contactId the sip id of the contact to create.
+ * @return the newly created unresolved <tt>ContactSipImpl</tt>.
+ */
+ public synchronized ContactSipImpl createUnresolvedContact(
+ ContactGroupSipImpl parentGroup, String contactId)
+ {
+ if (parentGroup == null)
+ {
+ throw new IllegalArgumentException("Parent group cannot be null");
+ }
+ if (contactId == null || contactId.length() == 0)
+ {
+ throw new IllegalArgumentException(
+ "Creating contact id name cannot be null or empty");
+ }
+ Address contactAddress;
+ try
+ {
+ contactAddress = sipProvider.parseAddressString(contactId);
+ }
+ catch (ParseException ex)
+ {
+ throw new IllegalArgumentException(
+ String.format("%1s is no a valid SIP identifier",
+ contactId),
+ ex);
+ }
+ logger.trace("createUnresolvedContact " + contactId);
+ ContactSipImpl newUnresolvedContact = new ContactSipImpl(contactAddress,
+ sipProvider);
+ parentGroup.addContact(newUnresolvedContact);
+ fireContactAdded(parentGroup, newUnresolvedContact);
+ return newUnresolvedContact;
+ }
+
+ /**
+ * Creates contact for the specified address and inside the
+ * specified group . If creation is successfull event will be fired.
+ *
+ * @param parentGroup the group where the unersolved contact is to be
+ * created.
+ * @param contactId the sip id of the contact to create.
+ * @param persistent specify whether created contact is persistent ot not.
+ * @return the newly created <tt>ContactSipImpl</tt>.
+ * @throws OperationFailedException with code NETWORK_FAILURE if the
+ * operation if failed during network
+ * communication.
+ */
+ synchronized public ContactSipImpl createContact(
+ ContactGroupSipImpl parentGroup, String contactId,
+ boolean persistent)
+ throws OperationFailedException
+ {
+ if (parentGroup == null)
+ {
+ throw new IllegalArgumentException("Parent group cannot be null");
+ }
+ if (contactId == null || contactId.trim().length() == 0)
+ {
+ throw new IllegalArgumentException(
+ "Contact identifier cannot be null or empty");
+ }
+ if (logger.isTraceEnabled())
+ {
+ logger.trace(
+ String.format("createContact %1s, %2s, %3s",
+ parentGroup.getGroupName(), contactId, persistent));
+ }
+ if (parentGroup.getContact(contactId) != null)
+ {
+ throw new OperationFailedException(
+ "Contact " + contactId + " already exists.",
+ OperationFailedException.SUBSCRIPTION_ALREADY_EXISTS);
+ }
+ Address contactAddress;
+ try
+ {
+ contactAddress = sipProvider.parseAddressString(contactId);
+ }
+ catch (ParseException ex)
+ {
+ throw new IllegalArgumentException(contactId +
+ " is not a valid string.", ex);
+ }
+
+ ContactSipImpl newContact = new ContactSipImpl(contactAddress,
+ sipProvider);
+ newContact.setPersistent(persistent);
+ String name = ((SipURI) contactAddress.getURI()).getUser();
+ newContact.setDisplayName(name);
+ parentGroup.addContact(newContact);
+ if (newContact.isPersistent())
+ {
+ // Update resoure-lists
+ try
+ {
+ updateResourceLists();
+ }
+ catch (XCapException e)
+ {
+ parentGroup.removeContact(newContact);
+ throw new OperationFailedException(
+ "Error while creating XCAP contact",
+ OperationFailedException.NETWORK_FAILURE, e);
+ }
+ // Update pres-rules if needed
+ if (!isContactExistsInWhiteRule(contactId))
+ {
+ // Update pres-rules
+ addContactToWhiteList(newContact);
+ try
+ {
+ updatePresRules();
+ }
+ catch (XCapException e)
+ {
+ logger.error("Error while creating XCAP contact", e);
+ }
+ }
+ }
+ fireContactAdded(parentGroup, newContact);
+ return newContact;
+ }
+
+ /**
+ * Removes a contact. If creation is successfull event will be fired.
+ *
+ * @param contact contact to be removed.
+ * @throws OperationFailedException with code NETWORK_FAILURE if the
+ * operation if failed during network
+ * communication.
+ */
+ synchronized public void removeContact(ContactSipImpl contact)
+ throws OperationFailedException
+ {
+ if (contact == null)
+ {
+ throw new IllegalArgumentException(
+ "Removing contact cannot be null");
+ }
+ logger.trace("removeContact " + contact.getUri());
+ ContactGroupSipImpl parentGroup =
+ (ContactGroupSipImpl) contact.getParentContactGroup();
+ parentGroup.removeContact(contact);
+ if (contact.isPersistent())
+ {
+ // Update resoure-lists
+ try
+ {
+ updateResourceLists();
+ }
+ catch (XCapException e)
+ {
+ parentGroup.removeContact(contact);
+ throw new OperationFailedException(
+ "Error while removing XCAP contact",
+ OperationFailedException.NETWORK_FAILURE, e);
+ }
+ // Update pres-rules if contact doesn't exist
+ if (!isContactPersistent(contact.getUri()))
+ {
+ removeContactFromWhiteList(contact);
+ try
+ {
+ updatePresRules();
+ }
+ catch (XCapException e)
+ {
+ logger.error("Error while removing XCAP contact", e);
+ }
+ }
+ }
+ fireContactRemoved(parentGroup, contact);
+ }
+
+ /**
+ * Removes the specified contact from its current parent and places it
+ * under <tt>newParent</tt>.
+ *
+ * @param contact the <tt>Contact</tt> to move
+ * @param newParentGroup the <tt>ContactGroup</tt> where <tt>Contact</tt>
+ * would be placed.
+ * @throws OperationFailedException with code NETWORK_FAILURE if the
+ * operation if failed during network
+ * communication.
+ */
+ public void moveContactToGroup(
+ ContactSipImpl contact,
+ ContactGroupSipImpl newParentGroup)
+ throws OperationFailedException
+ {
+ if (contact == null)
+ {
+ throw new IllegalArgumentException(
+ "Moving contact cannot be null");
+ }
+ if (newParentGroup == null)
+ {
+ throw new IllegalArgumentException(
+ "New contact's parent group be null");
+ }
+ if (newParentGroup.getContact(contact.getUri()) != null)
+ {
+ throw new OperationFailedException(
+ "Contact " + contact.getUri() + " already exists.",
+ OperationFailedException.SUBSCRIPTION_ALREADY_EXISTS);
+ }
+ ContactGroupSipImpl oldParentGroup =
+ (ContactGroupSipImpl) contact.getParentContactGroup();
+ oldParentGroup.removeContact(contact);
+ newParentGroup.addContact(contact);
+ if (contact.isPersistent())
+ {
+ try
+ {
+ updateResourceLists();
+ }
+ catch (XCapException e)
+ {
+ newParentGroup.removeContact(contact);
+ oldParentGroup.addContact(contact);
+ throw new OperationFailedException(
+ "Error while moving XCAP contact",
+ OperationFailedException.NETWORK_FAILURE, e);
+ }
+ }
+ fireContactMoved(oldParentGroup, newParentGroup, contact);
+ }
+
+ /**
+ * Renames the specified contac.
+ *
+ * @param contact the contact to be renameed.
+ * @param newName the new contact name.
+ * @throws OperationFailedException with code NETWORK_FAILURE if the
+ * operation if failed during network
+ * communication.
+ */
+ synchronized public void renameContact(
+ ContactSipImpl contact,
+ String newName)
+ throws OperationFailedException
+ {
+ if (contact == null)
+ {
+ throw new IllegalArgumentException(
+ "Renaming contact cannot be null");
+ }
+ String oldName = contact.getDisplayName();
+ if (oldName.equals(newName))
+ {
+ return;
+ }
+ contact.setDisplayName(newName);
+ if (contact.isPersistent())
+ {
+ try
+ {
+ updateResourceLists();
+ }
+ catch (XCapException e)
+ {
+ contact.setDisplayName(oldName);
+ throw new OperationFailedException(
+ "Error while renaming XCAP group",
+ OperationFailedException.NETWORK_FAILURE, e);
+ }
+ }
+ parentOperationSet.fireContactPropertyChangeEvent(
+ ContactPropertyChangeEvent.PROPERTY_DISPLAY_NAME,
+ contact,
+ oldName,
+ newName);
+ }
+
+
+ /**
+ * Creates a non resolved contact group for the specified name. The newly
+ * created group would be added to the local contact list as any other group
+ * but when an event is received from the server concerning this group, then
+ * it will be reused and only its isResolved field would be updated instead
+ * of creating the whole group again.
+ * <p/>
+ *
+ * @param parentGroup the group under which the new group is to be created.
+ * @param groupName the name of the group to create.
+ * @return the newly created unresolved <tt>ContactGroupSipImpl</tt>.
+ */
+ synchronized public ContactGroupSipImpl createUnresolvedContactGroup(
+ ContactGroupSipImpl parentGroup,
+ String groupName)
+ {
+ if (parentGroup == null)
+ {
+ throw new IllegalArgumentException("Parent group cannot be null");
+ }
+ if (groupName == null || groupName.length() == 0)
+ {
+ throw new IllegalArgumentException(
+ "Creating group name cannot be null or empry");
+ }
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("createUnresolvedContactGroup " + groupName);
+ }
+ ContactGroupSipImpl subGroup = new ContactGroupSipImpl(groupName,
+ sipProvider);
+ subGroup.setResolved(false);
+ parentGroup.addSubgroup(subGroup);
+ fireGroupEvent(subGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ return subGroup;
+ }
+
+ /**
+ * Creates a group with the specified name and parent in the server stored
+ * contact list.
+ *
+ * @param parentGroup the group where the new group should be created.
+ * @param groupName the name of the new group to create.
+ * @param persistent specify whether created contact is persistent ot not.
+ * @return the newly created <tt>ContactGroupSipImpl</tt>.
+ * @throws OperationFailedException with code NETWORK_FAILURE if creating
+ * the group fails because of XCAP server
+ * error or with code
+ * CONTACT_GROUP_ALREADY_EXISTS if contact
+ * group with such name already exists.
+ */
+ synchronized public ContactGroupSipImpl createGroup(
+ ContactGroupSipImpl parentGroup, String groupName,
+ boolean persistent)
+ throws OperationFailedException
+ {
+ if (parentGroup == null)
+ {
+ throw new IllegalArgumentException("Parent group cannot be null");
+ }
+ if (groupName == null || groupName.length() == 0)
+ {
+ throw new IllegalArgumentException(
+ "Creating group name cannot be null or empry");
+ }
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("createGroup " + parentGroup.getGroupName() + ","
+ + groupName + "," + persistent);
+ }
+ if (parentGroup.getGroup(groupName) != null)
+ {
+ throw new OperationFailedException(
+ String.format("Group %1s already exists.", groupName),
+ OperationFailedException.CONTACT_GROUP_ALREADY_EXISTS);
+ }
+ ContactGroupSipImpl subGroup =
+ new ContactGroupSipImpl(groupName, sipProvider);
+ subGroup.setPersistent(persistent);
+ parentGroup.addSubgroup(subGroup);
+ if (subGroup.isPersistent())
+ {
+ try
+ {
+ updateResourceLists();
+ }
+ catch (XCapException e)
+ {
+ parentGroup.removeSubGroup(subGroup);
+ throw new OperationFailedException(
+ "Error while creating XCAP group",
+ OperationFailedException.NETWORK_FAILURE, e);
+ }
+ }
+ fireGroupEvent(subGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ return subGroup;
+ }
+
+ /**
+ * Removes the specified group from the server stored contact list.
+ *
+ * @param group the group to delete.
+ */
+ synchronized public void removeGroup(ContactGroupSipImpl group)
+ {
+ if (group == null)
+ {
+ throw new IllegalArgumentException("Removing group cannot be null");
+ }
+ if (rootGroup.equals(group))
+ {
+ throw new IllegalArgumentException("Root group cannot be deleted");
+ }
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("removeGroup " + group.getGroupName());
+ }
+ ContactGroupSipImpl parentGroup =
+ (ContactGroupSipImpl) group.getParentContactGroup();
+ parentGroup.removeSubGroup(group);
+ if (group.isPersistent())
+ {
+ try
+ {
+ updateResourceLists();
+ }
+ catch (XCapException e)
+ {
+ parentGroup.addSubgroup(group);
+ throw new IllegalStateException(
+ "Error while removing XCAP group", e);
+ }
+ }
+ fireGroupEvent(group, ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
+ }
+
+ /**
+ * Renames the specified group from the server stored contact list.
+ *
+ * @param group the group to rename.
+ * @param newName the new name of the group.
+ */
+ synchronized public void renameGroup(
+ ContactGroupSipImpl group,
+ String newName)
+ {
+ if (group == null)
+ {
+ throw new IllegalArgumentException("Renaming group cannot be null");
+ }
+ if (rootGroup.equals(group))
+ {
+ throw new IllegalArgumentException("Root group cannot be renamed");
+ }
+ String oldName = group.getGroupName();
+ if (oldName.equals(newName))
+ {
+ return;
+ }
+ ContactGroupSipImpl parentGroup =
+ (ContactGroupSipImpl) group.getParentContactGroup();
+ if (parentGroup.getGroup(newName) != null)
+ {
+ throw new IllegalStateException(
+ String.format("Group with name %1s already exists",
+ newName));
+ }
+ group.setName(newName);
+ if (group.isPersistent())
+ {
+ try
+ {
+ updateResourceLists();
+ }
+ catch (XCapException e)
+ {
+ group.setName(oldName);
+ throw new IllegalStateException(
+ "Error while renaming XCAP group", e);
+ }
+ }
+ fireGroupEvent(group, ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
+ }
+
+ /**
+ * Make the parent persistent presence operation set dispatch a contact
+ * added event.
+ *
+ * @param parentGroup the group where the new contact was added.
+ * @param contact the contact that was added.
+ */
+ private void fireContactAdded(
+ ContactGroupSipImpl parentGroup,
+ ContactSipImpl contact)
+ {
+ parentOperationSet.fireSubscriptionEvent(
+ contact,
+ parentGroup,
+ SubscriptionEvent.SUBSCRIPTION_CREATED);
+ }
+
+ /**
+ * Make the parent persistent presence operation set dispatch a subscription
+ * moved event.
+ *
+ * @param oldParentGroup the group where the source contact was located
+ * before being moved.
+ * @param newParentGroup the group that the source contact is currently in.
+ * @param contact the contact that was added.
+ */
+ private void fireContactMoved(
+ ContactGroupSipImpl oldParentGroup,
+ ContactGroupSipImpl newParentGroup,
+ ContactSipImpl contact)
+ {
+ parentOperationSet.fireSubscriptionMovedEvent(
+ contact,
+ oldParentGroup,
+ newParentGroup);
+ }
+
+ /**
+ * Make the parent persistent presence operation set dispatch a contact
+ * removed event.
+ *
+ * @param parentGroup the group where that the removed contact belonged to.
+ * @param contact the contact that was removed.
+ */
+ private void fireContactRemoved(
+ ContactGroupSipImpl parentGroup,
+ ContactSipImpl contact)
+ {
+ parentOperationSet.fireSubscriptionEvent(
+ contact,
+ parentGroup,
+ SubscriptionEvent.SUBSCRIPTION_REMOVED);
+ }
+
+ /**
+ * Make the parent persistent presence operation set dispatch a contact
+ * resolved event.
+ *
+ * @param parentGroup the group that the resolved contact belongs to.
+ * @param contact the contact that was resolved.
+ */
+ private void fireContactResolved(
+ ContactGroupSipImpl parentGroup,
+ ContactSipImpl contact)
+ {
+ parentOperationSet.fireSubscriptionEvent(
+ contact,
+ parentGroup,
+ SubscriptionEvent.SUBSCRIPTION_RESOLVED);
+ }
+
+ /**
+ * Initializes the server stored list. Synchronize server stored groups and
+ * contacts with the local groups and contacts.
+ */
+ synchronized public void init()
+ {
+ try
+ {
+ XCapClient xCapClient = sipProvider.getXCapClient();
+ if (!xCapClient.isConnected() ||
+ !xCapClient.isResourceListsSupported())
+ {
+ return;
+ }
+ ResourceListsType resourceLists = xCapClient.getResourceLists();
+ // Collect all root's subgroups to check if some of them were deleted
+ ListType serverRootList = new ListType();
+ //serverRootList.getLists().addAll(resourceLists.getList());
+ for (ListType list : resourceLists.getList())
+ {
+ // If root group has sub group with ROOT_GROUP_NAME - it is
+ // special group for storing contacts that is not allowed by RFC
+ if (list.getName().equals(ROOT_GROUP_NAME))
+ {
+ serverRootList.setName(ROOT_GROUP_NAME);
+ serverRootList.setDisplayName(list.getDisplayName());
+ serverRootList.getEntries().addAll(list.getEntries());
+ serverRootList.getEntryRefs().addAll(list.getEntryRefs());
+ serverRootList.getExternals().addAll(list.getExternals());
+ serverRootList.setAny(list.getAny());
+ serverRootList
+ .setAnyAttributes(list.getAnyAttributes());
+ }
+ else
+ {
+ serverRootList.getLists().add(list);
+ }
+ }
+ resolveContactGroup(rootGroup, serverRootList);
+ if (xCapClient.isPresRulesSupported())
+ {
+ // Get pres-rules and analyze it
+ presRules = xCapClient.getPresRules();
+ for (RuleType rule : presRules.getRule())
+ {
+ if (rule.getId().equals(WHITE_RULE_ID))
+ {
+ whiteRule = rule;
+ break;
+ }
+ }
+ // If "white" rule is available refresh it
+ if (whiteRule != null)
+ {
+ presRules.getRule().remove(whiteRule);
+ }
+ whiteRule = createWhiteRule();
+ presRules.getRule().add(whiteRule);
+ // Add contacts into the "white" rule
+ List<ContactSipImpl> uniqueContacts =
+ getUniqueContacts(rootGroup);
+ for (ContactSipImpl contact : uniqueContacts)
+ {
+ addContactToWhiteList(contact);
+ }
+ updatePresRules();
+ }
+ }
+ catch (XCapException e)
+ {
+ logger.error(e);
+ }
+ }
+
+ /**
+ * Destroys the server stored list.
+ */
+ synchronized public void destroy()
+ {
+ List<ContactSipImpl> contacts = getAllContacts(rootGroup);
+ for (ContactSipImpl contact : contacts)
+ {
+ contact.setResolvable(false);
+ }
+ presRules = null;
+ whiteRule = null;
+ }
+
+ /**
+ * Creates "white" rule with full permissions.
+ *
+ * @return created rule.
+ */
+ private static RuleType createWhiteRule()
+ {
+ RuleType whiteList = new RuleType();
+ whiteList.setId(WHITE_RULE_ID);
+
+ ConditionsType conditions = new ConditionsType();
+ whiteList.setConditions(conditions);
+
+ ActionsType actions = new ActionsType();
+ actions.setSubHandling(SubHandlingType.Allow);
+ whiteList.setActions(actions);
+
+ TransfomationsType transfomations = new TransfomationsType();
+ ProvideServicePermission servicePermission =
+ new ProvideServicePermission();
+ servicePermission.setAllServices(
+ new ProvideServicePermission.AllServices());
+ transfomations.setServicePermission(servicePermission);
+ ProvidePersonPermission personPermission =
+ new ProvidePersonPermission();
+ personPermission.setAllPersons(
+ new ProvidePersonPermission.AllPersons());
+ transfomations.setPersonPermission(personPermission);
+ ProvideDevicePermission devicePermission =
+ new ProvideDevicePermission();
+ devicePermission.setAllDevices(
+ new ProvideDevicePermission.AllDevices());
+ transfomations.setDevicePermission(devicePermission);
+ whiteList.setTransformations(transfomations);
+
+ return whiteList;
+ }
+
+ /**
+ * Adds contact to the "white" rule.
+ *
+ * @param contact the contact to add.
+ */
+ private void addContactToWhiteList(ContactSipImpl contact)
+ {
+ XCapClient xCapClient = sipProvider.getXCapClient();
+ if (!xCapClient.isConnected() || !xCapClient.isPresRulesSupported())
+ {
+ return;
+ }
+ IdentityType identity;
+ if (whiteRule.getConditions().getIdentityOrSphereOrValidity().
+ size() == 0)
+ {
+ identity = new IdentityType();
+ whiteRule.getConditions().getIdentityOrSphereOrValidity()
+ .add(identity);
+ }
+ else
+ {
+ identity = (IdentityType) whiteRule.getConditions()
+ .getIdentityOrSphereOrValidity().get(0);
+ }
+ OneType one = new OneType();
+ one.setId(contact.getUri());
+ identity.getOneList().add(one);
+ }
+
+ /**
+ * Indicates whether or not contact is exists in the "white" rule.
+ *
+ * @param contactUri the contact uri.
+ * @return true if contact is exists, false if not.
+ */
+ private boolean isContactExistsInWhiteRule(String contactUri)
+ {
+ XCapClient xCapClient = sipProvider.getXCapClient();
+ if (!xCapClient.isConnected() || !xCapClient.isPresRulesSupported())
+ {
+ return false;
+ }
+ IdentityType identity;
+ if (whiteRule.getConditions().getIdentityOrSphereOrValidity().
+ size() == 0)
+ {
+ return false;
+ }
+ identity = (IdentityType) whiteRule.getConditions()
+ .getIdentityOrSphereOrValidity().get(0);
+ for (OneType one : identity.getOneList())
+ {
+ if (one.getId().equals(contactUri))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes contact from the "white" rule.
+ *
+ * @param contact the contact to remove.
+ */
+ private void removeContactFromWhiteList(ContactSipImpl contact)
+ {
+ XCapClient xCapClient = sipProvider.getXCapClient();
+ if (!xCapClient.isConnected() || !xCapClient.isPresRulesSupported())
+ {
+ return;
+ }
+ IdentityType identity = (IdentityType)
+ whiteRule.getConditions().getIdentityOrSphereOrValidity().
+ get(0);
+ OneType contactOne = null;
+ for (OneType one : identity.getOneList())
+ {
+ if (contact.getUri().equals(one.getId()))
+ {
+ contactOne = one;
+ break;
+ }
+ }
+ if (contactOne != null)
+ {
+ identity.getOneList().remove(contactOne);
+ }
+ if (identity.getOneList().size() == 0)
+ {
+ whiteRule.getConditions().getIdentityOrSphereOrValidity().
+ remove(identity);
+ }
+ }
+
+ /**
+ * Returns all avaliable contacts from group and all subgroups.
+ *
+ * @param group the parent of the contacts.
+ * @return list of availcable contacts.
+ */
+ public synchronized List<ContactSipImpl> getAllContacts(
+ ContactGroupSipImpl group)
+ {
+ List<ContactSipImpl> contacts = new ArrayList<ContactSipImpl>();
+ Iterator<ContactGroup> groupIterator = group.subgroups();
+ while (groupIterator.hasNext())
+ {
+ contacts.addAll(
+ getAllContacts((ContactGroupSipImpl) groupIterator.next()));
+ }
+ Iterator<Contact> contactIterator = group.contacts();
+ while (contactIterator.hasNext())
+ {
+ ContactSipImpl contact = (ContactSipImpl) contactIterator.next();
+ contacts.add(contact);
+ }
+ return contacts;
+ }
+
+ /**
+ * Gets all unique contacts from group and all subgroups.
+ *
+ * @param group the parent of the contacts.
+ * @return List of available contacts
+ */
+ public synchronized List<ContactSipImpl> getUniqueContacts(
+ ContactGroupSipImpl group)
+ {
+ Map<String, ContactSipImpl> uniqueContacts =
+ new HashMap<String, ContactSipImpl>();
+ List<ContactSipImpl> contacts = getAllContacts(group);
+ for (ContactSipImpl contact : contacts)
+ {
+ uniqueContacts.put(contact.getUri(), contact);
+ }
+ return new ArrayList<ContactSipImpl>(uniqueContacts.values());
+ }
+
+ /**
+ * Indicates whether or not contact is exists.
+ *
+ * @param contactUri the contact uri.
+ * @return true if contact is exists, false if not.
+ */
+ private boolean isContactExists(String contactUri)
+ {
+ for (ContactSipImpl uniqueContact : getUniqueContacts(rootGroup))
+ {
+ if (uniqueContact.getUri().equals(contactUri))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets all contacts with the specified uri.
+ *
+ * @param contactUri the contact uri.
+ * @return the list of the contacts.
+ */
+ private List<ContactSipImpl> getContacts(String contactUri)
+ {
+ List<ContactSipImpl> result = new ArrayList<ContactSipImpl>();
+ for (ContactSipImpl contact : getAllContacts(rootGroup))
+ {
+ if (contact.getUri().equals(contactUri))
+ {
+ result.add(contact);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Indicates whether or not contact is exists.
+ *
+ * @param contactUri contactUri the contact uri.
+ * @return true if at least one contact is persistent, false if not.
+ */
+ private boolean isContactPersistent(String contactUri)
+ {
+ for (ContactSipImpl contact : getContacts(contactUri))
+ {
+ if (contact.isPersistent())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Resolves local group with server stored group.
+ * <p/>
+ * If local group exsists GROUP_CREATED_RESOLVED will be fired.
+ * <p/>
+ * If local group doesn't exsist GROUP_CREATED_EVENT will be fired.
+ * <p/>
+ * If server group doesn't represented GROUP_REMOVED_EVENT will be fired.
+ *
+ * @param clientGroup the local group.
+ * @param serverGroup the server stored group.
+ */
+ private void resolveContactGroup(
+ ContactGroupSipImpl clientGroup,
+ ListType serverGroup)
+ {
+ // Gather client information
+ List<ContactGroupSipImpl> unresolvedGroups =
+ new ArrayList<ContactGroupSipImpl>();
+ Iterator<ContactGroup> groupIterator = clientGroup.subgroups();
+ while (groupIterator.hasNext())
+ {
+ ContactGroupSipImpl group =
+ (ContactGroupSipImpl) groupIterator.next();
+ unresolvedGroups.add(group);
+ }
+ List<ContactSipImpl> unresolvedContacts =
+ new ArrayList<ContactSipImpl>();
+ Iterator<Contact> contactIterator = clientGroup.contacts();
+ while (contactIterator.hasNext())
+ {
+ ContactSipImpl contact = (ContactSipImpl) contactIterator.next();
+ unresolvedContacts.add(contact);
+ }
+ // Process all server groups and fire events
+ for (ListType serverList : serverGroup.getLists())
+ {
+ ContactGroupSipImpl newGroup =
+ (ContactGroupSipImpl) clientGroup.getGroup(
+ serverList.getName());
+ if (newGroup == null)
+ {
+ newGroup = new ContactGroupSipImpl(serverList.getName(),
+ sipProvider);
+ newGroup.setOtherAttributes(serverList.getAnyAttributes());
+ newGroup.setAny(serverList.getAny());
+ newGroup.setResolved(true);
+ clientGroup.addSubgroup(newGroup);
+ // Tell listeners about the added group
+
+ fireGroupEvent(newGroup,
+ ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ resolveContactGroup(newGroup, serverList);
+ }
+ else
+ {
+ newGroup.setResolved(true);
+ newGroup.setOtherAttributes(serverList.getAnyAttributes());
+ newGroup.setAny(serverList.getAny());
+ unresolvedGroups.remove(newGroup);
+ // Tell listeners about the resolved group
+
+ fireGroupEvent(newGroup,
+ ServerStoredGroupEvent.GROUP_RESOLVED_EVENT);
+ resolveContactGroup(newGroup, serverList);
+ }
+ }
+ // Process all server contacts and fire events
+ for (EntryType serverEntry : serverGroup.getEntries())
+ {
+ ContactSipImpl newContact =
+ (ContactSipImpl) clientGroup.getContact(
+ serverEntry.getUri());
+ if (newContact == null)
+ {
+ Address sipAddress;
+ try
+ {
+ sipAddress =
+ sipProvider.parseAddressString(
+ serverEntry.getUri());
+ }
+ catch (ParseException e)
+ {
+ logger.error(e);
+ continue;
+ }
+ newContact = new ContactSipImpl(sipAddress, sipProvider);
+ newContact.setDisplayName(serverEntry.getDisplayName());
+ newContact.setOtherAttributes(serverEntry.getAnyAttributes());
+ newContact.setAny(serverEntry.getAny());
+ newContact.setResolved(true);
+ clientGroup.addContact(newContact);
+
+ fireContactAdded(clientGroup, newContact);
+ }
+ else
+ {
+ newContact.setDisplayName(serverEntry.getDisplayName());
+ newContact.setOtherAttributes(serverEntry.getAnyAttributes());
+ newContact.setAny(serverEntry.getAny());
+ newContact.setResolved(true);
+ unresolvedContacts.remove(newContact);
+
+ fireContactResolved(clientGroup, newContact);
+ }
+ }
+ // Save all others
+ // TODO: process externals and enrty-refs after sip2sip fixes
+ clientGroup.getList().getExternals().addAll(serverGroup.getExternals());
+ clientGroup.getList().getEntryRefs().addAll(serverGroup.getEntryRefs());
+ clientGroup.getList().getAny().addAll(serverGroup.getAny());
+
+ // Remove unresolved contacts
+ for (ContactSipImpl unresolvedContact : unresolvedContacts)
+ {
+ unresolvedContact.setResolved(true);
+ clientGroup.removeContact(unresolvedContact);
+ // Tell listeners about the removed contact
+
+ fireContactRemoved(clientGroup, unresolvedContact);
+ }
+ // Remove unresolved groups
+ for (ContactGroupSipImpl unresolvedGroup : unresolvedGroups)
+ {
+ unresolvedGroup.setResolved(true);
+ clientGroup.removeSubGroup(unresolvedGroup);
+ // Tell listeners about the removed group
+
+ fireGroupEvent(unresolvedGroup,
+ ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
+ }
+ }
+
+ /**
+ * Puts resource-lists to the server.
+ *
+ * @throws XCapException if there is some error during operation.
+ */
+ synchronized private void updateResourceLists()
+ throws XCapException
+ {
+ XCapClient xCapClient = sipProvider.getXCapClient();
+ if (!xCapClient.isConnected() || !xCapClient.isResourceListsSupported())
+ {
+ return;
+ }
+ ResourceListsType resourceLists = new ResourceListsType();
+ for (ListType list : rootGroup.getList().getLists())
+ {
+ resourceLists.getList().add(list);
+ }
+ // Create special root group
+ ListType serverRootList = new ListType();
+ serverRootList.setName(ROOT_GROUP_NAME);
+ serverRootList.setDisplayName(rootGroup.getList().getDisplayName());
+ serverRootList.getEntries().addAll(rootGroup.getList().getEntries());
+ serverRootList.getEntryRefs()
+ .addAll(rootGroup.getList().getEntryRefs());
+ serverRootList.getExternals()
+ .addAll(rootGroup.getList().getExternals());
+ serverRootList.setAny(rootGroup.getList().getAny());
+ serverRootList
+ .setAnyAttributes(rootGroup.getList().getAnyAttributes());
+ resourceLists.getList().add(serverRootList);
+
+ xCapClient.putResourceLists(resourceLists);
+ }
+
+ /**
+ * Puts pres-rules to the server.
+ *
+ * @throws XCapException if there is some error during operation.
+ */
+ synchronized private void updatePresRules()
+ throws XCapException
+ {
+ XCapClient xCapClient = sipProvider.getXCapClient();
+ if (!xCapClient.isConnected() || !xCapClient.isPresRulesSupported())
+ {
+ return;
+ }
+ xCapClient.putPresRules(presRules);
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
index 30827e4..55a9d2d 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/sip/sip.provider.manifest.mf
@@ -5,6 +5,32 @@ Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.apache.log4j,
+ org.apache.http,
+ org.apache.http.entity,
+ org.apache.http.impl,
+ org.apache.http.impl.entity,
+ org.apache.http.impl.io,
+ org.apache.http.io,
+ org.apache.http.message,
+ org.apache.http.params,
+ org.apache.http.protocol,
+ org.apache.http.util,
+ org.apache.http.annotation,
+ org.apache.http.auth,
+ org.apache.http.auth.params,
+ org.apache.http.client,
+ org.apache.http.client.entity,
+ org.apache.http.client.methods,
+ org.apache.http.client.params,
+ org.apache.http.client.protocol,
+ org.apache.http.client.utils,
+ org.apache.http.conn,
+ org.apache.http.conn.params,
+ org.apache.http.conn.routing,
+ org.apache.http.conn.scheme,
+ org.apache.http.conn.ssl,
+ org.apache.http.conn.util,
+ org.apache.http.impl.client,
org.osgi.framework,
org.w3c.dom,
org.xml.sax,
@@ -25,7 +51,20 @@ Import-Package: org.apache.log4j,
net.java.sip.communicator.util,
net.java.sip.communicator.util.xml,
javax.net.ssl,
+ javax.security.auth.x500,
+ javax.xml.datatype,
javax.xml.parsers,
+ javax.xml.namespace,
javax.xml.transform,
javax.xml.transform.dom,
- javax.xml.transform.stream
+ javax.xml.transform.stream,
+Export-Package: net.java.sip.communicator.impl.protocol.sip,
+ net.java.sip.communicator.impl.protocol.sip.xcap,
+ net.java.sip.communicator.impl.protocol.sip.xcap.utils,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror
+
+
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/BaseHttpXCapClient.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/BaseHttpXCapClient.java
new file mode 100644
index 0000000..4467c29
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/BaseHttpXCapClient.java
@@ -0,0 +1,483 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.utils.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror.*;
+import net.java.sip.communicator.util.*;
+import org.apache.http.*;
+import org.apache.http.auth.*;
+import org.apache.http.client.methods.*;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.params.*;
+
+import javax.sip.address.*;
+import java.io.*;
+import java.net.URI;
+import java.net.*;
+
+/**
+ * Base HTTP XCAP client implementation.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public abstract class BaseHttpXCapClient implements HttpXCapClient
+{
+ /**
+ * Class logger.
+ */
+ private static final Logger logger =
+ Logger.getLogger(BaseHttpXCapClient.class);
+
+ /**
+ * HTTP Content-Type header.
+ */
+ public static final String HEADER_CONTENT_TYPE = "Content-Type";
+
+ /**
+ * HTTP ETag header.
+ */
+ public static final String HEADER_ETAG = "ETag";
+
+ /**
+ * HTTP If-None-Match header.
+ */
+ public static final String HEADER_IF_NONE_MATCH = "If-None-Match";
+
+ /**
+ * XCap-error content type.
+ */
+ public static final String XCAP_ERROR_CONTENT_TYPE
+ = "application/xcap-error+xml";
+
+ /**
+ * The default timeout (10 seconds)
+ */
+ private static int DEFAULT_TIMEOUT = 10 * 1000;
+
+ /**
+ * Current server uri.
+ */
+ protected URI uri;
+
+ /**
+ * Current user.
+ */
+ protected Address userAddress;
+
+ /**
+ * Current user password.
+ */
+ private String password;
+
+ /**
+ * Indicates whether or not client is connected.
+ */
+ private boolean connected;
+
+ /**
+ * How many seconds should the client wait for HTTP response.
+ */
+ private int timeout;
+
+ /**
+ * Creates an instance of this XCAP client.
+ */
+ public BaseHttpXCapClient()
+ {
+ timeout = DEFAULT_TIMEOUT;
+ }
+
+ /**
+ * Connects user to XCap server.
+ *
+ * @param uri the server location.
+ * @param userAddress the user name.
+ * @param password the user password.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void connect(URI uri, Address userAddress, String password)
+ throws XCapException
+ {
+ if (!userAddress.getURI().isSipURI())
+ {
+ throw new IllegalArgumentException("Address must contains SipUri");
+ }
+ this.uri = uri;
+ this.userAddress = (Address) userAddress.clone();
+ this.password = password == null ? "" : password;
+ connected = true;
+ }
+
+ /**
+ * Checks if user is connected to the XCAP server.
+ *
+ * @return true if user is connected.
+ */
+ public boolean isConnected()
+ {
+ return connected;
+ }
+
+ /**
+ * Dicsonnects user from the XCAP server.
+ */
+ public void dicsonnect()
+ {
+ this.uri = null;
+ this.userAddress = null;
+ this.password = null;
+ connected = false;
+ }
+
+ /**
+ * Gets the resource from the server.
+ *
+ * @param resourceId resource identifier.
+ * @return the server response.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapHttpResponse get(XCapResourceId resourceId)
+ throws XCapException
+ {
+ return get(getResourceURI(resourceId));
+ }
+
+ /**
+ * Gets resource from the server.
+ *
+ * @param uri the resource uri.
+ * @return the server response.
+ * @throws XCapException if there is error during reading the resource's
+ * content.
+ */
+ protected XCapHttpResponse get(URI uri)
+ throws XCapException
+ {
+ DefaultHttpClient httpClient = createHttpClient();
+ try
+ {
+ HttpGet getMethod = new HttpGet(uri);
+ getMethod.setHeader("Connection", "close");
+ Credentials credentials =
+ new UsernamePasswordCredentials(getUserName(), password);
+ httpClient.getCredentialsProvider().
+ setCredentials(AuthScope.ANY, credentials);
+ if (logger.isDebugEnabled())
+ {
+ String logMessage = String.format(
+ "Getting resource %1s from the server",
+ uri.toString()
+ );
+ logger.debug(logMessage);
+ }
+ HttpResponse response = httpClient.execute(getMethod);
+ return createResponse(response);
+ }
+ catch (IOException e)
+ {
+ String errorMessage = String.format(
+ "%1s resource cannot be read",
+ uri.toString());
+ throw new XCapException(errorMessage, e);
+ }
+ finally
+ {
+ httpClient.getConnectionManager().shutdown();
+ }
+ }
+
+ /**
+ * Puts the resource to the server.
+ *
+ * @param resource the resource to be saved on the server.
+ * @return the server response.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapHttpResponse put(XCapResource resource)
+ throws XCapException
+ {
+ DefaultHttpClient httpClient = createHttpClient();
+ try
+ {
+ URI resourceUri = getResourceURI(resource.getId());
+ HttpPut putMethod = new HttpPut(resourceUri);
+ putMethod.setHeader("Connection", "close");
+ StringEntity stringEntity = new StringEntity(resource.getContent());
+ stringEntity.setContentType(resource.getContentType());
+ stringEntity.setContentEncoding("UTF-8");
+ putMethod.setEntity(stringEntity);
+ Credentials credentials =
+ new UsernamePasswordCredentials(getUserName(), password);
+ httpClient.getCredentialsProvider().
+ setCredentials(AuthScope.ANY, credentials);
+ if (logger.isDebugEnabled())
+ {
+ String logMessage = String.format(
+ "Puting resource %1s to the server %2s",
+ resource.getId().toString(),
+ resource.getContent()
+ );
+ logger.debug(logMessage);
+ }
+ HttpResponse response = httpClient.execute(putMethod);
+ return createResponse(response);
+ }
+ catch (IOException e)
+ {
+ String errorMessage = String.format(
+ "%1s resource cannot be put",
+ resource.getId().toString());
+ throw new XCapException(errorMessage, e);
+ }
+ finally
+ {
+ httpClient.getConnectionManager().shutdown();
+ }
+ }
+
+ /**
+ * Deletes the resource from the server.
+ *
+ * @param resourceId resource identifier.
+ * @return the server response.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapHttpResponse delete(XCapResourceId resourceId)
+ throws XCapException
+ {
+ assertConnected();
+ DefaultHttpClient httpClient = createHttpClient();
+ try
+ {
+ URI resourceUri = getResourceURI(resourceId);
+ HttpDelete deleteMethod = new HttpDelete(resourceUri);
+ deleteMethod.setHeader("Connection", "close");
+ Credentials credentials =
+ new UsernamePasswordCredentials(getUserName(), password);
+ httpClient.getCredentialsProvider().
+ setCredentials(AuthScope.ANY, credentials);
+ if (logger.isDebugEnabled())
+ {
+ String logMessage = String.format(
+ "Deleting resource %1s from the server",
+ resourceId.toString()
+ );
+ logger.debug(logMessage);
+ }
+ HttpResponse response = httpClient.execute(deleteMethod);
+ return createResponse(response);
+ }
+ catch (IOException e)
+ {
+ String errorMessage = String.format(
+ "%1s resource cannot be deleted",
+ resourceId.toString());
+ throw new XCapException(errorMessage, e);
+ }
+ finally
+ {
+ httpClient.getConnectionManager().shutdown();
+ }
+ }
+
+ /**
+ * Gets user name.
+ *
+ * @return the user name.
+ */
+ public String getUserName()
+ {
+ return userAddress != null ?
+ ((SipURI) userAddress.getURI()).getUser() : null;
+ }
+
+ /**
+ * Gets server uri.
+ *
+ * @return the server uri.
+ */
+ public URI getUri()
+ {
+ return uri;
+ }
+
+ /**
+ * Gets operation timeout.The deffault value is 10 seconds.
+ *
+ * @return operation timeout.
+ */
+ public int getTimeout()
+ {
+ return timeout;
+ }
+
+ /**
+ * Sets operation timeout. The deffault value is 10 seconds.
+ *
+ * @param timeout operation timeout.
+ */
+ public void setTimeout(int timeout)
+ {
+ this.timeout = timeout;
+ }
+
+ /**
+ * Utility method throwing an exception if the user is not connected.
+ *
+ * @throws IllegalStateException if the user is not connected.
+ */
+ protected void assertConnected()
+ {
+ if (!connected)
+ {
+ throw new IllegalStateException(
+ "User is not connected to the server");
+ }
+ }
+
+ /**
+ * Gets resource uri from XCAP resource identifier.
+ *
+ * @param resourceId the resource identifier.
+ * @return the resource uri.
+ */
+ protected URI getResourceURI(XCapResourceId resourceId)
+ {
+ try
+ {
+ return new URI(uri.toString() + "/" + resourceId);
+ }
+ catch (URISyntaxException e)
+ {
+ throw new IllegalArgumentException(
+ "Invalid XCAP resource identifier", e);
+ }
+ }
+
+ /**
+ * Creates HTTP client with special parameters.
+ *
+ * @return the HTTP client.
+ */
+ private DefaultHttpClient createHttpClient()
+ {
+ DefaultHttpClient httpClient = new DefaultHttpClient();
+ HttpParams httpParams = httpClient.getParams();
+ HttpConnectionParams.setConnectionTimeout(httpParams, timeout);
+ HttpConnectionParams.setSoTimeout(httpParams, timeout);
+ return httpClient;
+ }
+
+ /**
+ * Creates XCAP response from HTTP response.
+ * If HTTP code is 200, 201 or 409 the HTTP content would be readed.
+ *
+ * @param response the HTTP response.
+ * @return the XCAP response.
+ * @throws IOException if there is error during reading the HTTP content.
+ */
+ private XCapHttpResponse createResponse(HttpResponse response)
+ throws IOException
+ {
+ XCapHttpResponse XCapHttpResponse = new XCapHttpResponse();
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode == HttpStatus.SC_OK ||
+ statusCode == HttpStatus.SC_CREATED ||
+ statusCode == HttpStatus.SC_CONFLICT)
+ {
+ String contentType = getSingleHeaderValue(response,
+ HEADER_CONTENT_TYPE);
+ byte[] content = StreamUtils.read(
+ response.getEntity().getContent());
+ String eTag = getSingleHeaderValue(response, HEADER_ETAG);
+ XCapHttpResponse.setContentType(contentType);
+ XCapHttpResponse.setContent(content);
+ XCapHttpResponse.setETag(eTag);
+ }
+ XCapHttpResponse.setHttpCode(statusCode);
+ return XCapHttpResponse;
+ }
+
+ /**
+ * Reads response from http.
+ * @param response the response
+ * @return the result String.
+ * @throws IOException
+ */
+ private static String readResponse(HttpResponse response)
+ throws IOException
+ {
+ HttpEntity responseEntity = response.getEntity();
+ if (responseEntity.getContentLength() == 0)
+ {
+ return "";
+ }
+ byte[] content = StreamUtils.read(responseEntity.getContent());
+ return new String(content, "UTF-8");
+ }
+
+ /**
+ * Gets HTTP header value.
+ *
+ * @param response the HTTP response.
+ * @param headerName the header name.
+ * @return the header value.
+ */
+ protected static String getSingleHeaderValue(
+ HttpResponse response,
+ String headerName)
+ {
+ Header[] headers = response.getHeaders(headerName);
+ if (headers != null && headers.length > 0)
+ {
+ return headers[0].getValue();
+ }
+ return null;
+ }
+
+ /**
+ * Analyzes the response and returns xcap error or null
+ * if response doesn't have it.
+ *
+ * @param response the server response.
+ * @return xcap error or null.
+ */
+ protected String getXCapErrorMessage(XCapHttpResponse response)
+ {
+ int httpCode = response.getHttpCode();
+ String contentType = response.getContentType();
+ try
+ {
+ if (httpCode != HttpStatus.SC_CONFLICT || contentType == null ||
+ !contentType.startsWith(XCAP_ERROR_CONTENT_TYPE))
+ {
+ return null;
+ }
+ String content = new String(response.getContent());
+ XCapErrorType xCapError = XCapErrorParser.fromXml(content);
+ XCapError error = xCapError.getError();
+ if (error == null)
+ {
+ return null;
+ }
+ return error.getPhrase();
+ }
+ catch (ParsingException e)
+ {
+ logger.error("XCapError cannot be parsed.");
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/HttpXCapClient.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/HttpXCapClient.java
new file mode 100644
index 0000000..af71508
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/HttpXCapClient.java
@@ -0,0 +1,105 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+import javax.sip.address.*;
+import java.net.URI;
+
+/**
+ * HTTP XCAP client interface.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public interface HttpXCapClient
+{
+ /**
+ * Connects user to XCAP server.
+ *
+ * @param uri the server location.
+ * @param userAddress the user name.
+ * @param password the user password.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void connect(URI uri, Address userAddress, String password)
+ throws XCapException;
+
+ /**
+ * Dicsonnects user from the XCAP server.
+ */
+ public void dicsonnect();
+
+ /**
+ * Checks if user is connected to the XCAP server.
+ *
+ * @return true if user is connected.
+ */
+ public boolean isConnected();
+
+ /**
+ * Gets the resource from the server.
+ *
+ * @param resourceId resource identifier.
+ * @return the server response.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapHttpResponse get(XCapResourceId resourceId)
+ throws XCapException;
+
+ /**
+ * Puts the resource to the server.
+ *
+ * @param resource the resource to be saved on the server.
+ * @return the server response.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapHttpResponse put(XCapResource resource)
+ throws XCapException;
+
+ /**
+ * Deletes the resource from the server.
+ *
+ * @param resourceId resource identifier.
+ * @return the server response.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapHttpResponse delete(XCapResourceId resourceId)
+ throws XCapException;
+
+ /**
+ * Gets connected user name.
+ *
+ * @return user name.
+ */
+ public String getUserName();
+
+ /**
+ * Gets the XCAP server location.
+ *
+ * @return server location.
+ */
+ public URI getUri();
+
+ /**
+ * Gets operation timeout.
+ *
+ * @return operation timeout.
+ */
+ public int getTimeout();
+
+ /**
+ * Sets operation timeout.
+ *
+ * @param timeout operation timeout.
+ */
+ public void setTimeout(int timeout);
+
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/PresContentClient.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/PresContentClient.java
new file mode 100644
index 0000000..70a1501
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/PresContentClient.java
@@ -0,0 +1,88 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent.*;
+
+import java.net.*;
+
+/**
+ * XCAP pres-content client interface.
+ * <p/>
+ * Compliant with Presence Content XDM Specification v1.0
+ *
+ * @author Grigorii Balutsel
+ */
+public interface PresContentClient
+{
+ /**
+ * Pres-content content type
+ */
+ public static String CONTENT_TYPE = "application/vnd.oma.pres-content+xml";
+
+ /**
+ * Pres-content namespace
+ */
+ public static String NAMESPACE = "urn:oma:xml:prs:pres-content";
+
+ /**
+ * Pres-content uri format
+ */
+ public static String DOCUMENT_FORMAT = "oma_status-icon/users/%1s/%2s";
+
+ /**
+ * Puts the pres-content to the server.
+ *
+ * @param content the pres-content to be saved on the server.
+ * @param imageName the image name under which pres-content would be saved.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void putPresContent(ContentType content, String imageName)
+ throws XCapException;
+
+ /**
+ * Gets the pres-content from the server.
+ *
+ * @param imageName the image name under which pres-content is saved.
+ * @return the pres-content or null if there is no pres-content on the
+ * server.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public ContentType getPresContent(String imageName)
+ throws XCapException;
+
+ /**
+ * Deletes the pres-content from the server.
+ *
+ * @param imageName the image name under which pres-content is saved.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void deletePresContent(String imageName)
+ throws XCapException;
+
+ /**
+ * Gets the pres-content image uri.
+ *
+ * @param imageName the image name under which pres-content is saved.
+ * @return the pres-content image uri.
+ * @throws IllegalStateException if the user has not been connected.
+ */
+ public URI getPresContentImageUri(String imageName);
+
+ /**
+ * Gets image from the specified uri.
+ *
+ * @param imageUri the image uri.
+ * @return the image.
+ * @throws XCapException if there is some error during operation.
+ */
+ public byte[] getImage(URI imageUri)
+ throws XCapException;
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/PresRulesClient.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/PresRulesClient.java
new file mode 100644
index 0000000..e0e9e62
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/PresRulesClient.java
@@ -0,0 +1,64 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy.*;
+
+/**
+ * XCAP pres-rules client interface.
+ * <p/>
+ * Compliant with rfc4745, rfc5025
+ *
+ * @author Grigorii Balutsel
+ */
+public interface PresRulesClient
+{
+ /**
+ * Pres-rules uri format
+ */
+ public static String DOCUMENT_FORMAT = "pres-rules/users/%2s/presrules";
+
+ /**
+ * Pres-rules content type
+ */
+ public static String CONTENT_TYPE = "application/auth-policy+xml";
+
+ /**
+ * Pres-rules namespace
+ */
+ public static String NAMESPACE = "urn:ietf:params:xml:ns:pres-rules";
+
+ /**
+ * Puts the pres-rules to the server.
+ *
+ * @param presRules the pres-rules to be saved on the server.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void putPresRules(RulesetType presRules)
+ throws XCapException;
+
+ /**
+ * Gets the pres-rules from the server.
+ *
+ * @return the pres-rules.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public RulesetType getPresRules()
+ throws XCapException;
+
+ /**
+ * Deletes the pres-rules from the server.
+ *
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void deletePresRules()
+ throws XCapException;
+
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/ResourceListsClient.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/ResourceListsClient.java
new file mode 100644
index 0000000..b37e9c8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/ResourceListsClient.java
@@ -0,0 +1,81 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists.*;
+
+/**
+ * XCAP resource-lists client interface.
+ * <p/>
+ * Compliant with rfc4825, rfc4826
+ *
+ * @author Grigorii Balutsel
+ */
+public interface ResourceListsClient
+{
+ /**
+ * Resource-lists uri format.
+ */
+ public static String DOCUMENT_FORMAT = "resource-lists/users/%2s/index";
+
+ /**
+ * Resource-lists content type.
+ */
+ public static String RESOURCE_LISTS_CONTENT_TYPE =
+ "application/resource-lists+xml";
+
+ /**
+ * Resource-lists content type.
+ */
+ public static String ELEMENT_CONTENT_TYPE = "application/xcap-el+xml";
+
+ /**
+ * Resource-lists namespace.
+ */
+ public static String NAMESPACE = "urn:ietf:params:xml:ns:xcap-caps";
+
+ /**
+ * Puts the resource-lists to the server.
+ *
+ * @param resourceLists the resource-lists to be saved on the server.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void putResourceLists(ResourceListsType resourceLists)
+ throws XCapException;
+
+ /**
+ * Gets the resource-lists from the server.
+ *
+ * @return the resource-lists.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public ResourceListsType getResourceLists()
+ throws XCapException;
+
+ /**
+ * Deletes the resource-lists from the server.
+ *
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void deleteResourceLists()
+ throws XCapException;
+
+ /**
+ * Gets the resource-lists from the server.
+ *
+ * @param anchor reference to the list.
+ * @return the list.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public ListType getList(String anchor)
+ throws XCapException;
+
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapCapsClient.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapCapsClient.java
new file mode 100644
index 0000000..00807aa
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapCapsClient.java
@@ -0,0 +1,39 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps.*;
+
+/**
+ * XCAP xcap-caps client interface.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public interface XCapCapsClient
+{
+ /**
+ * Xcap-caps uri format
+ */
+ public static String DOCUMENT_FORMAT = "xcap-caps/global/index";
+
+ /**
+ * Xcap-caps content type
+ */
+ public static String CONTENT_TYPE = "application/xcap-caps+xml";
+
+ /**
+ * Gets the xcap-caps from the server.
+ *
+ * @return the xcap-caps.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapCapsType getXCapCaps()
+ throws XCapException;
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClient.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClient.java
new file mode 100644
index 0000000..d29a0ad
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClient.java
@@ -0,0 +1,41 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+/**
+ * XCAP client interface.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public interface XCapClient extends HttpXCapClient,
+ XCapCapsClient, ResourceListsClient,
+ PresRulesClient, PresContentClient
+{
+ /**
+ * Gets information about XCAP resource-lists support information.
+ *
+ * @return true if resource-lists is supported.
+ */
+ public boolean isResourceListsSupported();
+
+ /**
+ * Gets information about XCAP pres-rules support information.
+ *
+ * @return true if pres-rules is supported.
+ */
+ public boolean isPresRulesSupported();
+
+ /**
+ * Gets information about XCAP pres-content support information.
+ *
+ * @return true if pres-content is supported.
+ */
+ public boolean isPresContentSupported();
+
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClientImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClientImpl.java
new file mode 100644
index 0000000..fc3b152
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapClientImpl.java
@@ -0,0 +1,751 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps.*;
+import net.java.sip.communicator.util.*;
+import org.apache.http.*;
+
+import javax.sip.address.*;
+import java.io.*;
+import java.net.URI;
+
+/**
+ * XCAP client implementation.
+ * <p/>
+ * Compliant with rfc4825, rfc4826, rfc5025 and Presence Content XDM
+ * Specification v1.0
+ *
+ * @author Grigorii Balutsel
+ */
+public class XCapClientImpl extends BaseHttpXCapClient implements XCapClient
+{
+ /**
+ * Current xcap-caps.
+ */
+ private XCapCapsType xCapCaps;
+
+ /**
+ * Indicates whether or not resource-lists is supported.
+ */
+ private boolean resourceListsSupported;
+
+ /**
+ * Indicates whether or not pres-rules is supported.
+ */
+ private boolean presRulesSupported;
+
+ /**
+ * Indicates whether or not pres-content is supported.
+ */
+ private boolean presContentSupported;
+
+ /**
+ * Connects user to XCap server. Loads xcap-caps server capabilities and
+ * anaylyze if resource-lists, pres-rules, pres-content is supported.
+ *
+ * @param uri the server location.
+ * @param userAddress the user name.
+ * @param password the user password.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void connect(URI uri, Address userAddress, String password)
+ throws XCapException
+ {
+ super.connect(uri, userAddress, password);
+ try
+ {
+ xCapCaps = loadXCapCaps();
+ }
+ catch (XCapException e)
+ {
+ dicsonnect();
+ throw e;
+ }
+ for (String namespace : xCapCaps.getNamespaces().getNamespace())
+ {
+ if (ResourceListsClient.NAMESPACE.equals(namespace))
+ {
+ resourceListsSupported = true;
+ }
+ if (PresRulesClient.NAMESPACE.equals(namespace))
+ {
+ //presRulesSupported = true;
+ }
+ if (PresContentClient.NAMESPACE.equals(namespace))
+ {
+ presContentSupported = true;
+ }
+ }
+ }
+
+ /**
+ * Disconnects user from the XCAP server.
+ */
+ public void dicsonnect()
+ {
+ super.dicsonnect();
+ xCapCaps = null;
+ resourceListsSupported = false;
+ }
+
+ /**
+ * Puts the resource-lists to the server.
+ *
+ * @param resourceLists the resource-lists to be saved on the server.
+ * @throws IllegalStateException if the user has not been connected, or
+ * resource-lists is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void putResourceLists(ResourceListsType resourceLists)
+ throws XCapException
+ {
+ assertConnected();
+ assertResourceListsSupported();
+ String resourceListsDocument = getResourceListsDocument();
+ XCapResourceId resourceId = new XCapResourceId(resourceListsDocument);
+ try
+ {
+ if (resourceLists.getList().size() == 0)
+ {
+ deleteResourceLists();
+ return;
+ }
+ String xml = ResourceListsParser.toXml(resourceLists);
+ XCapResource resource = new XCapResource(resourceId, xml,
+ XCapCapsClient.CONTENT_TYPE);
+ // Put resource-lists to the server
+ putResource(resource);
+ }
+ catch (ParsingException e)
+ {
+ throw new XCapException("ResourceLists cannot be parsed", e);
+ }
+ }
+
+ /**
+ * Gets the resource-lists from the server.
+ *
+ * @return the resource-lists.
+ * @throws IllegalStateException if the user has not been connected, or
+ * resource-lists is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public ResourceListsType getResourceLists()
+ throws XCapException
+ {
+ assertConnected();
+ assertResourceListsSupported();
+ String resourceListsDocument = getResourceListsDocument();
+ XCapResourceId resourceId = new XCapResourceId(resourceListsDocument);
+ try
+ {
+ String xml = getResource(resourceId,
+ ResourceListsClient.RESOURCE_LISTS_CONTENT_TYPE);
+ if (xml == null)
+ {
+ return new ResourceListsType();
+ }
+ return ResourceListsParser.fromXml(xml);
+ }
+ catch (ParsingException e)
+ {
+ throw new XCapException("ResourceLists cannot be parsed", e);
+ }
+ }
+
+ /**
+ * Deletes the resource-lists from the server.
+ *
+ * @throws IllegalStateException if the user has not been connected, or
+ * resource-lists is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void deleteResourceLists()
+ throws XCapException
+ {
+ assertConnected();
+ assertResourceListsSupported();
+ String resourceListsDocument = getResourceListsDocument();
+ XCapResourceId resourceId = new XCapResourceId(resourceListsDocument);
+ deleteResource(resourceId);
+ }
+
+ /**
+ * Gets the resource-lists from the server.
+ *
+ * @param anchor reference to the list.
+ * @return the list.
+ * @throws IllegalStateException if the user has not been connected, or
+ * resource-lists is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public ListType getList(String anchor)
+ throws XCapException
+ {
+ assertConnected();
+ assertResourceListsSupported();
+ XCapResourceId resourceId = XCapResourceId.create(anchor);
+ return null;
+ // TODO: uncomment after implementation
+// try
+// {
+// // Load list from the server
+// String xml = getResource(resourceId,
+// ResourceListsClient.ELEMENT_CONTENT_TYPE);
+// if (xml == null)
+// {
+// throw new XCapException(resourceId.toString() + "wasn't find");
+// }
+// return (ListType) XmlUtils.createDocument(ListType.class, xml);
+// }
+// catch (JAXBException e)
+// {
+// throw new XCapException("ResourceLists cannot be parsed", e);
+// }
+ }
+
+ /**
+ * Gets the xcap-caps from the server.
+ *
+ * @return the xcap-caps.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ public XCapCapsType getXCapCaps()
+ throws XCapException
+ {
+ assertConnected();
+ return xCapCaps;
+ }
+
+ /**
+ * Loads the xcap-caps from the server.
+ *
+ * @return the xcap-caps.
+ * @throws IllegalStateException if the user has not been connected.
+ * @throws XCapException if there is some error during operation.
+ */
+ private XCapCapsType loadXCapCaps()
+ throws XCapException
+ {
+ String xCapCapsDocument = getXCapCapsDocument();
+ XCapResourceId resourceId = new XCapResourceId(xCapCapsDocument);
+ try
+ {
+ // Load xcap-caps from the server
+ String xml = getResource(resourceId, XCapCapsClient.CONTENT_TYPE);
+ if (xml == null)
+ {
+ return new XCapCapsType();
+ }
+ return XCapCapsParser.fromXml(xml);
+ }
+ catch (ParsingException e)
+ {
+ throw new XCapException("XCapCapsType cannot be parsed", e);
+ }
+ }
+
+ /**
+ * Gets the pres-rules from the server.
+ *
+ * @return the pres-rules.
+ * @throws IllegalStateException if the user has not been connected, or
+ * pres-rules is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public RulesetType getPresRules()
+ throws XCapException
+ {
+ assertConnected();
+ assertPresRulesSupported();
+ String presRulesDocument = getPresRulesDocument();
+ XCapResourceId resourceId = new XCapResourceId(presRulesDocument);
+ try
+ {
+ // Load pres-rules from the server
+ String xml = getResource(resourceId, PresRulesClient.CONTENT_TYPE);
+ if (xml == null)
+ {
+ return new RulesetType();
+ }
+ // TODO: uncomment after implementation
+ //return (RulesetType) XmlUtils.createDocument(RulesetType.class, xml);
+ return null;
+ }
+ catch (Exception e)
+ {
+ throw new XCapException("PresRules cannot be parsed", e);
+ }
+ }
+
+ /**
+ * Puts the pres-rules to the server.
+ *
+ * @param presRules the pres-rules to be saved on the server.
+ * @throws IllegalStateException if the user has not been connected, or
+ * pres-rules is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void putPresRules(RulesetType presRules)
+ throws XCapException
+ {
+ assertConnected();
+ assertPresRulesSupported();
+ String resourceListsDocument = getPresRulesDocument();
+ XCapResourceId resourceId = new XCapResourceId(resourceListsDocument);
+ // TODO: uncomment after implementation
+// try
+// {
+// String xml = XmlUtils.toXml(RulesetType.class, presRules);
+// XCapResource resource = new XCapResource(resourceId, xml,
+// PresRulesClient.CONTENT_TYPE);
+// // Put pres-rules to the server
+// putResource(resource);
+// }
+// catch (JAXBException e)
+// {
+// throw new XCapException("PresRules cannot be parsed", e);
+// }
+ }
+
+ /**
+ * Deletes the pres-rules from the server.
+ *
+ * @throws IllegalStateException if the user has not been connected, or
+ * pres-rules is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void deletePresRules()
+ throws XCapException
+ {
+ assertConnected();
+ assertResourceListsSupported();
+ String presRulesDocument = getPresRulesDocument();
+ XCapResourceId resourceId = new XCapResourceId(presRulesDocument);
+ deleteResource(resourceId);
+ }
+
+ /**
+ * Puts the pres-content to the server.
+ *
+ * @param content the pres-content to be saved on the server.
+ * @param imageName the image name under which pres-content would be saved.
+ * @throws IllegalStateException if the user has not been connected, or
+ * pres-content is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void putPresContent(ContentType content, String imageName)
+ throws XCapException
+ {
+ assertConnected();
+ assertPresContentSupported();
+ String presContentDocument = getPresContentDocument(imageName);
+ XCapResourceId resourceId = new XCapResourceId(presContentDocument);
+ try
+ {
+ String xml = PresContentParser.toXml(content);
+ XCapResource resource = new XCapResource(resourceId, xml,
+ PresContentClient.CONTENT_TYPE);
+ // Put pres-content to the server
+ putResource(resource);
+ }
+ catch (ParsingException e)
+ {
+ throw new XCapException("ContentType cannot be parsed", e);
+ }
+ }
+
+ /**
+ * Gets the pres-content from the server.
+ *
+ * @param imageName the image name under which pres-content is saved.
+ * @return the pres-content or null if there is no pres-content on
+ * the server.
+ * @throws IllegalStateException if the user has not been connected, or
+ * pres-content is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public ContentType getPresContent(String imageName)
+ throws XCapException
+ {
+ assertConnected();
+ assertPresContentSupported();
+ String presContentDocument = getPresContentDocument(imageName);
+ XCapResourceId resourceId = new XCapResourceId(presContentDocument);
+ try
+ {
+ // Load pres-content from the server
+ XCapHttpResponse response = this.get(resourceId);
+ int httpCode = response.getHttpCode();
+ String contentType = response.getContentType();
+ byte[] content = response.getContent();
+ // Analyze the responce
+ if (httpCode != HttpStatus.SC_OK)
+ {
+ if (httpCode == HttpStatus.SC_NOT_FOUND)
+ {
+ return null;
+ }
+ String errorMessage = String.format(
+ "Error %1s while getting %1s PresContent from XCAP server",
+ httpCode,
+ resourceId.toString());
+ throw new XCapException(errorMessage);
+ }
+ if (!contentType.equals(PresContentClient.CONTENT_TYPE))
+ {
+ String errorMessage = String.format(
+ "XCAP server returns invalid PresContent content type: %1s",
+ contentType);
+ throw new XCapException(errorMessage);
+ }
+ if (content == null || content.length == 0)
+ {
+ throw new XCapException(
+ "XCAP server returns invalid PresContent content");
+ }
+ try
+ {
+ return PresContentParser.fromXml(new String(content, "UTF-8"));
+ }
+ catch (ParsingException e)
+ {
+ // TODO: remove it after the sip2sip fixes
+ // The only server that supports it is sip2sip server.
+ // They do not follow for 100% percent the RFC
+ ContentType presContent = new ContentType();
+ DataType data = new DataType();
+ data.setValue(new String(Base64.encode(content)));
+ presContent.setData(data);
+ return presContent;
+ }
+ }
+ catch (IOException e)
+ {
+ String errorMessage = String.format(
+ "%1s resource cannot be read",
+ resourceId.toString());
+ throw new XCapException(errorMessage, e);
+ }
+ }
+
+ /**
+ * Deletes the pres-content from the server.
+ *
+ * @param imageName the image name under which pres-content is saved.
+ * @throws IllegalStateException if the user has not been connected, or
+ * pres-content is not supported.
+ * @throws XCapException if there is some error during operation.
+ */
+ public void deletePresContent(String imageName)
+ throws XCapException
+ {
+ assertConnected();
+ assertPresContentSupported();
+ String presContentDocument = getPresContentDocument(imageName);
+ XCapResourceId resourceId = new XCapResourceId(presContentDocument);
+ deleteResource(resourceId);
+ }
+
+ /**
+ * Gets the pres-content image uri.
+ *
+ * @param imageName the image name under which pres-content is saved.
+ * @return the pres-content image uri.
+ * @throws IllegalStateException if the user has not been connected.
+ */
+ public URI getPresContentImageUri(String imageName)
+ {
+ assertConnected();
+ String presContentDocument = getPresContentDocument(imageName);
+ XCapResourceId resourceId = new XCapResourceId(presContentDocument);
+ return getResourceURI(resourceId);
+ }
+
+ /**
+ * Gets image from the specified uri.
+ *
+ * @param imageUri the image uri.
+ * @return the image.
+ * @throws XCapException if there is some error during operation.
+ */
+ public byte[] getImage(URI imageUri)
+ throws XCapException
+ {
+ assertConnected();
+ XCapHttpResponse response = this.get(imageUri);
+ int httpCode = response.getHttpCode();
+ byte[] content = response.getContent();
+ // Analyze the responce
+ if (httpCode != HttpStatus.SC_OK)
+ {
+ String errorMessage = String.format(
+ "Error %1s while getting %2s image from the server",
+ httpCode,
+ imageUri);
+ throw new XCapException(errorMessage);
+ }
+ return content;
+ }
+
+ /**
+ * Utility method throwing an exception if the resource-lists
+ * is not supported.
+ *
+ * @throws IllegalStateException if the user is not connected.
+ */
+ protected void assertResourceListsSupported()
+ {
+ if (!resourceListsSupported)
+ {
+ throw new IllegalStateException(
+ "XCAP server doesn't support resource-lists");
+ }
+ }
+
+ /**
+ * Utility method throwing an exception if the pres-rules
+ * is not supported.
+ *
+ * @throws IllegalStateException if the user is not connected.
+ */
+ protected void assertPresRulesSupported()
+ {
+ if (!presRulesSupported)
+ {
+ throw new IllegalStateException(
+ "XCAP server doesn't support pres-rules");
+ }
+ }
+
+ /**
+ * Utility method throwing an exception if the pres-content
+ * is not supported.
+ *
+ * @throws IllegalStateException if the user is not connected.
+ */
+ protected void assertPresContentSupported()
+ {
+ if (!presContentSupported)
+ {
+ throw new IllegalStateException(
+ "XCAP server doesn't support pres-content");
+ }
+ }
+
+ /**
+ * Puts XCAP resources to the server. Analyzes HTTP code and tryes to get
+ * xcap-error if possible.
+ *
+ * @param resource the resource.
+ * @throws XCapException if there is some error during operation.
+ */
+ private void putResource(XCapResource resource)
+ throws XCapException
+ {
+ XCapHttpResponse response = this.put(resource);
+ int httpCode = response.getHttpCode();
+ if (httpCode != HttpStatus.SC_OK && httpCode != HttpStatus.SC_CREATED)
+ {
+ String errorMessage;
+ String xCapErrorMessage = getXCapErrorMessage(response);
+ if (xCapErrorMessage != null)
+ {
+ errorMessage = String.format(
+ "Error %1s while putting %2s to XCAP server. %3s",
+ httpCode,
+ resource.getId().toString(),
+ xCapErrorMessage);
+ }
+ else
+ {
+ errorMessage = String.format(
+ "Error %1s while putting %2s to XCAP server",
+ httpCode,
+ resource.getId().toString());
+ }
+ throw new XCapException(errorMessage);
+ }
+ }
+
+ /**
+ * Gets XCAP resources from the server. Analyzes HTTP code and tryes to get
+ * xcap-error if possible.
+ *
+ * @param resourceId the resource identifier.
+ * @param contentType the resource content-type.
+ * @return XCAP resource.
+ * @throws XCapException if there is some error during operation.
+ */
+ private String getResource(XCapResourceId resourceId, String contentType)
+ throws XCapException
+ {
+ try
+ {
+ // Load resource from the server
+ XCapHttpResponse response = this.get(resourceId);
+ int httpCode = response.getHttpCode();
+ byte[] content = response.getContent();
+ // Analyze the response
+ if (httpCode != HttpStatus.SC_OK)
+ {
+ if (httpCode == HttpStatus.SC_NOT_FOUND)
+ {
+ return null;
+ }
+ String errorMessage;
+ String xCapErrorMessage = getXCapErrorMessage(response);
+ if (xCapErrorMessage != null)
+ {
+ errorMessage = String.format(
+ "Error %1s while getting %2s from XCAP server. %3s",
+ httpCode,
+ resourceId.toString(),
+ xCapErrorMessage);
+ }
+ else
+ {
+ errorMessage = String.format(
+ "Error %1s while getting %2s from XCAP server",
+ httpCode,
+ resourceId.toString());
+ }
+ throw new XCapException(errorMessage);
+ }
+ if (!contentType.equals(response.getContentType()))
+ {
+ String errorMessage = String.format(
+ "XCAP server returns invalid content type: %1s",
+ contentType);
+ throw new XCapException(errorMessage);
+ }
+ if (content == null || content.length == 0)
+ {
+ return null;
+ }
+ return new String(content, "UTF-8");
+ }
+ catch (IOException e)
+ {
+ String errorMessage = String.format(
+ "%1s resource cannot be read",
+ resourceId.toString());
+ throw new XCapException(errorMessage, e);
+ }
+ }
+
+ /**
+ * Deletes XCAP resources from the server. Analyzes HTTP code and tryes to
+ * get xcap-error if possible.
+ *
+ * @param resourceId the resource identifier.
+ * @throws XCapException if there is some error during operation.
+ */
+ private void deleteResource(XCapResourceId resourceId)
+ throws XCapException
+ {
+ XCapHttpResponse response = this.delete(resourceId);
+ int httpCode = response.getHttpCode();
+ if (httpCode != HttpStatus.SC_OK && httpCode != HttpStatus.SC_NOT_FOUND)
+ {
+ String errorMessage;
+ String xCapErrorMessage = getXCapErrorMessage(response);
+ if (xCapErrorMessage != null)
+ {
+ errorMessage = String.format(
+ "Error %1s while deleting %2s resource from XCAP server. %3s",
+ httpCode,
+ resourceId.toString(),
+ xCapErrorMessage);
+ }
+ else
+ {
+ errorMessage = String.format(
+ "Error %1s while deleting %2s resource from XCAP server",
+ httpCode,
+ resourceId.toString());
+ }
+ throw new XCapException(errorMessage);
+ }
+ }
+
+ /**
+ * Returns resource lists uri according to rfc4825.
+ *
+ * @return resource lists uri.
+ */
+ private String getResourceListsDocument()
+ {
+ return String.format(ResourceListsClient.DOCUMENT_FORMAT,
+ userAddress.getURI().toString());
+ }
+
+ /**
+ * Returns xcap-caps uri according to rfc4825.
+ *
+ * @return xcap-caps uri.
+ */
+ private String getXCapCapsDocument()
+ {
+ return XCapCapsClient.DOCUMENT_FORMAT;
+ }
+
+ /**
+ * Gets resource-lists uri according to rfc5025.
+ *
+ * @return resource-lists uri.
+ */
+ private String getPresRulesDocument()
+ {
+ return String.format(PresRulesClient.DOCUMENT_FORMAT,
+ userAddress.getURI().toString());
+ }
+
+ /**
+ * Gets pres-content uri according to rfc.
+ *
+ * @param imageName the pres-content image name.
+ * @return pres-content uri.
+ */
+ private String getPresContentDocument(String imageName)
+ {
+ return String.format(PresContentClient.DOCUMENT_FORMAT,
+ userAddress.getURI().toString(), imageName);
+ }
+
+ /**
+ * Indicates whether or not pres-rules is supported.
+ */
+ public boolean isResourceListsSupported()
+ {
+ assertConnected();
+ return resourceListsSupported;
+ }
+
+ /**
+ * Indicates whether or not pres-rules is supported.
+ */
+ public boolean isPresRulesSupported()
+ {
+ assertConnected();
+ return presRulesSupported;
+ }
+
+ /**
+ * Indicates whether or not pres-rules is supported.
+ */
+ public boolean isPresContentSupported()
+ {
+ return presContentSupported;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapException.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapException.java
new file mode 100644
index 0000000..77677d7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapException.java
@@ -0,0 +1,63 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+/**
+ * Exceptions of this class get thrown whenever an error occurs while operating
+ * with XCAP server.
+ *
+ * @author Grigorii Balutsel
+ */
+public class XCapException extends Exception
+{
+ /**
+ * Creates a new <code>XCapException</code> instance
+ * which does not give a human-readable explanation why the operation is
+ * not supported.
+ */
+ public XCapException()
+ {
+ }
+
+ /**
+ * Creates a new <code>XCapException</code> instance whith human-readable
+ * explanation.
+ *
+ * @param message the detailed message explaining any particular details as
+ * to why is not the specified operation supported or null if
+ * no particular details exist.
+ */
+ public XCapException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Creates a new <code>XCapException</code> instance with human-readable
+ * explanation and the original cause of the problem.
+ *
+ * @param message the detailed message explaining any particular details as
+ * to why is not the specified operation supported or null if
+ * no particular details exist.
+ * @param cause the original cause of the problem.
+ */
+ public XCapException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new <code>XCapException</code> instance with the original cause
+ * of the problem.
+ *
+ * @param cause the original cause of the problem.
+ */
+ public XCapException(Throwable cause)
+ {
+ super(cause);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapHttpResponse.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapHttpResponse.java
new file mode 100644
index 0000000..1d8314d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapHttpResponse.java
@@ -0,0 +1,115 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+/**
+ * XCAP HTTP response.
+ *
+ * @author Grigorii Balutsel
+ */
+public class XCapHttpResponse
+{
+ /**
+ * HTTP code.
+ */
+ private int httpCode;
+
+ /**
+ * HTTP Content-Type
+ */
+ private String contentType;
+
+ /**
+ * HTTP response content.
+ */
+ private byte[] content;
+
+ /**
+ * HTTP ETag.
+ */
+ private String eTag;
+
+ /**
+ * Gets HTTP code.
+ *
+ * @return the HTTP code.
+ */
+ public int getHttpCode()
+ {
+ return httpCode;
+ }
+
+ /**
+ * Sets HTTP code.
+ *
+ * @param httpCode the HTTP code.
+ */
+ void setHttpCode(int httpCode)
+ {
+ this.httpCode = httpCode;
+ }
+
+ /**
+ * Gets HTTP Content-Type.
+ *
+ * @return the HTTP Content-Type.
+ */
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ /**
+ * Sets HTTP Content-Type.
+ *
+ * @param contentType the HTTP Content-Type.
+ */
+ void setContentType(String contentType)
+ {
+ this.contentType = contentType;
+ }
+
+ /**
+ * Gets HTTP response content.
+ *
+ * @return the HTTP response content.
+ */
+ public byte[] getContent()
+ {
+ return content;
+ }
+
+ /**
+ * Sets HTTP response content.
+ *
+ * @param content the HTTP response content.
+ */
+ void setContent(byte[] content)
+ {
+ this.content = content;
+ }
+
+ /**
+ * Gets HTTP ETag.
+ *
+ * @return the HTTP ETag.
+ */
+ public String getETag()
+ {
+ return eTag;
+ }
+
+ /**
+ * Sets HTTP ETag.
+ *
+ * @param eTag the HTTP ETag.
+ */
+ void setETag(String eTag)
+ {
+ this.eTag = eTag;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResource.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResource.java
new file mode 100644
index 0000000..877f405
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResource.java
@@ -0,0 +1,77 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+/**
+ * XCAP resource.
+ * </p>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class XCapResource
+{
+ /**
+ * XCAP resource identifier.
+ */
+ private XCapResourceId id;
+
+ /**
+ * XCAP resource content in UTF-8 enconding.
+ */
+ private String content;
+
+ /**
+ * XCAP resource content type.
+ */
+ private String contentType;
+
+ /**
+ * Creates XCAP resource with XCAP resource identifier, XCAP resource
+ * content and content-type.
+ *
+ * @param id the XCAP resource identifier.
+ * @param content the XCAP resource content.
+ * @param contentType the XCAP resource content type.
+ */
+ public XCapResource(XCapResourceId id, String content, String contentType)
+ {
+ this.id = id;
+ this.content = content;
+ this.contentType = contentType;
+ }
+
+ /**
+ * Gets XCAP resource identifier.
+ *
+ * @return the XCAP resource identifier.
+ */
+ public XCapResourceId getId()
+ {
+ return id;
+ }
+
+ /**
+ * Gets XCAP resource content.
+ *
+ * @return the XCAP resource content.
+ */
+ public String getContent()
+ {
+ return content;
+ }
+
+ /**
+ * Gets XCAP resource content type.
+ *
+ * @return the XCAP resource content type.
+ */
+ public String getContentType()
+ {
+ return contentType;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResourceId.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResourceId.java
new file mode 100644
index 0000000..de9fa31
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/XCapResourceId.java
@@ -0,0 +1,118 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap;
+
+/**
+ * XCAP resource identifier.
+ *
+ * @author Grigorii Balutsel
+ */
+public class XCapResourceId
+{
+ /**
+ * Delimeter between document and node selectors.
+ */
+ private static String DELIMETER = "/~~";
+
+ /**
+ * Document selector.
+ */
+ private String document;
+
+ /**
+ * Node selector.
+ */
+ private String node;
+
+ /**
+ * Creates XCAP resource identifier with document selector.
+ *
+ * @param document the document selector.
+ */
+ public XCapResourceId(String document)
+ {
+ this(document, null);
+ }
+
+ /**
+ * Creates XCAP resource identifier with document and node selector.
+ *
+ * @param document the document selector.
+ * @param node the node selector.
+ */
+ public XCapResourceId(String document, String node)
+ {
+ if (document == null || document.length() == 0)
+ {
+ throw new IllegalArgumentException(
+ "XCAP resource document cannot be null or empty");
+ }
+ this.document = document;
+ this.node = node;
+ }
+
+ /**
+ * Gets document selector.
+ *
+ * @return the document selector.
+ */
+ public String getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * Gets node selector.
+ *
+ * @return the node selector.
+ */
+ public String getNode()
+ {
+ return node;
+ }
+
+ /**
+ * Gets XCAP resource identifier object as single string.
+ *
+ * @return the XCAP resource identifier object as single string.
+ */
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder(document);
+ if (node != null && node.length() != 0)
+ {
+ builder.append(DELIMETER).append(node);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Creates XCAP resource identifier object from single string.
+ *
+ * @param resourceId the XCAP resource identifier as single string.
+ * @return the XCAP resource identifier.
+ * @throws IllegalArgumentException if resourceId is null or emty or has
+ * invalid format.
+ */
+ public static XCapResourceId create(String resourceId)
+ {
+ if (resourceId == null || resourceId.trim().length() == 0)
+ {
+ throw new IllegalArgumentException(
+ "Resource identifier cannot be null or empty");
+ }
+ int index = resourceId.indexOf(DELIMETER);
+ if (index == -1)
+ {
+ throw new IllegalArgumentException(
+ "Resource identifier has invalid format");
+ }
+ String document = resourceId.substring(0, index);
+ String node = resourceId.substring(index + DELIMETER.length());
+ return new XCapResourceId(document, node);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/ParsingException.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/ParsingException.java
new file mode 100644
index 0000000..124fe7a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/ParsingException.java
@@ -0,0 +1,63 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model;
+
+/**
+ * Exceptions of this class get thrown whenever an error occurs while operating
+ * with XCAP server.
+ *
+ * @author Grigorii Balutsel
+ */
+public class ParsingException extends Exception
+{
+ /**
+ * Creates a new <code>XCapException</code> instance
+ * which does not give a human-readable explanation why the operation is
+ * not supported.
+ */
+ public ParsingException()
+ {
+ }
+
+ /**
+ * Creates a new <code>XCapException</code> instance whith human-readable
+ * explanation.
+ *
+ * @param message the detailed message explaining any particular details as
+ * to why is not the specified operation supported or null if
+ * no particular details exist.
+ */
+ public ParsingException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Creates a new <code>XCapException</code> instance with human-readable
+ * explanation and the original cause of the problem.
+ *
+ * @param message the detailed message explaining any particular details as
+ * to why is not the specified operation supported or null if
+ * no particular details exist.
+ * @param cause the original cause of the problem.
+ */
+ public ParsingException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new <code>XCapException</code> instance with the original cause
+ * of the problem.
+ *
+ * @param cause the original cause of the problem.
+ */
+ public ParsingException(Throwable cause)
+ {
+ super(cause);
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/StringUtils.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/StringUtils.java
new file mode 100644
index 0000000..a7298e5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/StringUtils.java
@@ -0,0 +1,95 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model;
+
+import java.io.*;
+
+/**
+ * Utility class that helps to work with <tt>String</tt> class.
+ *
+ * @author Grigorii Balutsel
+ */
+public final class StringUtils
+{
+ /**
+ * This class cannot be instanced.
+ */
+ private StringUtils()
+ {
+ }
+
+ /**
+ * Indicates whether string is null or empty.
+ *
+ * @param s the string to analyze.
+ * @return true if string is null or empty.
+ */
+ public static boolean isNullOrEmpty(String s)
+ {
+ return isNullOrEmpty(s, true);
+ }
+
+ /**
+ * Indicates whether string is null or empty.
+ *
+ * @param s the string to analyze.
+ * @param trim indicates whether to trim the string.
+ * @return true if string is null or empty.
+ */
+ public static boolean isNullOrEmpty(String s, boolean trim)
+ {
+ if (s == null)
+ {
+ return true;
+ }
+ if (trim)
+ {
+ s = s.trim();
+ }
+ return s.length() == 0;
+ }
+
+ /**
+ * Indicates whether strings are equal.
+ *
+ * @param s1 the string to analyze.
+ * @param s2 the string to analyze.
+ * @return true if string are equal.
+ */
+ public static boolean isEquals(String s1, String s2)
+ {
+ return (s1 == null && s2 == null) || (s1 != null && s1.equals(s2));
+ }
+
+ /**
+ * Creates <tt>InputStream</tt> from the string in UTF8 encoding.
+ *
+ * @param string the string to convert.
+ * @return the <tt>InputStream</tt>.
+ * @throws UnsupportedEncodingException if UTF8 is unsupported.
+ */
+ public static InputStream fromString(String string)
+ throws UnsupportedEncodingException
+ {
+ return fromString(string, "UTF-8");
+ }
+
+ /**
+ * Creates <tt>InputStream</tt> from the string in the specified encoding.
+ *
+ * @param string the string to convert.
+ * @param encoding the encoding
+ * @return the <tt>InputStream</tt>.
+ * @throws UnsupportedEncodingException if the encoding is unsupported.
+ */
+ public static InputStream fromString(String string, String encoding)
+ throws UnsupportedEncodingException
+ {
+ byte[] bytes = string.getBytes(encoding);
+ return new ByteArrayInputStream(bytes);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/XmlUtils.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/XmlUtils.java
new file mode 100644
index 0000000..2a1dc80
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/XmlUtils.java
@@ -0,0 +1,299 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model;
+
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.StringUtils.*;
+import org.w3c.dom.*;
+
+import javax.xml.*;
+import javax.xml.namespace.QName;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import static javax.xml.XMLConstants.*;
+import javax.xml.parsers.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Utility class that helps to convert classes into xml and from xml to the
+ * classes.
+ *
+ * @author Grigorii Balutsel
+ */
+public final class XmlUtils
+{
+ /**
+ * Indicates whether namespace is one of the standart xml namespace.
+ *
+ * @param namespace the namespace to analyze.
+ * @return true is namespace is one of the standart xml namespace otherwise
+ * false.
+ */
+ public static boolean isStandartXmlNamespace(String namespace)
+ {
+ namespace = normalizeNamespace(namespace);
+ return normalizeNamespace(XML_NS_URI).equals(namespace)
+ || normalizeNamespace(XMLNS_ATTRIBUTE_NS_URI).equals(namespace)
+ || normalizeNamespace(W3C_XML_SCHEMA_NS_URI).equals(namespace)
+ || normalizeNamespace(W3C_XML_SCHEMA_INSTANCE_NS_URI)
+ .equals(namespace);
+ }
+
+ /**
+ * Gets the node namespace.
+ *
+ * @param node the <tt>Element</tt> or <tt>Attr</tt> node to analyze.
+ * @return the node namespace or null.
+ */
+ public static String getNamespaceUri(Node node)
+ {
+ String prefix = node.getPrefix();
+ String namespaceUri = node.getNamespaceURI();
+ if (!isNullOrEmpty(namespaceUri))
+ {
+ return normalizeNamespace(namespaceUri);
+ }
+ if (XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
+ {
+ return normalizeNamespace(XMLNS_ATTRIBUTE_NS_URI);
+ }
+ Element rootElement = node.getOwnerDocument().getDocumentElement();
+ Node parentNode = null;
+ while (parentNode != rootElement)
+ {
+ if (parentNode == null)
+ {
+ if (node.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ parentNode = ((Attr) node).getOwnerElement();
+ }
+ else if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ parentNode = node.getParentNode();
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ parentNode = parentNode.getParentNode();
+ }
+ String parentPrefix = parentNode.getPrefix();
+ String parentNamespaceUri = parentNode.getNamespaceURI();
+ if (isNullOrEmpty(prefix))
+ {
+ Node xmlnsAttribute =
+ parentNode.getAttributes().getNamedItem("xmlns");
+ if (xmlnsAttribute != null)
+ {
+ return ((Attr) xmlnsAttribute).getValue();
+ }
+ }
+ else if (isEquals(prefix, parentPrefix))
+ {
+ if (!isNullOrEmpty(parentNamespaceUri))
+ {
+ return normalizeNamespace(parentNamespaceUri);
+ }
+ }
+ }
+ if ("xml".equals(prefix))
+ {
+ return normalizeNamespace(XML_NS_URI);
+ }
+ return null;
+ }
+
+ /**
+ * Normalizes the namespace.
+ *
+ * @param namespace the namespace to normalize.
+ * @return normalized namespace.
+ */
+ private static String normalizeNamespace(String namespace)
+ {
+ if (namespace.endsWith("/"))
+ {
+ return namespace.substring(0, namespace.length() - 1);
+ }
+ return namespace;
+ }
+
+ /**
+ * Creates copy of the node in the scope of the document. Attributes,
+ * Elements, and Tex will be include.
+ *
+ * @param document the xml document.
+ * @param node the node to create the copy.
+ * @return the copy of the node in the scope of the document.
+ * @throws Exception if there is some error during processing.
+ */
+ public static Node importNode(Document document, Node node)
+ throws Exception
+ {
+ if (node.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ String namespace = getNamespaceUri(node);
+ if (namespace == null)
+ {
+ throw new Exception("Namespace cannot be null");
+ }
+ Attr attribute =
+ document.createAttributeNS(namespace, node.getNodeName());
+ attribute.setValue(((Attr) node).getValue());
+ return attribute;
+ }
+ else if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String namespace = getNamespaceUri(node);
+ if (namespace == null)
+ {
+ throw new Exception("Namespace cannot be null");
+ }
+
+ Element element =
+ document.createElementNS(namespace, node.getNodeName());
+
+ // Process attributes
+ NamedNodeMap attributes = node.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ if ("xmlns".equals(attribute.getPrefix()))
+ {
+ continue;
+ }
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("entry element is invalid");
+ }
+ element.getAttributes()
+ .setNamedItemNS(importNode(document, attribute));
+ }
+ // Process elements
+ NodeList childNodes = node.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node childNode = childNodes.item(i);
+ if (childNode.getNodeType() == Node.ELEMENT_NODE)
+ {
+ element.appendChild(importNode(document, childNode));
+ }
+ else if (childNode.getNodeType() == Node.TEXT_NODE)
+ {
+ element.appendChild(document.createTextNode(
+ childNode.getTextContent()));
+ }
+ }
+ return element;
+ }
+ else
+ {
+ throw new Exception("Node cannot be processed " + node.toString());
+ }
+ }
+
+ /**
+ * Creates W3C Document.
+ *
+ * @return the W3C Document.
+ * @throws Exception is there is some error during operation.
+ */
+ public static Document createDocument()
+ throws Exception
+ {
+ return createDocument(null);
+ }
+
+ /**
+ * Creates W3C Document from the xml.
+ *
+ * @param xml the xml that needs to be converted.
+ * @return the W3C Document.
+ * @throws Exception is there is some error during operation.
+ */
+ public static Document createDocument(String xml)
+ throws Exception
+ {
+ DocumentBuilderFactory builderFactory =
+ DocumentBuilderFactory.newInstance();
+ builderFactory.setNamespaceAware(true);
+ DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
+ if (!isNullOrEmpty(xml))
+ {
+ InputStream input = fromString(xml);
+ return documentBuilder.parse(input);
+ }
+ else
+ {
+ return documentBuilder.newDocument();
+ }
+ }
+
+ /**
+ * Creates XML from W3C Document from the xml.
+ *
+ * @param document the xml that needs to be converted.
+ * @return the XML.
+ * @throws Exception is there is some error during operation.
+ */
+ public static String createXml(Document document)
+ throws Exception
+ {
+ TransformerFactory transformerFactory =
+ TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ StringWriter stringWriter = new StringWriter();
+ StreamResult result = new StreamResult(stringWriter);
+ DOMSource source = new DOMSource(document);
+ transformer.transform(source, result);
+ return stringWriter.toString();
+ }
+
+ /**
+ * Processes any attributes and add them into the element.
+ *
+ * @param element the element where to add the attributes.
+ * @param anyAttributes the any attributes to process.
+ */
+ public static void processAnyAttributes(
+ Element element, Map<QName, String> anyAttributes)
+ {
+ for (Map.Entry<QName, String> attribute : anyAttributes.entrySet())
+ {
+ String localName = attribute.getKey().getLocalPart();
+ String prefix = attribute.getKey().getPrefix();
+ String namespace = attribute.getKey().getNamespaceURI();
+ element.setAttributeNS(namespace, prefix + ":" + localName,
+ attribute.getValue());
+ }
+ }
+
+ /**
+ * Processes any element and add them into the element.
+ *
+ * @param element the element where to add the elements.
+ * @param any the any elements to process.
+ * @throws Exception if there is some error during processing.
+ */
+ public static void processAny(Element element, List<Element> any)
+ throws Exception
+ {
+ for (Element anyElement : any)
+ {
+ Element importedElement =
+ (Element) importNode(element.getOwnerDocument(),
+ anyElement);
+ element.appendChild(importedElement);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ActionsType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ActionsType.java
new file mode 100644
index 0000000..8d73c0e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ActionsType.java
@@ -0,0 +1,86 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules.*;
+
+import java.util.*;
+
+/**
+ * <p>Java class for extensibleType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="extensibleType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;any/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "actionsType", propOrder = {
+// "subHandling",
+// "any"
+// })
+public class ActionsType
+{
+
+// @XmlElement(name = "sub-handling",
+// namespace = "urn:ietf:params:xml:ns:pres-rules", required = false)
+ protected SubHandlingType subHandling;
+
+// @XmlAnyElement(lax = true)
+ protected List<Object> any;
+
+ /**
+ * Gets the value of the any property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the any property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getAny().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link org.w3c.dom.Element }
+ * {@link Object }
+ */
+ public List<Object> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Object>();
+ }
+ return this.any;
+ }
+
+ public SubHandlingType getSubHandling()
+ {
+ return subHandling;
+ }
+
+ public void setSubHandling(SubHandlingType subHandling)
+ {
+ this.subHandling = subHandling;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ConditionsType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ConditionsType.java
new file mode 100644
index 0000000..fcd8980
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ConditionsType.java
@@ -0,0 +1,63 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+import java.util.*;
+
+/**
+ * <p>Java class for conditionsType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="conditionsType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;choice maxOccurs="unbounded">
+ * &lt;element name="identity" type="{urn:ietf:params:xml:ns:common-policy}identityType" minOccurs="0"/>
+ * &lt;element name="sphere" type="{urn:ietf:params:xml:ns:common-policy}sphereType" minOccurs="0"/>
+ * &lt;element name="validity" type="{urn:ietf:params:xml:ns:common-policy}validityType" minOccurs="0"/>
+ * &lt;any/>
+ * &lt;/choice>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "conditionsType", propOrder = {
+// "identityOrSphereOrValidity"
+// })
+public class ConditionsType
+{
+
+// @XmlElementRefs({
+// @XmlElementRef(name = "identity",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = JAXBElement.class),
+// @XmlElementRef(name = "sphere",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = JAXBElement.class),
+// @XmlElementRef(name = "validity",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = JAXBElement.class)
+// })
+// @XmlAnyElement(lax = true)
+ protected List<Object> identityOrSphereOrValidity;
+
+
+ public List<Object> getIdentityOrSphereOrValidity()
+ {
+ if (identityOrSphereOrValidity == null)
+ {
+ identityOrSphereOrValidity = new ArrayList<Object>();
+ }
+ return this.identityOrSphereOrValidity;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ExceptType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ExceptType.java
new file mode 100644
index 0000000..67f0a49
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ExceptType.java
@@ -0,0 +1,83 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+//import javax.xml.bind.annotation.*;
+
+/**
+ * <p>Java class for exceptType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="exceptType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="domain" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}anyURI" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "exceptType")
+public class ExceptType
+{
+
+// @XmlAttribute
+ protected String domain;
+
+// @XmlAttribute
+ protected String id;
+
+ /**
+ * Gets the value of the domain property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getDomain()
+ {
+ return domain;
+ }
+
+ /**
+ * Sets the value of the domain property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setDomain(String value)
+ {
+ this.domain = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setId(String value)
+ {
+ this.id = value;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/IdentityType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/IdentityType.java
new file mode 100644
index 0000000..0ed154a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/IdentityType.java
@@ -0,0 +1,109 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+import org.w3c.dom.Element;
+
+//import javax.xml.bind.*;
+//import javax.xml.bind.annotation.*;
+import java.util.*;
+
+/**
+ * <p>Java class for identityType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="identityType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;choice maxOccurs="unbounded">
+ * &lt;element name="one" type="{urn:ietf:params:xml:ns:common-policy}oneType"/>
+ * &lt;element name="many" type="{urn:ietf:params:xml:ns:common-policy}manyType"/>
+ * &lt;any/>
+ * &lt;/choice>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "identityType", propOrder = {
+// "oneList",
+// "manyList",
+// "any"
+// })
+//@XmlRootElement(name = "identity",
+// namespace = "urn:ietf:params:xml:ns:common-policy")
+public class IdentityType
+{
+// @XmlElementRef(name = "one",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = OneType.class)
+ protected List<OneType> oneList;
+
+// @XmlElementRef(name = "many",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = ManyType.class)
+ protected List<ManyType> manyList;
+
+// @XmlAnyElement(lax = true)
+ protected List<Object> any;
+
+// /**
+// * Gets the value of the oneOrManyOrAny property.
+// * <p/>
+// * <p/>
+// * This accessor method returns a reference to the live list,
+// * not a snapshot. Therefore any modification you make to the
+// * returned list will be present inside the JAXB object.
+// * This is why there is not a <CODE>set</CODE> method for the oneOrManyOrAny property.
+// * <p/>
+// * <p/>
+// * For example, to add a new item, do as follows:
+// * <pre>
+// * getOneOrManyOrAny().add(newItem);
+// * </pre>
+// * <p/>
+// * <p/>
+// * <p/>
+// * Objects of the following type(s) are allowed in the list
+// * {@link JAXBElement }{@code <}{@link ManyType }{@code >}
+// * {@link Element }
+// * {@link Object }
+// * {@link JAXBElement }{@code <}{@link OneType }{@code >}
+// */
+ public List<Object> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Object>();
+ }
+ return this.any;
+ }
+
+ public List<OneType> getOneList()
+ {
+ if (oneList == null)
+ {
+ oneList = new ArrayList<OneType>();
+ }
+ return this.oneList;
+ }
+
+ public List<ManyType> getManyList()
+ {
+ if (manyList == null)
+ {
+ manyList = new ArrayList<ManyType>();
+ }
+ return this.manyList;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ManyType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ManyType.java
new file mode 100644
index 0000000..3a05650
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ManyType.java
@@ -0,0 +1,104 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+import java.util.*;
+//import javax.xml.bind.*;
+//import javax.xml.bind.annotation.*;
+
+/**
+ * <p>Java class for manyType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="manyType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;choice maxOccurs="unbounded" minOccurs="0">
+ * &lt;element name="except" type="{urn:ietf:params:xml:ns:common-policy}exceptType"/>
+ * &lt;any/>
+ * &lt;/choice>
+ * &lt;attribute name="domain" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "manyType", propOrder = {
+// "exceptOrAny"
+// })
+//@XmlRootElement(name = "many",
+// namespace = "urn:ietf:params:xml:ns:common-policy")
+public class ManyType
+{
+
+// @XmlElementRef(name = "except",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = JAXBElement.class)
+// @XmlAnyElement(lax = true)
+ protected List<Object> exceptOrAny;
+
+// @XmlAttribute
+ protected String domain;
+
+// /**
+// * Gets the value of the exceptOrAny property.
+// * <p/>
+// * <p/>
+// * This accessor method returns a reference to the live list,
+// * not a snapshot. Therefore any modification you make to the
+// * returned list will be present inside the JAXB object.
+// * This is why there is not a <CODE>set</CODE> method for the exceptOrAny property.
+// * <p/>
+// * <p/>
+// * For example, to add a new item, do as follows:
+// * <pre>
+// * getExceptOrAny().add(newItem);
+// * </pre>
+// * <p/>
+// * <p/>
+// * <p/>
+// * Objects of the following type(s) are allowed in the list
+// * {@link Element }
+// * {@link JAXBElement }{@code <}{@link ExceptType }{@code >}
+// * {@link Object }
+// */
+ public List<Object> getExceptOrAny()
+ {
+ if (exceptOrAny == null)
+ {
+ exceptOrAny = new ArrayList<Object>();
+ }
+ return this.exceptOrAny;
+ }
+
+ /**
+ * Gets the value of the domain property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getDomain()
+ {
+ return domain;
+ }
+
+ /**
+ * Sets the value of the domain property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setDomain(String value)
+ {
+ this.domain = value;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/OneType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/OneType.java
new file mode 100644
index 0000000..e3ac678
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/OneType.java
@@ -0,0 +1,91 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+import org.w3c.dom.*;
+
+/**
+ * <p>Java class for oneType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="oneType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;any/>
+ * &lt;/sequence>
+ * &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}anyURI" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "oneType", propOrder = {
+// "any"
+// })
+//@XmlRootElement(name = "one",
+// namespace = "urn:ietf:params:xml:ns:common-policy")
+public class OneType
+{
+
+// @XmlAnyElement(lax = true)
+ protected Object any;
+
+// @XmlAttribute(required = true)
+ protected String id;
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return possible object is
+ * {@link Element }
+ * {@link Object }
+ */
+ public Object getAny()
+ {
+ return any;
+ }
+
+ /**
+ * Sets the value of the any property.
+ *
+ * @param value allowed object is
+ * {@link Element }
+ * {@link Object }
+ */
+ public void setAny(Object value)
+ {
+ this.any = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setId(String value)
+ {
+ this.id = value;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RuleType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RuleType.java
new file mode 100644
index 0000000..209d877
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RuleType.java
@@ -0,0 +1,141 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+/**
+ * <p>Java class for ruleType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="ruleType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="conditions" type="{urn:ietf:params:xml:ns:common-policy}conditionsType" minOccurs="0"/>
+ * &lt;element name="actions" type="{urn:ietf:params:xml:ns:common-policy}extensibleType" minOccurs="0"/>
+ * &lt;element name="transformations" type="{urn:ietf:params:xml:ns:common-policy}extensibleType" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}ID" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "ruleType", propOrder = {
+// "conditions",
+// "actions",
+// "transformations"
+// })
+public class RuleType
+{
+
+// @XmlElement(namespace = "urn:ietf:params:xml:ns:common-policy")
+ protected ConditionsType conditions;
+
+// @XmlElement(namespace = "urn:ietf:params:xml:ns:common-policy")
+ protected ActionsType actions;
+
+// @XmlElement(namespace = "urn:ietf:params:xml:ns:common-policy")
+ protected TransfomationsType transformations;
+
+// @XmlAttribute(required = true)
+// @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+// @XmlID
+ protected String id;
+
+ /**
+ * Gets the value of the conditions property.
+ *
+ * @return possible object is
+ * {@link ConditionsType }
+ */
+ public ConditionsType getConditions()
+ {
+ return conditions;
+ }
+
+ /**
+ * Sets the value of the conditions property.
+ *
+ * @param value allowed object is
+ * {@link ConditionsType }
+ */
+ public void setConditions(ConditionsType value)
+ {
+ this.conditions = value;
+ }
+
+ /**
+ * Gets the value of the actions property.
+ *
+ * @return possible object is
+ * {@link TransfomationsType }
+ */
+ public ActionsType getActions()
+ {
+ return actions;
+ }
+
+ /**
+ * Sets the value of the actions property.
+ *
+ * @param value allowed object is
+ * {@link TransfomationsType }
+ */
+ public void setActions(ActionsType value)
+ {
+ this.actions = value;
+ }
+
+ /**
+ * Gets the value of the transformations property.
+ *
+ * @return possible object is
+ * {@link TransfomationsType }
+ */
+ public TransfomationsType getTransformations()
+ {
+ return transformations;
+ }
+
+ /**
+ * Sets the value of the transformations property.
+ *
+ * @param value allowed object is
+ * {@link TransfomationsType }
+ */
+ public void setTransformations(TransfomationsType value)
+ {
+ this.transformations = value;
+ }
+
+ /**
+ * Gets the value of the id property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ /**
+ * Sets the value of the id property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setId(String value)
+ {
+ this.id = value;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RulesetType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RulesetType.java
new file mode 100644
index 0000000..b287ac3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/RulesetType.java
@@ -0,0 +1,74 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+import java.util.*;
+import java.util.List;
+//import javax.xml.bind.annotation.*;
+
+/**
+ * <p>Java class for ruleset element declaration.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;element name="ruleset">
+ * &lt;complexType>
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;element name="rule" type="{urn:ietf:params:xml:ns:common-policy}ruleType" maxOccurs="unbounded" minOccurs="0"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * &lt;/element>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "", propOrder = {
+// "rule"
+// })
+//@XmlRootElement(name = "ruleset")
+public class RulesetType
+{
+//
+// @XmlElement(namespace = "urn:ietf:params:xml:ns:common-policy",
+// required = true)
+ protected List<RuleType> rule;
+
+ /**
+ * Gets the value of the rule property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the rule property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getRule().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link RuleType }
+ */
+ public List<RuleType> getRule()
+ {
+ if (rule == null)
+ {
+ rule = new ArrayList<RuleType>();
+ }
+ return this.rule;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/SphereType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/SphereType.java
new file mode 100644
index 0000000..1ed4cb7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/SphereType.java
@@ -0,0 +1,55 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+/**
+ * <p>Java class for sphereType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="sphereType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "sphereType")
+public class SphereType
+{
+
+// @XmlAttribute(required = true)
+ protected String value;
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/TransfomationsType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/TransfomationsType.java
new file mode 100644
index 0000000..a5adc78
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/TransfomationsType.java
@@ -0,0 +1,120 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules.*;
+import org.w3c.dom.*;
+
+import java.util.*;
+
+/**
+ * <p>Java class for extensibleType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="extensibleType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence>
+ * &lt;any/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "transfomationsType", propOrder = {
+// "servicePermission",
+// "personPermission",
+// "devicePermission",
+// "any"
+// })
+public class TransfomationsType
+{
+
+// @XmlElement(name = "provide-services",
+// namespace = "urn:ietf:params:xml:ns:resource-lists",
+// required = false)
+ protected ProvideServicePermission servicePermission;
+
+// @XmlElement(name = "provide-persons",
+// namespace = "urn:ietf:params:xml:ns:resource-lists",
+// required = false)
+ protected ProvidePersonPermission personPermission;
+
+// @XmlElement(name = "provide-devices",
+// namespace = "urn:ietf:params:xml:ns:resource-lists",
+// required = false)
+ protected ProvideDevicePermission devicePermission;
+
+// @XmlAnyElement(lax = true)
+ protected List<Object> any;
+
+ public ProvideServicePermission getServicePermission()
+ {
+ return servicePermission;
+ }
+
+ public void setServicePermission(ProvideServicePermission servicePermission)
+ {
+ this.servicePermission = servicePermission;
+ }
+
+ public ProvidePersonPermission getPersonPermission()
+ {
+ return personPermission;
+ }
+
+ public void setPersonPermission(ProvidePersonPermission personPermission)
+ {
+ this.personPermission = personPermission;
+ }
+
+ public ProvideDevicePermission getDevicePermission()
+ {
+ return devicePermission;
+ }
+
+ public void setDevicePermission(ProvideDevicePermission devicePermission)
+ {
+ this.devicePermission = devicePermission;
+ }
+
+ /**
+ * Gets the value of the any property.
+ * <p/>
+ * <p/>
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a <CODE>set</CODE> method for the any property.
+ * <p/>
+ * <p/>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getAny().add(newItem);
+ * </pre>
+ * <p/>
+ * <p/>
+ * <p/>
+ * Objects of the following type(s) are allowed in the list
+ * {@link Element }
+ * {@link Object }
+ */
+ public List<Object> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Object>();
+ }
+ return this.any;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ValidityType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ValidityType.java
new file mode 100644
index 0000000..cdff1ce
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/ValidityType.java
@@ -0,0 +1,75 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.commonpolicy;
+
+/**
+ * <p>Java class for validityType complex type.
+ * <p/>
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * <p/>
+ * <pre>
+ * &lt;complexType name="validityType">
+ * &lt;complexContent>
+ * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * &lt;sequence maxOccurs="unbounded">
+ * &lt;element name="from" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ * &lt;element name="until" type="{http://www.w3.org/2001/XMLSchema}dateTime"/>
+ * &lt;/sequence>
+ * &lt;/restriction>
+ * &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "validityType", propOrder = {
+// "fromAndUntil"
+// })
+public class ValidityType
+{
+
+// @XmlElementRefs({
+// @XmlElementRef(name = "from",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = JAXBElement.class),
+// @XmlElementRef(name = "until",
+// namespace = "urn:ietf:params:xml:ns:common-policy",
+// type = JAXBElement.class)
+// })
+// protected List<JAXBElement<XMLGregorianCalendar>> fromAndUntil;
+
+// /**
+// * Gets the value of the fromAndUntil property.
+// * <p/>
+// * <p/>
+// * This accessor method returns a reference to the live list,
+// * not a snapshot. Therefore any modification you make to the
+// * returned list will be present inside the JAXB object.
+// * This is why there is not a <CODE>set</CODE> method for the fromAndUntil property.
+// * <p/>
+// * <p/>
+// * For example, to add a new item, do as follows:
+// * <pre>
+// * getFromAndUntil().add(newItem);
+// * </pre>
+// * <p/>
+// * <p/>
+// * <p/>
+// * Objects of the following type(s) are allowed in the list
+// * {@link JAXBElement }{@code <}{@link XMLGregorianCalendar }{@code >}
+// * {@link JAXBElement }{@code <}{@link XMLGregorianCalendar }{@code >}
+// */
+// public List<JAXBElement<XMLGregorianCalendar>> getFromAndUntil()
+// {
+// if (fromAndUntil == null)
+// {
+// fromAndUntil = new ArrayList<JAXBElement<XMLGregorianCalendar>>();
+// }
+// return this.fromAndUntil;
+// }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/common-policy.xsd b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/common-policy.xsd
new file mode 100644
index 0000000..bc84e4b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/commonpolicy/common-policy.xsd
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:cp="urn:ietf:params:xml:ns:common-policy"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="urn:ietf:params:xml:ns:common-policy"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+ <xs:element name="ruleset">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:sequence>
+ <xs:element name="rule" type="cp:ruleType" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="ruleType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:sequence>
+ <xs:element name="conditions" type="cp:conditionsType" minOccurs="0"/>
+ <xs:element name="actions" type="cp:extensibleType" minOccurs="0"/>
+ <xs:element name="transformations" type="cp:extensibleType" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:ID" use="required"/>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="conditionsType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="identity" type="cp:identityType" minOccurs="0"/>
+ <xs:element name="sphere" type="cp:sphereType" minOccurs="0"/>
+ <xs:element name="validity" type="cp:validityType" minOccurs="0"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xs:choice>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="identityType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:choice maxOccurs="unbounded">
+ <xs:element name="one" type="cp:oneType"/>
+ <xs:element name="many" type="cp:manyType"/>
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:choice>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="oneType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="id" type="xs:anyURI" use="required"/>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="manyType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="except" type="cp:exceptType"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"/>
+ </xs:choice>
+ <xs:attribute name="domain" type="xs:string" use="optional"/>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="exceptType">
+ <xs:attribute name="domain" type="xs:string" use="optional"/>
+ <xs:attribute name="id" type="xs:anyURI" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="sphereType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:attribute name="value" type="xs:string" use="required"/>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="validityType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:sequence maxOccurs="unbounded">
+ <xs:element name="from" type="xs:dateTime"/>
+ <xs:element name="until" type="xs:dateTime"/>
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+ <xs:complexType name="extensibleType">
+ <xs:complexContent>
+ <xs:restriction base="xs:anyType">
+ <xs:sequence>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:restriction>
+ </xs:complexContent>
+ </xs:complexType>
+</xs:schema>
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/ContentType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/ContentType.java
new file mode 100644
index 0000000..172d3d3
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/ContentType.java
@@ -0,0 +1,173 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent;
+
+import java.util.*;
+import javax.xml.namespace.*;
+
+import org.w3c.dom.*;
+
+/**
+ * The XCAP content element.
+ * <p/>
+ * Compliant with Presence Content XDM Specification v1.0
+ *
+ * @author Grigorii Balutsel
+ */
+public class ContentType
+{
+ /**
+ * The data element.
+ */
+ private DataType data;
+
+ /**
+ * The mime-type element.
+ */
+ private MimeType mimeType;
+
+ /**
+ * The encoding element.
+ */
+ private EncodingType encoding;
+
+ /**
+ * The list of description elements.
+ */
+ private List<DescriptionType> description;
+
+ /**
+ * The list of any elements.
+ */
+ private List<Element> any;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Gets the value of the mimeType property.
+ *
+ * @return the mimeType property.
+ */
+ public MimeType getMimeType()
+ {
+ return mimeType;
+ }
+
+ /**
+ * Sets the value of the mimeType property.
+ *
+ * @param mimeType the mimeType to set.
+ */
+ public void setMimeType(MimeType mimeType)
+ {
+ this.mimeType = mimeType;
+ }
+
+
+ /**
+ * Gets the value of the encoding property.
+ *
+ * @return the encoding property.
+ */
+ public EncodingType getEncoding()
+ {
+ return encoding;
+ }
+
+ /**
+ * Sets the value of the encoding property.
+ *
+ * @param encoding the encoding to set.
+ */
+ public void setEncoding(EncodingType encoding)
+ {
+ this.encoding = encoding;
+ }
+
+
+ /**
+ * Gets the value of the description property.
+ *
+ * @return the description property.
+ */
+ public List<DescriptionType> getDescription()
+ {
+ if (description == null)
+ {
+ description = new ArrayList<DescriptionType>();
+ }
+ return this.description;
+ }
+
+
+ /**
+ * Gets the value of the data property.
+ *
+ * @return the data property.
+ */
+ public DataType getData()
+ {
+ return data;
+ }
+
+ /**
+ * Sets the value of the data property.
+ *
+ * @param data the data to set.
+ */
+ public void setData(DataType data)
+ {
+ this.data = data;
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return the any property.
+ */
+ public List<Element> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+
+ /**
+ * Sets the value of the any property.
+ *
+ * @param any the any to set.
+ */
+ public void setAny(List<Element> any)
+ {
+ this.any = any;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+
+ /**
+ * Sets the value of the anyAttributes property.
+ *
+ * @param anyAttributes the anyAttributes to set.
+ */
+ public void setAnyAttributes(Map<QName, String> anyAttributes)
+ {
+ this.anyAttributes = anyAttributes;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DataType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DataType.java
new file mode 100644
index 0000000..be02ba1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DataType.java
@@ -0,0 +1,60 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent;
+
+import javax.xml.namespace.*;
+import java.util.*;
+
+/**
+ * The PRES-CONTENT data element.
+ * <p/>
+ * Compliant with Presence Content XDM Specification v1.0
+ *
+ * @author Grigorii Balutsel
+ */
+public class DataType
+{
+ /**
+ * The element value.
+ */
+ protected String value;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return the value property.
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value the value to set.
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DescriptionType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DescriptionType.java
new file mode 100644
index 0000000..70fb631
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/DescriptionType.java
@@ -0,0 +1,114 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent;
+
+import javax.xml.namespace.*;
+import java.util.*;
+
+/**
+ * The PRES-CONTENT description element.
+ * <p/>
+ * Compliant with Presence Content XDM Specification v1.0
+ *
+ * @author Grigorii Balutsel
+ */
+public class DescriptionType
+{
+ /**
+ * The element value.
+ */
+ private String value;
+
+ /**
+ * The lang attribute.
+ */
+ private String lang;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Creates description.
+ */
+ public DescriptionType()
+ {
+ }
+
+ /**
+ * Creates description with value.
+ *
+ * @param value the value property.
+ */
+ public DescriptionType(String value)
+ {
+ this(value, null);
+ }
+
+ /**
+ * Creates description with value and lang properties.
+ *
+ * @param value the value property.
+ * @param lang the lang property.
+ */
+ public DescriptionType(String value, String lang)
+ {
+ this.value = value;
+ this.lang = lang;
+ }
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return the value property.
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value the value to set.
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the lang property.
+ *
+ * @return the lang property.
+ */
+ public String getLang()
+ {
+ return lang;
+ }
+
+ /**
+ * Sets the value of the lang property.
+ *
+ * @param lang the lang to set.
+ */
+ public void setLang(String lang)
+ {
+ this.lang = lang;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/EncodingType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/EncodingType.java
new file mode 100644
index 0000000..f79093a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/EncodingType.java
@@ -0,0 +1,60 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent;
+
+import javax.xml.namespace.*;
+import java.util.*;
+
+/**
+ * The PRES-CONTENT encoding element.
+ * <p/>
+ * Compliant with Presence Content XDM Specification v1.0
+ *
+ * @author Grigorii Balutsel
+ */
+public class EncodingType
+{
+ /**
+ * The element value.
+ */
+ protected String value;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return the value property.
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value the value to set.
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/MimeType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/MimeType.java
new file mode 100644
index 0000000..86bd358
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/MimeType.java
@@ -0,0 +1,60 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent;
+
+import javax.xml.namespace.*;
+import java.util.*;
+
+/**
+ * The PRES-CONTENT mime-type element.
+ * <p/>
+ * Compliant with Presence Content XDM Specification v1.0
+ *
+ * @author Grigorii Balutsel
+ */
+public class MimeType
+{
+ /**
+ * The element value.
+ */
+ protected String value;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return the value property.
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value the value to set.
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/PresContentParser.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/PresContentParser.java
new file mode 100644
index 0000000..ffd24db
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/PresContentParser.java
@@ -0,0 +1,476 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.*;
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.XmlUtils.*;
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.StringUtils.*;
+
+import static javax.xml.XMLConstants.*;
+
+import org.w3c.dom.*;
+
+import javax.xml.namespace.*;
+import java.util.*;
+
+/**
+ * Utility class that helps to converts pres-content xml to the object model and
+ * object model to the pres-content xml.
+ *
+ * @author Grigorii Balutsel
+ */
+public class PresContentParser
+{
+ private static String NAMESPACE = "urn:oma:xml:prs:pres-content";
+
+ private static String CONTENT_ELEMENT = "content";
+
+ private static String MIMETYPE_ELEMENT = "mime-type";
+
+ private static String ENCODING_ELEMENT = "encoding";
+
+ private static String DESCRIPTION_ELEMENT = "description";
+
+ private static String DESCRIPTION_LANG_ATTR = "lang";
+
+ private static String DATA_ELEMENT = "data";
+
+ /**
+ * Creates xcap-caps object from the element.
+ *
+ * @param xml the XML to analyze.
+ * @return the xcap-caps object.
+ * @throws ParsingException if there is some error during parsing.
+ */
+ public static ContentType fromXml(String xml)
+ throws ParsingException
+ {
+ if (isNullOrEmpty(xml))
+ {
+ throw new IllegalArgumentException("XML cannot be null or empty");
+ }
+ try
+ {
+ ContentType content = new ContentType();
+ Document document = XmlUtils.createDocument(xml);
+ Element contentElement = document.getDocumentElement();
+ if (CONTENT_ELEMENT.equals(contentElement.getLocalName()) &&
+ !NAMESPACE.equals(contentElement.getNamespaceURI()))
+ {
+ throw new Exception(
+ "Document doesn't contain content element");
+ }
+ // Process attributes
+ NamedNodeMap attributes = contentElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("content element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ throw new Exception("content element is invalid");
+ }
+ QName qName = new QName(namespaceUri,
+ attribute.getLocalName(),
+ attribute.getPrefix() == null ? "" :
+ attribute.getPrefix());
+ content.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ // Process elements
+ NodeList childNodes = contentElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("content element is invalid");
+ }
+ String localName = node.getLocalName();
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ // data
+ if (DATA_ELEMENT.equals(localName))
+ {
+ content.setData(dataFromElement(element));
+ }
+ // mime-type
+ else if (MIMETYPE_ELEMENT.equals(localName))
+ {
+ content.setMimeType(mimeTypeFromElement(element));
+ }
+ // encoding
+ else if (ENCODING_ELEMENT.equals(localName))
+ {
+ content.setEncoding(encodingFromElement(element));
+ }
+ // descritpion
+ else if (DESCRIPTION_ELEMENT.equals(localName))
+ {
+ content.getDescription()
+ .add(descriptionFromElement(element));
+ }
+ else
+ {
+ throw new Exception("content element is invalid");
+ }
+ }
+ else
+ {
+ // any
+ content.getAny().add(element);
+ }
+ }
+ return content;
+ }
+ catch (Exception ex)
+ {
+ throw new ParsingException(ex);
+ }
+ }
+
+ /**
+ * Creates XML from the pres-content element.
+ *
+ * @param content the pres-content to analyze.
+ * @return the pres-content xml.
+ * @throws ParsingException if there is some error during parsing.
+ */
+ public static String toXml(ContentType content)
+ throws ParsingException
+ {
+ if (content == null)
+ {
+ throw new IllegalArgumentException("pres-content cannot be null");
+ }
+ try
+ {
+ Document document = createDocument();
+ Element presContentElement =
+ document.createElementNS(NAMESPACE, CONTENT_ELEMENT);
+ if (content.getData() != null)
+ {
+ presContentElement.appendChild(elementFromValue(
+ document,
+ DATA_ELEMENT,
+ content.getData().getValue(),
+ content.getData().getAnyAttributes()));
+ }
+ if (content.getEncoding() != null)
+ {
+ presContentElement.appendChild(elementFromValue(
+ document,
+ ENCODING_ELEMENT,
+ content.getEncoding().getValue(),
+ content.getEncoding().getAnyAttributes()));
+ }
+ if (content.getMimeType() != null)
+ {
+ presContentElement.appendChild(elementFromValue(
+ document,
+ MIMETYPE_ELEMENT,
+ content.getMimeType().getValue(),
+ content.getMimeType().getAnyAttributes()));
+ }
+ for (DescriptionType description : content.getDescription())
+ {
+ presContentElement.appendChild(
+ elementFromDescription(document, description));
+ }
+ processAnyAttributes(presContentElement,
+ content.getAnyAttributes());
+ processAny(presContentElement, content.getAny());
+ document.appendChild(presContentElement);
+ return createXml(document);
+ }
+ catch (Exception ex)
+ {
+ throw new ParsingException(ex);
+ }
+ }
+
+ /**
+ * Creates display-name element from the value and attributes.
+ *
+ * @param document the xml document.
+ * @param nodeName the local node name.
+ * @param value the xml node value.
+ * @param anyAttributes the map of any attributes
+ * @return the xml element.
+ */
+ private static Element elementFromValue(
+ Document document, String nodeName, String value,
+ Map<QName, String> anyAttributes)
+ {
+ Element element = document.createElementNS(NAMESPACE, nodeName);
+ if (value != null)
+ {
+ element.setTextContent(value);
+ }
+ processAnyAttributes(element, anyAttributes);
+ return element;
+ }
+
+ /**
+ * Creates ddescriptionelement from the object.
+ *
+ * @param document the xml document.
+ * @param description the description to analyze.
+ * @return the description element.
+ * @throws Exception if there is some error during creating.
+ */
+ private static Element elementFromDescription(
+ Document document,
+ DescriptionType description)
+ throws Exception
+ {
+ Element element = document.createElementNS(NAMESPACE,
+ DESCRIPTION_ELEMENT);
+ if (description.getLang() != null)
+ {
+ element.setAttribute(
+ XML_NS_PREFIX + ":" + DESCRIPTION_LANG_ATTR,
+ description.getLang());
+ }
+ if (description.getValue() != null)
+ {
+ element.setTextContent(description.getValue());
+ }
+ processAnyAttributes(element, description.getAnyAttributes());
+ return element;
+ }
+
+ /**
+ * Creates data object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the display-name object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static DataType dataFromElement(Element element)
+ throws Exception
+ {
+ DataType result = new DataType();
+ if (!DATA_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("data element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("data element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ throw new Exception("data element is invalid");
+ }
+ QName qName = new QName(namespaceUri,
+ attribute.getLocalName(),
+ attribute.getPrefix() == null ? "" :
+ attribute.getPrefix());
+ result.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ throw new Exception("data element is invalid");
+ }
+ }
+ result.setValue(element.getTextContent());
+ return result;
+ }
+
+ /**
+ * Creates data object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the data object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static EncodingType encodingFromElement(Element element)
+ throws Exception
+ {
+ EncodingType result = new EncodingType();
+ if (!ENCODING_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("encoding element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("encoding element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ throw new Exception("encoding element is invalid");
+ }
+ QName qName = new QName(namespaceUri,
+ attribute.getLocalName(),
+ attribute.getPrefix() == null ? "" :
+ attribute.getPrefix());
+ result.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ throw new Exception("encoding element is invalid");
+ }
+ }
+ result.setValue(element.getTextContent());
+ return result;
+ }
+
+ /**
+ * Creates mime-type object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the mime-type object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static MimeType mimeTypeFromElement(Element element)
+ throws Exception
+ {
+ MimeType result = new MimeType();
+ if (!MIMETYPE_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("mime-type element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("mime-type element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ throw new Exception("mime-type element is invalid");
+ }
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ throw new Exception("encoding element is invalid");
+ }
+ }
+ result.setValue(element.getTextContent());
+ return result;
+ }
+
+ /**
+ * Creates description object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the description object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static DescriptionType descriptionFromElement(Element element)
+ throws Exception
+ {
+ DescriptionType result = new DescriptionType();
+ if (!DESCRIPTION_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("description element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("description element is invalid");
+ }
+ if (DESCRIPTION_LANG_ATTR.equals(attribute.getLocalName()) &&
+ XML_NS_URI.equals(namespaceUri))
+ {
+ result.setLang(attribute.getValue());
+ continue;
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ throw new Exception("description element is invalid");
+ }
+ QName qName = new QName(namespaceUri,
+ attribute.getLocalName(),
+ attribute.getPrefix() == null ? "" :
+ attribute.getPrefix());
+ result.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ throw new Exception("description element is invalid");
+ }
+ }
+ result.setValue(element.getTextContent());
+ return result;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/pres-content.xsd b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/pres-content.xsd
new file mode 100644
index 0000000..11d6017
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/prescontent/pres-content.xsd
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+
+Schema for the Presence Content Application Usage
+ version - 1.0
+ date - 23 Dec 2008
+
+FILE INFORMATION
+
+ OMA Permanent Document
+ File: OMA-SUP-XSD_prs_presContent-V1_0-20081223-C
+ Type: Text - Schema Description
+
+ Public Reachable Information
+ Path: http://www.openmobilealliance.org/Technical/schemas.aspx
+ Name: prs_presContent-v1_0.xsd
+NORMATIVE INFORMATION
+
+ Information about this file can be found in the specification
+
+ OMA-TS-Presence-SIMPLE_Content_XDM-V1_0
+
+ available at http://www.openmobilealliance.org/
+
+ Send comments to technical-comments@mail.openmobilealliance.org
+
+LEGAL DISCLAIMER
+
+ Use of this document is subject to all of the terms and conditions
+ of the Use Agreement located at
+ http://www.openmobilealliance.org/UseAgreement.html
+
+ You may use this document or any part of the document for internal
+ or educational purposes only, provided you do not modify, edit or
+ take out of context the information in this document in any manner.
+ Information contained in this document may be used, at your sole
+ risk, for any purposes.
+
+ You may not use this document in any other manner without the prior
+ written permission of the Open Mobile Alliance. The Open Mobile
+ Alliance authorizes you to copy this document, provided that you
+ retain all copyright and other proprietary notices contained in the
+ original materials on any copies of the materials and that you
+ comply strictly with these terms. This copyright permission does
+ not constitute an endorsement of the products or services. The
+ Open Mobile Alliance assumes no responsibility for errors or
+ omissions in this document.
+
+ Each Open Mobile Alliance member has agreed to use reasonable
+ endeavors to inform the Open Mobile Alliance in a timely manner of
+ Essential IPR as it becomes aware that the Essential IPR is related
+ to the prepared or published specification. However, the members
+ do not have an obligation to conduct IPR searches. The declared
+ Essential IPR is publicly available to members and non-members of
+ the Open Mobile Alliance and may be found on the "OMA IPR
+ Declarations" list at http://www.openmobilealliance.org/ipr.html.
+ The Open Mobile Alliance has not conducted an independent IPR review
+ of this document and the information contained herein, and makes no
+ representations or warranties regarding third party IPR, including
+ without limitation patents, copyrights or trade secret rights. This
+ document may contain inventions for which you must obtain licenses
+ from third parties before making, using or selling the inventions.
+ Defined terms above are set forth in the schedule to the Open Mobile
+ Alliance Application Form.
+
+ NO REPRESENTATIONS OR WARRANTIES (WHETHER EXPRESS OR IMPLIED) ARE
+ MADE BY THE OPEN MOBILE ALLIANCE OR ANY OPEN MOBILE ALLIANCE MEMBER
+ OR ITS AFFILIATES REGARDING ANY OF THE IPR'S REPRESENTED ON THE "OMA
+ IPR DECLARATIONS" LIST, INCLUDING, BUT NOT LIMITED TO THE ACCURACY,
+ COMPLETENESS, VALIDITY OR RELEVANCE OF THE INFORMATION OR WHETHER OR
+ NOT SUCH RIGHTS ARE ESSENTIAL OR NON-ESSENTIAL.
+
+ THE OPEN MOBILE ALLIANCE IS NOT LIABLE FOR AND HEREBY DISCLAIMS ANY
+ DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR
+ EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE OF
+ DOCUMENTS AND THE INFORMATION CONTAINED IN THE DOCUMENTS.
+
+ Copyright 2008 Open Mobile Alliance Ltd. All Rights Reserved.
+ Used with the permission of the Open Mobile Alliance Ltd. under the
+ terms set forth above.
+
+-->
+
+<xs:schema targetNamespace="urn:oma:xml:prs:pres-content"
+ xmlns="urn:oma:xml:prs:pres-content"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+ <xs:element name="content">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="mime-type" minOccurs="0">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:anyAttribute processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="encoding" minOccurs="0">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:anyAttribute processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="description" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute ref="xml:lang"/>
+ <xs:anyAttribute processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="data">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:anyAttribute processContents="lax"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:anyAttribute processContents="lax"/>
+ </xs:complexType>
+ </xs:element>
+
+</xs:schema>
+
+
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideAllAttributes.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideAllAttributes.java
new file mode 100644
index 0000000..ded8676
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideAllAttributes.java
@@ -0,0 +1,22 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules;
+
+/**
+ * Grants access to all presence attributes in all of the person, device, and
+ * tuple elements that are present in thedocument
+ * <p/>
+ * Compliant with rfc5025.
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "")
+//@XmlRootElement(name = "provide-all-attributes")
+public class ProvideAllAttributes
+{
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideDevicePermission.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideDevicePermission.java
new file mode 100644
index 0000000..b3f9363
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideDevicePermission.java
@@ -0,0 +1,78 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules;
+
+import java.util.*;
+
+/**
+ * Allows a watcher to see "device" information present in the presence
+ * document.
+ * <p/>
+ * Compliant with rfc5025.
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "provideDevicePermission", propOrder = {
+// "allDevices",
+// "deviceIDOrOccurrenceIdOrClazz"
+// })
+//@XmlRootElement(name = "providedevices",
+// namespace = "urn:ietf:params:xml:ns:pres-rules")
+public class ProvideDevicePermission
+{
+//
+// @XmlElement(name = "all-devices",
+// namespace = "urn:ietf:params:xml:ns:pres-rules")
+ protected AllDevices allDevices;
+// @XmlElementRefs({
+// @XmlElementRef(name = "deviceID", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class),
+// @XmlElementRef(name = "occurrence-id", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class),
+// @XmlElementRef(name = "class", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class)
+
+ // })
+
+// @XmlAnyElement(lax = true)
+ protected List<Object> deviceIDOrOccurrenceIdOrClazz;
+
+ /**
+ * Gets the value of the allDevices property.
+ *
+ * @return possible object is
+ * {@link AllDevices }
+ */
+ public AllDevices getAllDevices()
+ {
+ return allDevices;
+ }
+
+ /**
+ * Sets the value of the allDevices property.
+ *
+ * @param value allowed object is
+ * {@link AllDevices }
+ */
+ public void setAllDevices(AllDevices value)
+ {
+ this.allDevices = value;
+ }
+
+ public List<Object> getDeviceIDOrOccurrenceIdOrClazz()
+ {
+ if (deviceIDOrOccurrenceIdOrClazz == null)
+ {
+ deviceIDOrOccurrenceIdOrClazz = new ArrayList<Object>();
+ }
+ return this.deviceIDOrOccurrenceIdOrClazz;
+ }
+
+
+
+ public static class AllDevices
+ {
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvidePersonPermission.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvidePersonPermission.java
new file mode 100644
index 0000000..bf4c673
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvidePersonPermission.java
@@ -0,0 +1,82 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules;
+
+import java.util.*;
+
+
+/**
+ * Allows a watcher to see the "person" information present in the presence
+ * document.
+ * <p/>
+ * Compliant with rfc5025.
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "providePersonPermission", propOrder = {
+// "allPersons",
+// "occurrenceIdOrClazzOrAny"
+// })
+//@XmlRootElement(name = "provide-persons",
+// namespace = "urn:ietf:params:xml:ns:pres-rules")
+public class ProvidePersonPermission
+{
+//
+// @XmlElement(name = "all-persons",
+// namespace = "urn:ietf:params:xml:ns:pres-rules")
+ protected AllPersons allPersons;
+// @XmlElementRefs({
+// @XmlElementRef(name = "occurrence-id", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class),
+
+ // @XmlElementRef(name = "class", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class)
+ // })
+// @XmlAnyElement(lax = true)
+ protected List<Object> occurrenceIdOrClazzOrAny;
+
+ /**
+ * Gets the value of the allPersons property.
+ *
+ * @return possible object is
+ * {@link AllPersons }
+ */
+ public AllPersons getAllPersons()
+ {
+ return allPersons;
+ }
+
+ /**
+ * Sets the value of the allPersons property.
+ *
+ * @param value allowed object is
+ * {@link AllPersons }
+ */
+ public void setAllPersons(AllPersons value)
+ {
+ this.allPersons = value;
+ }
+
+
+ public List<Object> getOccurrenceIdOrClazzOrAny()
+ {
+ if (occurrenceIdOrClazzOrAny == null)
+ {
+ occurrenceIdOrClazzOrAny = new ArrayList<Object>();
+ }
+ return this.occurrenceIdOrClazzOrAny;
+ }
+
+
+//
+// @XmlAccessorType(XmlAccessType.FIELD)
+// @XmlType(name = "")
+ public static class AllPersons
+ {
+
+
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideServicePermission.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideServicePermission.java
new file mode 100644
index 0000000..0dbbb93
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/ProvideServicePermission.java
@@ -0,0 +1,86 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules;
+
+import java.util.*;
+
+/**
+ * Allows a watcher to see service information present in "tuple" elements in
+ * the presence document the subscription authorization decision that the server
+ * should make.
+ * <p/>
+ * Compliant with rfc5025.
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "provideServicePermission", propOrder = {
+// "allServices",
+// "serviceUriOrServiceUriSchemeOrOccurrenceId"
+// })
+//@XmlRootElement(name = "provide-services",
+// namespace = "urn:ietf:params:xml:ns:pres-rules")
+public class ProvideServicePermission
+{
+//
+// @XmlElement(name = "all-services",
+// namespace = "urn:ietf:params:xml:ns:pres-rules")
+ protected AllServices allServices;
+// @XmlElementRefs({
+// @XmlElementRef(name = "service-uri", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class),
+// @XmlElementRef(name = "service-uri-scheme", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class),
+// @XmlElementRef(name = "occurrence-id", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class),
+// @XmlElementRef(name = "class", namespace = "urn:ietf:params:xml:ns:pres-rules", type = JAXBElement.class)
+
+ // })
+
+// @XmlAnyElement(lax = true)
+ protected List<Object> serviceUriOrServiceUriSchemeOrOccurrenceId;
+
+ /**
+ * Gets the value of the allServices property.
+ *
+ * @return possible object is
+ * {@link AllServices }
+ */
+ public AllServices getAllServices()
+ {
+ return allServices;
+ }
+
+ /**
+ * Sets the value of the allServices property.
+ *
+ * @param value allowed object is
+ * {@link AllServices }
+ */
+ public void setAllServices(AllServices value)
+ {
+ this.allServices = value;
+ }
+
+
+ public List<Object> getServiceUriOrServiceUriSchemeOrOccurrenceId()
+ {
+ if (serviceUriOrServiceUriSchemeOrOccurrenceId == null)
+ {
+ serviceUriOrServiceUriSchemeOrOccurrenceId =
+ new ArrayList<Object>();
+ }
+ return this.serviceUriOrServiceUriSchemeOrOccurrenceId;
+ }
+
+
+
+// @XmlAccessorType(XmlAccessType.FIELD)
+// @XmlType(name = "")
+ public static class AllServices
+ {
+
+
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/SubHandlingType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/SubHandlingType.java
new file mode 100644
index 0000000..f898ea2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/SubHandlingType.java
@@ -0,0 +1,70 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules;
+
+/**
+ * Specifies the subscription authorization decision that the server should
+ * make.
+ * <p/>
+ * Compliant with rfc5025.
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlEnum
+public enum SubHandlingType
+{
+ /**
+ * This action tells the server to reject the subscription, placing it in
+ * the "terminated" state.
+ */
+// @XmlEnumValue("block")
+ Block("block"),
+ /**
+ * This action tells the server to place the subscription in the "pending"
+ * state, and await input from the presentity to determine how to proceed.
+ */
+// @XmlEnumValue("confirm")
+ Confirm("confirm"),
+ /**
+ * This action tells the server to place the subscription into the "active"
+ * state, and to produce a presence document that indicates that the
+ * presentity is unavailable.
+ */
+// @XmlEnumValue("polite-block")
+ PoliteBlock("polite-block"),
+ /**
+ * This action tells the server to place the subscription into the "active"
+ * state.
+ */
+// @XmlEnumValue("allow")
+ Allow("allow");
+
+ /**
+ * Current enum value.
+ */
+ private final String value;
+
+ /**
+ * Creates enum whith the specified value.
+ *
+ * @param value the value to set.
+ */
+ SubHandlingType(String value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value.
+ *
+ * @return the value
+ */
+ public String value()
+ {
+ return value;
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/UnknownBooleanPermission.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/UnknownBooleanPermission.java
new file mode 100644
index 0000000..543f75c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/UnknownBooleanPermission.java
@@ -0,0 +1,100 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.presrules;
+
+/**
+ * Indicates that the unknown presence attribute with the given name and
+ * namespace should be included in the document.
+ * <p/>
+ * Compliant with rfc5025
+ *
+ * @author Grigorii Balutsel
+ */
+//@XmlAccessorType(XmlAccessType.FIELD)
+//@XmlType(name = "unknownBooleanPermission", propOrder = {
+// "value"
+// })
+public class UnknownBooleanPermission
+{
+ /**
+ * The value.
+ */
+// @XmlValue
+ protected boolean value;
+
+ /**
+ * Presence name.
+ */
+// @XmlAttribute(required = true)
+ protected String name;
+
+ /**
+ * Namespace URI.
+ */
+// @XmlAttribute(required = true)
+ protected String ns;
+
+ /**
+ * Gets the value of the value property.
+ */
+ public boolean isValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ */
+ public void setValue(boolean value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setName(String value)
+ {
+ this.name = value;
+ }
+
+ /**
+ * Gets the value of the ns property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getNs()
+ {
+ return ns;
+ }
+
+ /**
+ * Sets the value of the ns property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setNs(String value)
+ {
+ this.ns = value;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/pres-rules.xsd b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/pres-rules.xsd
new file mode 100644
index 0000000..84ab3c0
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/presrules/pres-rules.xsd
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="urn:ietf:params:xml:ns:pres-rules"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:cr="urn:ietf:params:xml:ns:common-policy"
+ xmlns:pr="urn:ietf:params:xml:ns:pres-rules"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+ <xs:import namespace="urn:ietf:params:xml:ns:common-policy"/>
+ <xs:simpleType name="booleanPermission">
+ <xs:restriction base="xs:boolean"/>
+ </xs:simpleType>
+ <xs:element name="service-uri-scheme" type="xs:token"/>
+ <xs:element name="class" type="xs:token"/>
+
+ <xs:element name="occurrence-id" type="xs:token"/>
+ <xs:element name="service-uri" type="xs:anyURI"/>
+ <xs:complexType name="provideServicePermission">
+ <xs:choice>
+ <xs:element name="all-services">
+ <xs:complexType/>
+ </xs:element>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element ref="pr:service-uri"/>
+ <xs:element ref="pr:service-uri-scheme"/>
+ <xs:element ref="pr:occurrence-id"/>
+ <xs:element ref="pr:class"/>
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:choice>
+ </xs:complexType>
+ <xs:element name="provide-services"
+ type="pr:provideServicePermission"/>
+ <xs:element name="deviceID" type="xs:anyURI"/>
+ <xs:complexType name="provideDevicePermission">
+ <xs:choice>
+ <xs:element name="all-devices">
+ <xs:complexType/>
+ </xs:element>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element ref="pr:deviceID"/>
+ <xs:element ref="pr:occurrence-id"/>
+ <xs:element ref="pr:class"/>
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:choice>
+ </xs:complexType>
+ <xs:element name="provide-devices"
+ type="pr:provideDevicePermission"/>
+ <xs:complexType name="providePersonPermission">
+ <xs:choice>
+ <xs:element name="all-persons">
+ <xs:complexType/>
+ </xs:element>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element ref="pr:occurrence-id"/>
+ <xs:element ref="pr:class"/>
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:choice>
+ </xs:complexType>
+ <xs:element name="provide-persons"
+ type="pr:providePersonPermission"/>
+ <xs:element name="provide-activities"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-class"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-deviceID"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-mood"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-place-is"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-place-type"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-privacy"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-relationship"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-status-icon"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-sphere"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-time-offset"
+ type="pr:booleanPermission"/>
+ <xs:element name="provide-user-input">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="false"/>
+ <xs:enumeration value="bare"/>
+ <xs:enumeration value="thresholds"/>
+ <xs:enumeration value="full"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="provide-note" type="pr:booleanPermission"/>
+ <xs:element name="sub-handling">
+ <xs:simpleType>
+ <xs:restriction base="xs:token">
+ <xs:enumeration value="block"/>
+ <xs:enumeration value="confirm"/>
+ <xs:enumeration value="polite-block"/>
+ <xs:enumeration value="allow"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:complexType name="unknownBooleanPermission">
+ <xs:simpleContent>
+ <xs:extension base="pr:booleanPermission">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="ns" type="xs:string" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:element name="provide-unknown-attribute"
+ type="pr:unknownBooleanPermission"/>
+ <xs:element name="provide-all-attributes">
+ <xs:complexType/>
+ </xs:element>
+</xs:schema>
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/DisplayNameType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/DisplayNameType.java
new file mode 100644
index 0000000..4a7cc12
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/DisplayNameType.java
@@ -0,0 +1,86 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists;
+
+/**
+ * The XCAP display-name element.
+ * <p/>
+ * Compliant with rfc4825, rfc4826
+ *
+ * @author Grigorii Balutsel
+ */
+public class DisplayNameType
+{
+ /**
+ * The element value.
+ */
+ private String value;
+
+ /**
+ * The lang attribute.
+ */
+ private String lang;
+
+ /**
+ * Creates display-name.
+ */
+ public DisplayNameType()
+ {
+ }
+
+ /**
+ * Creates display-name with value and lang properties.
+ *
+ * @param value the value property.
+ * @param lang the lang property.
+ */
+ public DisplayNameType(String value, String lang)
+ {
+ this.value = value;
+ this.lang = lang;
+ }
+
+ /**
+ * Gets the value of the value property.
+ *
+ * @return the value property.
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the value of the value property.
+ *
+ * @param value the value to set.
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Gets the value of the lang property.
+ *
+ * @return the lang property.
+ */
+ public String getLang()
+ {
+ return lang;
+ }
+
+ /**
+ * Sets the value of the lang property.
+ *
+ * @param lang the lang to set.
+ */
+ public void setLang(String lang)
+ {
+ this.lang = lang;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryRefType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryRefType.java
new file mode 100644
index 0000000..b33be81
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryRefType.java
@@ -0,0 +1,129 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists;
+
+import java.util.*;
+import javax.xml.namespace.*;
+
+import org.w3c.dom.*;
+
+/**
+ * The XCAP entry-ref element.
+ * <p/>
+ * Compliant with rfc4825, rfc4826
+ *
+ * @author Grigorii Balutsel
+ */
+public class EntryRefType
+{
+ /**
+ * The ref attribute.
+ */
+ private String ref;
+
+ /**
+ * The display-name element.
+ */
+ private DisplayNameType displayName;
+
+ /**
+ * The list of any elements.
+ */
+ private List<Element> any;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Creates the entry-ref element
+ */
+ EntryRefType()
+ {
+ }
+
+ /**
+ * Creates the entry-ref element with the ref attribute.
+ *
+ * @param ref the ref attribute.
+ * @throws IllegalArgumentException if ref attribute is null or empty.
+ */
+ public EntryRefType(String ref)
+ {
+ if (ref == null || ref.trim().length() == 0)
+ {
+ throw new IllegalArgumentException("The ref attribute cannot be " +
+ "null or empry");
+ }
+ this.ref = ref;
+ }
+
+ /**
+ * Gets the value of the ref property.
+ *
+ * @return the ref property.
+ */
+ public String getRef()
+ {
+ return ref;
+ }
+
+ /**
+ * Sets the value of the ref property.
+ *
+ * @param ref the ref to set.
+ */
+ public void setRef(String ref)
+ {
+ this.ref = ref;
+ }
+
+ /**
+ * Gets the value of the displayName property.
+ *
+ * @return the displayName property.
+ */
+ public DisplayNameType getDisplayName()
+ {
+ return displayName;
+ }
+
+ /**
+ * Sets the value of the displayName property.
+ *
+ * @param displayName the displayName to set.
+ */
+ public void setDisplayName(DisplayNameType displayName)
+ {
+ this.displayName = displayName;
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return the any property.
+ */
+ public List<Element> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryType.java
new file mode 100644
index 0000000..75318a8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/EntryType.java
@@ -0,0 +1,149 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists;
+
+import java.util.*;
+import javax.xml.namespace.*;
+
+import org.w3c.dom.*;
+
+/**
+ * The XCAP entry element.
+ * <p/>
+ * Compliant with rfc4825, rfc4826
+ *
+ * @author Grigorii Balutsel
+ */
+public class EntryType
+{
+ /**
+ * The uri attribute.
+ */
+ private String uri;
+
+ /**
+ * The display-name element.
+ */
+ private DisplayNameType displayName;
+
+ /**
+ * The list of any elements.
+ */
+ private List<Element> any;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Create the entry element.
+ */
+ EntryType()
+ {
+ }
+
+ /**
+ * Create the entry element with the uri attribute.
+ *
+ * @param uri the uri attribute.
+ * @throws IllegalArgumentException if uri attribute is null or empty.
+ */
+ public EntryType(String uri)
+ {
+ if (uri == null || uri.trim().length() == 0)
+ {
+ throw new IllegalArgumentException("The uri attribute cannot be " +
+ "null or empry");
+ }
+ this.uri = uri;
+ }
+
+ /**
+ * Gets the value of the uri property.
+ *
+ * @return the uri property.
+ */
+ public String getUri()
+ {
+ return uri;
+ }
+
+ /**
+ * Sets the value of the uri property.
+ *
+ * @param uri the uri to set.
+ */
+ public void setUri(String uri)
+ {
+ this.uri = uri;
+ }
+
+ /**
+ * Gets the value of the displayName property.
+ *
+ * @return the displayName property.
+ */
+ public DisplayNameType getDisplayName()
+ {
+ return displayName;
+ }
+
+ /**
+ * Sets the value of the displayName property.
+ *
+ * @param displayName the displayName to set.
+ */
+ public void setDisplayName(DisplayNameType displayName)
+ {
+ this.displayName = displayName;
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return the any property.
+ */
+ public List<Element> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+
+ /**
+ * Sets the value of the any property.
+ *
+ * @param any the any to set.
+ */
+ public void setAny(List<Element> any)
+ {
+ this.any = any;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+
+ /**
+ * Sets the value of the anyAttributes property.
+ *
+ * @param anyAttributes the anyAttributes to set.
+ */
+ public void setAnyAttributes(Map<QName, String> anyAttributes)
+ {
+ this.anyAttributes = anyAttributes;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ExternalType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ExternalType.java
new file mode 100644
index 0000000..1bd72e6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ExternalType.java
@@ -0,0 +1,106 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists;
+
+import java.util.*;
+import javax.xml.namespace.*;
+
+import org.w3c.dom.*;
+
+/**
+ * The XCAP external element.
+ * <p/>
+ * Compliant with rfc4825, rfc4826
+ *
+ * @author Grigorii Balutsel
+ */
+public class ExternalType
+{
+ /**
+ * The danchor attribute.
+ */
+ protected String anchor;
+
+ /**
+ * The display-name element.
+ */
+ private DisplayNameType displayName;
+
+ /**
+ * The list of any elements.
+ */
+ private List<Element> any;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Gets the value of the anchor property.
+ *
+ * @return the anchor property.
+ */
+ public String getAnchor()
+ {
+ return anchor;
+ }
+
+ /**
+ * Sets the value of the anchor property.
+ *
+ * @param anchor the anchor to set.
+ */
+ public void setAnchor(String anchor)
+ {
+ this.anchor = anchor;
+ }
+
+ /**
+ * Gets the value of the displayName property.
+ *
+ * @return the displayName property.
+ */
+ public DisplayNameType getDisplayName()
+ {
+ return displayName;
+ }
+
+ /**
+ * Sets the value of the displayName property.
+ *
+ * @param displayName the displayName to set.
+ */
+ public void setDisplayName(DisplayNameType displayName)
+ {
+ this.displayName = displayName;
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return the any property.
+ */
+ public List<Element> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ListType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ListType.java
new file mode 100644
index 0000000..3caa9ab
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ListType.java
@@ -0,0 +1,202 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists;
+
+import org.w3c.dom.*;
+
+import javax.xml.namespace.*;
+import java.util.*;
+
+/**
+ * The XCAP list element.
+ * <p/>
+ * Compliant with rfc4825, rfc4826
+ *
+ * @author Grigorii Balutsel
+ */
+public class ListType
+{
+ /**
+ * The name attribute.
+ */
+ protected String name;
+
+ /**
+ * The display-name element.
+ */
+ protected DisplayNameType displayName;
+
+ /**
+ * The list of entry elements.
+ */
+ protected List<EntryType> entries;
+
+ /**
+ * The list of external elements.
+ */
+ protected List<ExternalType> externals;
+
+ /**
+ * The list of list elements.
+ */
+ protected List<ListType> lists;
+
+ /**
+ * The list of entry-ref elements.
+ */
+ protected List<EntryRefType> entryRefs;
+
+ /**
+ * The list of any elements.
+ */
+ private List<Element> any;
+
+ /**
+ * The map of any attributes.
+ */
+ private Map<QName, String> anyAttributes = new HashMap<QName, String>();
+
+ /**
+ * Gets the value of the displayName property.
+ *
+ * @return the displayName property.
+ */
+ public DisplayNameType getDisplayName()
+ {
+ return displayName;
+ }
+
+ /**
+ * Sets the value of the displayName property.
+ *
+ * @param displayName the displayName to set.
+ */
+ public void setDisplayName(DisplayNameType displayName)
+ {
+ this.displayName = displayName;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return the name property.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param name the name to set.
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Gets the value of the entries property.
+ *
+ * @return the entries property.
+ */
+ public List<EntryType> getEntries()
+ {
+ if (entries == null)
+ {
+ entries = new ArrayList<EntryType>();
+ }
+ return entries;
+ }
+
+ /**
+ * Gets the value of the externals property.
+ *
+ * @return the externals property.
+ */
+ public List<ExternalType> getExternals()
+ {
+ if (externals == null)
+ {
+ externals = new ArrayList<ExternalType>();
+ }
+ return externals;
+ }
+
+ /**
+ * Gets the value of the lists property.
+ *
+ * @return the lists property.
+ */
+ public List<ListType> getLists()
+ {
+ if (lists == null)
+ {
+ lists = new ArrayList<ListType>();
+ }
+ return lists;
+ }
+
+ /**
+ * Gets the value of the entryRefs property.
+ *
+ * @return the entryRefs property.
+ */
+ public List<EntryRefType> getEntryRefs()
+ {
+ if (entryRefs == null)
+ {
+ entryRefs = new ArrayList<EntryRefType>();
+ }
+ return entryRefs;
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return the any property.
+ */
+ public List<Element> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+
+ /**
+ * Sets the value of the any property.
+ *
+ * @param any the any to set.
+ */
+ public void setAny(List<Element> any)
+ {
+ this.any = any;
+ }
+
+ /**
+ * Gets the value of the anyAttributes property.
+ *
+ * @return the anyAttributes property.
+ */
+ public Map<QName, String> getAnyAttributes()
+ {
+ return anyAttributes;
+ }
+
+ /**
+ * Sets the value of the anyAttributes property.
+ *
+ * @param anyAttributes the anyAttributes to set.
+ */
+ public void setAnyAttributes(Map<QName, String> anyAttributes)
+ {
+ this.anyAttributes = anyAttributes;
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsParser.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsParser.java
new file mode 100644
index 0000000..6e5ca3e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsParser.java
@@ -0,0 +1,716 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.*;
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.StringUtils.*;
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.XmlUtils.*;
+import org.w3c.dom.*;
+
+import static javax.xml.XMLConstants.*;
+import javax.xml.namespace.*;
+
+/**
+ * Utility class that helps to converts resource-lists xml to the object model
+ * and object model to the resource-lists xml.
+ *
+ * @author Grigorii Balutsel
+ */
+public final class ResourceListsParser
+{
+ private static String NAMESPACE = "urn:ietf:params:xml:ns:resource-lists";
+
+ private static String RESOURCE_LISTS_ELEMENT = "resource-lists";
+
+ private static String LIST_ELEMENT = "list";
+
+ private static String LIST_NAME_ATTR = "name";
+
+ private static String ENTRY_ELEMENT = "entry";
+
+ private static String ENTRY_URI_ATTR = "uri";
+
+ private static String ENTRYREF_ELEMENT = "entry-ref";
+
+ private static String ENTRYREF_REF_ATTR = "ref";
+
+ private static String EXTERNAL_ELEMENT = "external";
+
+ private static String EXTERNAL_ANCHOR_ATTR = "anchor";
+
+ private static String DISPALY_NAME_ELEMENT = "display-name";
+
+ private static String DISPALY_NAME_LANG_ATTR = "lang";
+
+ private ResourceListsParser()
+ {
+ }
+
+ /**
+ * Creates resource-lists object from the element.
+ *
+ * @param xml the XML to analyze.
+ * @return the resource-lists object.
+ * @throws ParsingException if there is some error during parsing.
+ */
+ public static ResourceListsType fromXml(String xml)
+ throws ParsingException
+ {
+ if (isNullOrEmpty(xml))
+ {
+ throw new IllegalArgumentException("XML cannot be null or empty");
+ }
+ try
+ {
+ ResourceListsType resourceLists = new ResourceListsType();
+ Document document = createDocument(xml);
+ Element resourceListsElement = document.getDocumentElement();
+ String localName = resourceListsElement.getLocalName();
+ if (RESOURCE_LISTS_ELEMENT.equals(localName) &&
+ !NAMESPACE.equals(resourceListsElement.getNamespaceURI()))
+ {
+ throw new Exception("Document doesn't contain resource-lists " +
+ "element");
+ }
+ // Process attributes
+ NamedNodeMap attributes = resourceListsElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("resource-lists element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ throw new Exception("resource-lists element is invalid");
+ }
+ // Process elements
+ NodeList childNodes = resourceListsElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element listElement = (Element) node;
+ resourceLists.getList().add(listFromElement(listElement));
+ }
+ return resourceLists;
+ }
+ catch (Exception ex)
+ {
+ throw new ParsingException(ex);
+ }
+ }
+
+ /**
+ * Creates XML from the resource-lists element.
+ *
+ * @param resourceLists the resource-lists to analyze.
+ * @return the resource-lists xml.
+ * @throws ParsingException if there is some error during parsing.
+ */
+ public static String toXml(ResourceListsType resourceLists)
+ throws ParsingException
+ {
+ if (resourceLists == null)
+ {
+ throw new IllegalArgumentException("resource-lists cannot be null");
+ }
+ try
+ {
+ Document document = createDocument();
+ Element resourceListsElement =
+ document.createElementNS(NAMESPACE, RESOURCE_LISTS_ELEMENT);
+ for (ListType list : resourceLists.getList())
+ {
+ resourceListsElement
+ .appendChild(elementFromList(document, list));
+ }
+ document.appendChild(resourceListsElement);
+ return createXml(document);
+ }
+ catch (Exception ex)
+ {
+ throw new ParsingException(ex);
+ }
+ }
+
+ /**
+ * Creates list object from the element.
+ *
+ * @param listElement the element to analyze.
+ * @return the list object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static ListType listFromElement(Element listElement)
+ throws Exception
+ {
+ ListType list = new ListType();
+ if (!LIST_ELEMENT.equals(listElement.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(listElement)))
+ {
+ throw new Exception("list element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = listElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("list element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ if (LIST_NAME_ATTR.equals(attribute.getLocalName()))
+ {
+ list.setName(attribute.getValue());
+ continue;
+ }
+ else
+ {
+ throw new Exception("list element is invalid");
+ }
+ }
+ QName qName = new QName(namespaceUri,
+ attribute.getLocalName(),
+ attribute.getPrefix() == null ? "" : attribute.getPrefix());
+ list.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ // Process elements
+ NodeList childNodes = listElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String localName = element.getLocalName();
+ String namespaceUri = getNamespaceUri(element);
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ // display-name
+ if (DISPALY_NAME_ELEMENT.equals(localName))
+ {
+ list.setDisplayName(displayNameFromElement(element));
+ }
+ // entry
+ else if (ENTRY_ELEMENT.equals(localName))
+ {
+ list.getEntries().add(entryFromElement(element));
+ }
+ // entry-ref
+ else if (ENTRYREF_ELEMENT.equals(localName))
+ {
+ list.getEntryRefs().add(entryRefFromElement(element));
+ }
+ // list
+ else if (LIST_ELEMENT.equals(localName))
+ {
+ list.getLists().add(listFromElement(element));
+ }
+ // extenal
+ else if (EXTERNAL_ELEMENT.equals(localName))
+ {
+ list.getExternals().add(externalFromElement(element));
+ }
+ else
+ {
+ throw new Exception("list element is invalid");
+ }
+ }
+ else
+ {
+ // any
+ list.getAny().add(element);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Creates list element from the object.
+ *
+ * @param document the xml document.
+ * @param list the list to analyze.
+ * @return the list element.
+ * @throws Exception if there is some error during creating.
+ */
+ private static Element elementFromList(Document document, ListType list)
+ throws Exception
+ {
+ Element listElement = document.createElementNS(NAMESPACE, LIST_ELEMENT);
+ if (list.getName() != null)
+ {
+ listElement.setAttribute(LIST_NAME_ATTR, list.getName());
+ }
+ // display-name
+ if (list.getDisplayName() != null)
+ {
+ listElement.appendChild(elementFromDisplayName(document,
+ list.getDisplayName()));
+ }
+ // entry
+ for (EntryType entry : list.getEntries())
+ {
+ listElement.appendChild(elementFromEntry(document, entry));
+ }
+ // entry-ref
+ for (EntryRefType entryRef : list.getEntryRefs())
+ {
+ listElement.appendChild(elementFromEntryRef(document, entryRef));
+ }
+ // list
+ for (ListType subList : list.getLists())
+ {
+ listElement.appendChild(elementFromList(document, subList));
+ }
+ // external
+ for (ExternalType external : list.getExternals())
+ {
+ listElement.appendChild(elementFromExternal(document, external));
+ }
+ processAnyAttributes(listElement, list.getAnyAttributes());
+ processAny(listElement, list.getAny());
+ return listElement;
+ }
+
+ /**
+ * Creates entry element from the object.
+ *
+ * @param document the xml document.
+ * @param entry the entry to analyze.
+ * @return the entry element.
+ * @throws Exception if there is some error during creating.
+ */
+ private static Element elementFromEntry(Document document, EntryType entry)
+ throws Exception
+ {
+ Element entryElement = document.createElementNS(NAMESPACE,
+ ENTRY_ELEMENT);
+ if (isNullOrEmpty(entry.getUri()))
+ {
+ throw new Exception("entry uri attribute is missed");
+ }
+ entryElement.setAttribute(ENTRY_URI_ATTR, entry.getUri());
+ if (entry.getDisplayName() != null)
+ {
+ entryElement.appendChild(elementFromDisplayName(document,
+ entry.getDisplayName()));
+ }
+ processAnyAttributes(entryElement, entry.getAnyAttributes());
+ processAny(entryElement, entry.getAny());
+ return entryElement;
+ }
+
+ /**
+ * Creates entryRef element from the object.
+ *
+ * @param document the xml document.
+ * @param entryRef the entry to analyze.
+ * @return the entryRef element.
+ * @throws Exception if there is some error during creating.
+ */
+ private static Element elementFromEntryRef(
+ Document document,
+ EntryRefType entryRef)
+ throws Exception
+ {
+ Element entryRefElement = document.createElementNS(NAMESPACE,
+ ENTRYREF_ELEMENT);
+ if (isNullOrEmpty(entryRef.getRef()))
+ {
+ throw new Exception("entry-ref ref attribute is missed");
+ }
+ entryRefElement.setAttribute(ENTRYREF_REF_ATTR, entryRef.getRef());
+ if (entryRef.getDisplayName() != null)
+ {
+ entryRefElement.appendChild(elementFromDisplayName(document,
+ entryRef.getDisplayName()));
+ }
+ processAnyAttributes(entryRefElement, entryRef.getAnyAttributes());
+ processAny(entryRefElement, entryRef.getAny());
+ return entryRefElement;
+ }
+
+ /**
+ * Creates external element from the object.
+ *
+ * @param document the xml document.
+ * @param external the entry to analyze.
+ * @return the external element.
+ * @throws Exception if there is some error during creating.
+ */
+ private static Element elementFromExternal(
+ Document document,
+ ExternalType external)
+ throws Exception
+ {
+ Element externalElement = document.createElementNS(NAMESPACE,
+ EXTERNAL_ELEMENT);
+ if (!isNullOrEmpty(external.getAnchor()))
+ {
+ externalElement.setAttribute(EXTERNAL_ANCHOR_ATTR,
+ external.getAnchor());
+ }
+ if (external.getDisplayName() != null)
+ {
+ externalElement.appendChild(elementFromDisplayName(document,
+ external.getDisplayName()));
+ }
+ processAnyAttributes(externalElement, external.getAnyAttributes());
+ processAny(externalElement, external.getAny());
+ return externalElement;
+ }
+
+ /**
+ * Creates display-name element from the object.
+ *
+ * @param document the xml document.
+ * @param displayName the display-name to analyze.
+ * @return the external element.
+ * @throws Exception if there is some error during creating.
+ */
+ private static Element elementFromDisplayName(
+ Document document,
+ DisplayNameType displayName)
+ throws Exception
+ {
+ Element displayNameElement = document.createElementNS(NAMESPACE,
+ DISPALY_NAME_ELEMENT);
+ if (displayName.getLang() != null)
+ {
+ displayNameElement.setAttribute(
+ XML_NS_PREFIX + ":" + DISPALY_NAME_LANG_ATTR,
+ displayName.getLang());
+ }
+ if (displayName.getValue() != null)
+ {
+ displayNameElement.setTextContent(displayName.getValue());
+ }
+ return displayNameElement;
+ }
+
+ /**
+ * Creates entry object from the element.
+ *
+ * @param entryElement the element to analyze.
+ * @return the entry object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static EntryType entryFromElement(Element entryElement)
+ throws Exception
+ {
+ EntryType entry = new EntryType();
+ if (!ENTRY_ELEMENT.equals(entryElement.getNodeName()) ||
+ !NAMESPACE.equals(getNamespaceUri(entryElement)))
+ {
+ throw new Exception("entry element is invalid");
+ }
+ String uri = null;
+ // Process attributes
+ NamedNodeMap attributes = entryElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("entry element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ if (ENTRY_URI_ATTR.equals(attribute.getLocalName()))
+ {
+ uri = attribute.getValue();
+ continue;
+ }
+ else
+ {
+ throw new Exception("entry element is invalid");
+ }
+ }
+ QName qName = new QName(namespaceUri,
+ attribute.getLocalName(),
+ attribute.getPrefix() == null ? "" : attribute.getPrefix());
+ entry.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ if (uri == null)
+ {
+ throw new Exception("entry uri attribute is missed");
+ }
+ entry.setUri(uri);
+ // Process elements
+ NodeList childNodes = entryElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("entry element is invalid");
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ // display-name
+ if (DISPALY_NAME_ELEMENT.equals(element.getLocalName()))
+ {
+ entry.setDisplayName(displayNameFromElement(element));
+ continue;
+ }
+ else
+ {
+ throw new Exception("entry element is invalid");
+ }
+ }
+ // any
+ entry.getAny().add(element);
+ }
+ return entry;
+ }
+
+ /**
+ * Creates entry-ref object from the element.
+ *
+ * @param entryRefElement the element to analyze.
+ * @return the entry-ref object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static EntryRefType entryRefFromElement(Element entryRefElement)
+ throws Exception
+ {
+ EntryRefType entryRef = new EntryRefType();
+ if (!ENTRYREF_ELEMENT.equals(entryRefElement.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(entryRefElement)))
+ {
+ throw new Exception("entry-ref element is invalid");
+ }
+ String ref = null;
+ // Process attributes
+ NamedNodeMap attributes = entryRefElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("entry-ref element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ if (ENTRYREF_REF_ATTR.equals(attribute.getLocalName()))
+ {
+ ref = attribute.getValue();
+ continue;
+ }
+ else
+ {
+ throw new Exception("entry-ref element is invalid");
+ }
+ }
+ QName qName = new QName(attribute.getNamespaceURI(),
+ attribute.getName(),
+ attribute.getPrefix() == null ? "" : attribute.getPrefix());
+ entryRef.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ if (ref == null)
+ {
+ throw new Exception("entry-ref ref attribute is missed");
+ }
+ entryRef.setRef(ref);
+ // Process elements
+ NodeList childNodes = entryRefElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("entry-ref element is invalid");
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ // display-name
+ if (DISPALY_NAME_ELEMENT.equals(element.getLocalName()))
+ {
+ entryRef.setDisplayName(displayNameFromElement(element));
+ continue;
+ }
+ else
+ {
+ throw new Exception("entry-ref element is invalid");
+ }
+ }
+ // any
+ entryRef.getAny().add(element);
+ }
+ return entryRef;
+ }
+
+ /**
+ * Creates external object from the element.
+ *
+ * @param entryElement the element to analyze.
+ * @return the external object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static ExternalType externalFromElement(Element entryElement)
+ throws Exception
+ {
+ ExternalType external = new ExternalType();
+ if (!EXTERNAL_ELEMENT.equals(entryElement.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(entryElement)))
+ {
+ throw new Exception("external element is invalid");
+ }
+
+ // Process attributes
+ NamedNodeMap attributes = entryElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("external element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ if (EXTERNAL_ANCHOR_ATTR.equals(attribute.getLocalName()))
+ {
+ external.setAnchor(attribute.getValue());
+ continue;
+ }
+ else
+ {
+ throw new Exception("external element is invalid");
+ }
+ }
+ QName qName = new QName(attribute.getNamespaceURI(),
+ attribute.getName(),
+ attribute.getPrefix() == null ? "" : attribute.getPrefix());
+ external.getAnyAttributes().put(qName, attribute.getValue());
+ }
+ // Process elements
+ NodeList childNodes = entryElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("external element is invalid");
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ // display-name
+ if (DISPALY_NAME_ELEMENT.equals(element.getLocalName()))
+ {
+ external.setDisplayName(displayNameFromElement(element));
+ continue;
+ }
+ else
+ {
+ throw new Exception("external element is invalid");
+ }
+ }
+ // any
+ external.getAny().add(element);
+ }
+ return external;
+ }
+
+ /**
+ * Creates display-name object from the element.
+ *
+ * @param displayNameElement the element to analyze.
+ * @return the display-name object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static DisplayNameType displayNameFromElement(
+ Element displayNameElement) throws Exception
+ {
+ DisplayNameType displayName = new DisplayNameType();
+ if (!DISPALY_NAME_ELEMENT.equals(displayNameElement.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(displayNameElement)))
+ {
+ throw new Exception("display-name element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = displayNameElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("display-name element is invalid");
+ }
+ if (DISPALY_NAME_LANG_ATTR.equals(attribute.getLocalName()) &&
+ XML_NS_URI.equals(namespaceUri))
+ {
+ displayName.setLang(attribute.getValue());
+ }
+ else if (!isStandartXmlNamespace(namespaceUri))
+ {
+ throw new Exception("display-name element is invalid");
+ }
+ }
+ // Process elements
+ NodeList childNodes = displayNameElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ throw new Exception("display-name element is invalid");
+ }
+ }
+ displayName.setValue(displayNameElement.getTextContent());
+ return displayName;
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsType.java
new file mode 100644
index 0000000..fb37854
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/ResourceListsType.java
@@ -0,0 +1,38 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists;
+
+import java.util.*;
+
+/**
+ * The XCAP resource-lists element.
+ * <p/>
+ * Compliant with rfc4825, rfc4826
+ *
+ * @author Grigorii Balutsel
+ */
+public class ResourceListsType
+{
+ /**
+ * The list of the list elements.
+ */
+ private List<ListType> list;
+
+ /**
+ * Gets the value of the list property.
+ *
+ * @return the list property.
+ */
+ public List<ListType> getList()
+ {
+ if (list == null)
+ {
+ list = new ArrayList<ListType>();
+ }
+ return this.list;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/resource-lists.xsd b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/resource-lists.xsd
new file mode 100644
index 0000000..064918c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/resourcelists/resource-lists.xsd
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="urn:ietf:params:xml:ns:resource-lists"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns="urn:ietf:params:xml:ns:resource-lists"
+ elementFormDefault="qualified" attributeFormDefault="unqualified">
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+ <xs:complexType name="listType">
+ <xs:sequence>
+ <xs:element name="display-name" type="display-nameType"
+ minOccurs="0"/>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:choice>
+ <xs:element name="list">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:extension base="listType"/>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="external" type="externalType"/>
+ <xs:element name="entry" type="entryType"/>
+ <xs:element name="entry-ref" type="entry-refType"/>
+ </xs:choice>
+ </xs:sequence>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="optional"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:complexType name="entryType">
+ <xs:sequence>
+ <xs:element name="display-name" minOccurs="0">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="display-nameType"/>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="uri" type="xs:anyURI" use="required"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:complexType name="entry-refType">
+ <xs:sequence>
+ <xs:element name="display-name" type="display-nameType"
+ minOccurs="0"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="ref" type="xs:anyURI" use="required"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:complexType name="externalType">
+ <xs:sequence>
+ <xs:element name="display-name" type="display-nameType"
+ minOccurs="0"/>
+ <xs:any namespace="##other" processContents="lax" minOccurs="0"
+ maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="anchor" type="xs:anyURI"/>
+ <xs:anyAttribute namespace="##other" processContents="lax"/>
+ </xs:complexType>
+ <xs:element name="resource-lists">
+ <xs:complexType>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="list" type="listType"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="display-nameType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute ref="xml:lang"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+</xs:schema>
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/AuidsType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/AuidsType.java
new file mode 100644
index 0000000..237118e
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/AuidsType.java
@@ -0,0 +1,38 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps;
+
+import java.util.*;
+
+/**
+ * The XCAP-CAPS auids element.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class AuidsType
+{
+ /**
+ * The list of the auid elements.
+ */
+ private List<String> auid;
+
+ /**
+ * Gets the value of the auid property.
+ *
+ * @return the auid property.
+ */
+ public List<String> getAuid()
+ {
+ if (auid == null)
+ {
+ auid = new ArrayList<String>();
+ }
+ return this.auid;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/ExtensionsType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/ExtensionsType.java
new file mode 100644
index 0000000..78238c2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/ExtensionsType.java
@@ -0,0 +1,38 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps;
+
+import java.util.*;
+
+/**
+ * The XCAP-CAPS extensions element.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class ExtensionsType
+{
+ /**
+ * The list of the extension elements.
+ */
+ private List<String> extension;
+
+ /**
+ * Gets the value of the extension property.
+ *
+ * @return the extension property.
+ */
+ public List<String> getExtension()
+ {
+ if (extension == null)
+ {
+ extension = new ArrayList<String>();
+ }
+ return this.extension;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/NamespacesType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/NamespacesType.java
new file mode 100644
index 0000000..2791460
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/NamespacesType.java
@@ -0,0 +1,38 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps;
+
+import java.util.*;
+
+/**
+ * The XCAP-CAPS namespaces element.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class NamespacesType
+{
+ /**
+ * The list of the namespace elements.
+ */
+ protected List<String> namespace;
+
+ /**
+ * Gets the value of the auid property.
+ *
+ * @return the namespace property.
+ */
+ public List<String> getNamespace()
+ {
+ if (namespace == null)
+ {
+ namespace = new ArrayList<String>();
+ }
+ return this.namespace;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsParser.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsParser.java
new file mode 100644
index 0000000..c8e3439
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsParser.java
@@ -0,0 +1,324 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps;
+
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.StringUtils.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.*;
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.XmlUtils.*;
+import org.w3c.dom.*;
+
+/**
+ * Utility class that helps to converts xcap-caps xml to the object model and
+ * object model to the xcap-caps xml.
+ *
+ * @author Grigorii Balutsel
+ */
+public final class XCapCapsParser
+{
+ private static final String NAMESPACE = "urn:ietf:params:xml:ns:xcap-caps";
+
+ private static String XCAPCAPS_ELEMENT = "xcap-caps";
+
+ private static String AUIDS_ELEMENT = "auids";
+
+ private static String AUID_ELEMENT = "auid";
+
+ private static String NAMESPACES_ELEMENT = "namespaces";
+
+ private static String NAMESPACE_ELEMENT = "namespace";
+
+ private static String EXTENSIONS_ELEMENT = "extensions";
+
+ private static String EXTENSION_ELEMENT = "extension";
+
+ /**
+ * Creates xcap-caps object from the element.
+ *
+ * @param xml the XML to analyze.
+ * @return the xcap-caps object.
+ * @throws ParsingException if there is some error during parsing.
+ */
+ public static XCapCapsType fromXml(String xml)
+ throws ParsingException
+ {
+ if (isNullOrEmpty(xml))
+ {
+ throw new IllegalArgumentException("XML cannot be null or empty");
+ }
+ try
+ {
+ XCapCapsType xCapCaps = new XCapCapsType();
+ Document document = XmlUtils.createDocument(xml);
+ Element xCapCapsElement = document.getDocumentElement();
+ if (XCAPCAPS_ELEMENT.equals(xCapCapsElement.getLocalName()) &&
+ !NAMESPACE.equals(xCapCapsElement.getNamespaceURI()))
+ {
+ throw new Exception(
+ "Document doesn't contain xcap-caps element");
+ }
+ boolean auidsFound = false;
+ boolean namespacesFound = false;
+ // Process attributes
+ NamedNodeMap attributes = xCapCapsElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("xcap-caps element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ throw new Exception("xcap-caps element is invalid");
+ }
+ // Process elements
+ NodeList childNodes = xCapCapsElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("xcap-caps element is invalid");
+ }
+ String localName = node.getLocalName();
+
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ // auids
+ if (AUIDS_ELEMENT.equals(localName))
+ {
+ xCapCaps.setAuids(auidsFromElement(element));
+ auidsFound = true;
+ }
+ // namspaces
+ else if (NAMESPACES_ELEMENT.equals(localName))
+ {
+ xCapCaps.setNamespaces(namespacesFromElement(element));
+ namespacesFound = true;
+ }
+ // extensions
+ else if (EXTENSIONS_ELEMENT.equals(localName))
+ {
+ xCapCaps.setExtensions(extensionsFromElement(element));
+ }
+ else
+ {
+ throw new Exception("xcap-caps element is invalid");
+ }
+ }
+ else
+ {
+ // any
+ xCapCaps.getAny().add(element);
+ }
+ }
+ if (!auidsFound)
+ {
+ throw new ParsingException("xcap-caps auids element is missed");
+ }
+ if (!namespacesFound)
+ {
+ throw new ParsingException(
+ "xcap-caps namespaces element is missed");
+ }
+ return xCapCaps;
+ }
+ catch (Exception ex)
+ {
+ throw new ParsingException(ex);
+ }
+ }
+
+ /**
+ * Creates auids object from the element.
+ *
+ * @param auidsElement the element to analyze.
+ * @return the auids object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static AuidsType auidsFromElement(
+ Element auidsElement) throws Exception
+ {
+ AuidsType auidsType = new AuidsType();
+ if (!AUIDS_ELEMENT.equals(auidsElement.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(auidsElement)))
+ {
+ throw new Exception("auids element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = auidsElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("auids element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ throw new Exception("auids element is invalid");
+ }
+ // Process elements
+ NodeList childNodes = auidsElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("auids element is invalid");
+ }
+ if (NAMESPACE.equals(namespaceUri) &&
+ AUID_ELEMENT.equals(element.getLocalName()))
+ {
+ auidsType.getAuid().add(element.getTextContent());
+ }
+ else
+ {
+ throw new Exception("auids element is invalid");
+ }
+ }
+ return auidsType;
+ }
+
+ /**
+ * Creates namespaces object from the element.
+ *
+ * @param namespacesElement the element to analyze.
+ * @return the namespaces object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static NamespacesType namespacesFromElement(
+ Element namespacesElement) throws Exception
+ {
+ NamespacesType namespaces = new NamespacesType();
+ if (!NAMESPACES_ELEMENT.equals(namespacesElement.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(namespacesElement)))
+ {
+ throw new Exception("namespaces element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = namespacesElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("namespaces element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ throw new Exception("namespaces element is invalid");
+ }
+ // Process elements
+ NodeList childNodes = namespacesElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("namespaces element is invalid");
+ }
+ if (NAMESPACE.equals(namespaceUri) &&
+ NAMESPACE_ELEMENT.equals(element.getLocalName()))
+ {
+ namespaces.getNamespace().add(element.getTextContent());
+ }
+ else
+ {
+ throw new Exception("namespaces element is invalid");
+ }
+ }
+ return namespaces;
+ }
+
+ /**
+ * Creates extensions object from the element.
+ *
+ * @param extensionsElement the element to analyze.
+ * @return the namespaces object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static ExtensionsType extensionsFromElement(
+ Element extensionsElement) throws Exception
+ {
+ ExtensionsType extensions = new ExtensionsType();
+ if (!EXTENSIONS_ELEMENT.equals(extensionsElement.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(extensionsElement)))
+ {
+ throw new Exception("extensions element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = extensionsElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("extensions element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ throw new Exception("extensions element is invalid");
+ }
+ // Process elements
+ NodeList childNodes = extensionsElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (namespaceUri == null)
+ {
+ throw new Exception("extensions element is invalid");
+ }
+ if (NAMESPACE.equals(namespaceUri) &&
+ EXTENSION_ELEMENT.equals(element.getLocalName()))
+ {
+ extensions.getExtension().add(element.getTextContent());
+ }
+ else
+ {
+ throw new Exception("extensions element is invalid");
+ }
+ }
+ return extensions;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsType.java
new file mode 100644
index 0000000..f435ccd
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/XCapCapsType.java
@@ -0,0 +1,112 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps;
+
+import java.util.*;
+import org.w3c.dom.*;
+
+/**
+ * Contains the capabilities of an XCAP server.
+ *
+ * @author Grigorii Balutsel
+ */
+public class XCapCapsType
+{
+ /**
+ * The auids elemet.
+ */
+ protected AuidsType auids;
+
+ /**
+ * The extensions elemet.
+ */
+ protected ExtensionsType extensions;
+
+ /**
+ * The namespaces elemet.
+ */
+ protected NamespacesType namespaces;
+
+ /**
+ * The list of any elements.
+ */
+ protected List<Element> any;
+
+ /**
+ * Gets the value of the auids property.
+ *
+ * @return the auids property.
+ */
+ public AuidsType getAuids()
+ {
+ return auids;
+ }
+
+ /**
+ * Sets the value of the auids property.
+ *
+ * @param auids the auids to set.
+ */
+ public void setAuids(AuidsType auids)
+ {
+ this.auids = auids;
+ }
+
+ /**
+ * Gets the value of the extensions property.
+ *
+ * @return the extensions property.
+ */
+ public ExtensionsType getExtensions()
+ {
+ return extensions;
+ }
+
+ /**
+ * Sets the value of the extensions property.
+ *
+ * @param extensions the extensions to set.
+ */
+ public void setExtensions(ExtensionsType extensions)
+ {
+ this.extensions = extensions;
+ }
+
+ /**
+ * Gets the value of the namespaces property.
+ *
+ * @return the namespaces property.
+ */
+ public NamespacesType getNamespaces()
+ {
+ return namespaces;
+ }
+
+ /**
+ * Sets the value of the namespaces property.
+ *
+ * @param namespaces the namespaces to set.
+ */
+ public void setNamespaces(NamespacesType namespaces)
+ {
+ this.namespaces = namespaces;
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return the any property.
+ */
+ public List<Element> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/xcap-caps.xsd b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/xcap-caps.xsd
new file mode 100644
index 0000000..23515f7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcapcaps/xcap-caps.xsd
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="urn:ietf:params:xml:ns:xcap-caps"
+ xmlns="urn:ietf:params:xml:ns:xcap-caps"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+ <xs:element name="xcap-caps">
+ <xs:annotation>
+ <xs:documentation>Root element for xcap-caps</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="auids">
+ <xs:annotation>
+ <xs:documentation>List of supported AUID.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="auid" type="auidType"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="extensions" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>List of supported extensions.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="extension" type="extensionType"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="namespaces">
+ <xs:annotation>
+ <xs:documentation>List of supported namespaces.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="namespace" type="namespaceType"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:any namespace="##other" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:simpleType name="auidType">
+ <xs:annotation>
+ <xs:documentation>AUID Type</xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string"/>
+ </xs:simpleType>
+ <xs:simpleType name="extensionType">
+ <xs:annotation>
+ <xs:documentation>Extension Type</xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string"/>
+ </xs:simpleType>
+ <xs:simpleType name="namespaceType">
+ <xs:annotation>
+ <xs:documentation>Namespace type</xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:anyURI"/>
+ </xs:simpleType>
+</xs:schema>
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/BaseXCapError.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/BaseXCapError.java
new file mode 100644
index 0000000..06f38ea
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/BaseXCapError.java
@@ -0,0 +1,50 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The base XCAP error.
+ *
+ * @author Grigorii Balutsel
+ */
+public abstract class BaseXCapError implements XCapError
+{
+ /**
+ * The phrase attribute.
+ */
+ private String phrase;
+
+ /**
+ * Creates the XCAP error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public BaseXCapError(String phrase)
+ {
+ this.phrase = phrase;
+ }
+
+ /**
+ * Gets the phrase attribute.
+ *
+ * @return User readable error description.
+ */
+ public String getPhrase()
+ {
+ return phrase;
+ }
+
+ /**
+ * Sets the value of the phrase property.
+ *
+ * @param phrase the phrase to set.
+ */
+ void setPhrase(String phrase)
+ {
+ this.phrase = phrase;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotDeleteType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotDeleteType.java
new file mode 100644
index 0000000..a6817fa
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotDeleteType.java
@@ -0,0 +1,28 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP cannot-delete element. Indicates that the requested DELETE operation
+ * could not be performed because it would not be idempotent.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class CannotDeleteType extends BaseXCapError
+{
+ /**
+ * Creates the XCAP cannot-delete error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public CannotDeleteType(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotInsertType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotInsertType.java
new file mode 100644
index 0000000..7b85109
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/CannotInsertType.java
@@ -0,0 +1,29 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP cannot-insert element. Indicates that the requested PUT operation
+ * could not be performed because a GET of that resource after the PUT would not
+ * yield the content of the PUT request.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class CannotInsertType extends BaseXCapError
+{
+ /**
+ * Creates the XCAP cannot-insert error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public CannotInsertType(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ConstraintFailureType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ConstraintFailureType.java
new file mode 100644
index 0000000..8d62072
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ConstraintFailureType.java
@@ -0,0 +1,29 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP constraint-failure element. Indicates that the requested operation
+ * would result in a document that failed a data constraint defined by the
+ * application usage, but not enforced by the schema or a uniqueness constraint.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class ConstraintFailureType extends BaseXCapError
+{
+ /**
+ * Creates the XCAP constraint-failure with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public ConstraintFailureType(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ExtensionType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ExtensionType.java
new file mode 100644
index 0000000..ed17459
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/ExtensionType.java
@@ -0,0 +1,51 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+import java.util.*;
+
+import org.w3c.dom.*;
+
+/**
+ * The XCAP extension element. Indicates an error condition that is defined by
+ * an extension to XCAP. Clients that do not understand the content of the
+ * extension element MUST discard the xcap-error document and treat the error
+ * as an unqualified 409.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class ExtensionType extends BaseXCapError
+{
+ /**
+ * The list of any elements.
+ */
+ private List<Element> any;
+
+ /**
+ * Creates the XCAP extension error.
+ */
+ public ExtensionType()
+ {
+ super(null);
+ }
+
+ /**
+ * Gets the value of the any property.
+ *
+ * @return the any property.
+ */
+ public List<Element> getAny()
+ {
+ if (any == null)
+ {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NoParentType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NoParentType.java
new file mode 100644
index 0000000..8541ff1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NoParentType.java
@@ -0,0 +1,64 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP no-parent element. Indicates that an attempt to insert a document,
+ * element, or attribute failed because the directory, document, or element into
+ * which the insertion was supposed to occur does not exist. This error element
+ * can contain an optional ancestor element, which provides an HTTP URI that
+ * represents the closest parent that would be a valid point of insertion. This
+ * HTTP URI MAY be a relative URI, relative to the document itself. Because this
+ * is a valid HTTP URI, its node selector component MUST be percent-encoded.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class NoParentType extends BaseXCapError
+{
+ /**
+ * The ancestor element. HTTP uri that represents the closest parent that
+ * would be a valid point of insertion.
+ */
+ protected String ancestor;
+
+ NoParentType()
+ {
+ super(null);
+ }
+
+ /**
+ * Creates the XCAP no-parent error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public NoParentType(String phrase)
+ {
+ super(phrase);
+ }
+
+ /**
+ * Gets the phrase attribute.
+ *
+ * @return User readable error description.
+ */
+ public String getAncestor()
+ {
+ return ancestor;
+ }
+
+ /**
+ * Sets the value of the ancestor property.
+ *
+ * @param ancestor the ancestor to set.
+ */
+ void setAncestor(String ancestor)
+ {
+ this.ancestor = ancestor;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotUtf8Type.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotUtf8Type.java
new file mode 100644
index 0000000..9076944
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotUtf8Type.java
@@ -0,0 +1,28 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP not-utf-8 element. Indicates that the request could not be completed
+ * because it would have produced a document not encoded in UTF-8.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class NotUtf8Type extends BaseXCapError
+{
+ /**
+ * Creates the XCAP not-utf-8 error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public NotUtf8Type(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotWellFormedType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotWellFormedType.java
new file mode 100644
index 0000000..22fc72a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotWellFormedType.java
@@ -0,0 +1,28 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP not-well-formed element. Indicates that the body of the request was
+ * not a well-formed XML document.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class NotWellFormedType extends BaseXCapError
+{
+ /**
+ * Creates the XCAP not-well-formed error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public NotWellFormedType(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlAttValueType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlAttValueType.java
new file mode 100644
index 0000000..44c7f12
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlAttValueType.java
@@ -0,0 +1,28 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP not-xml-att-value element. Indicates that the request was supposed
+ * to contain a valid XML attribute value, but did not.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class NotXmlAttValueType extends BaseXCapError
+{
+ /**
+ * Creates the XCAP not-xml-att-value error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public NotXmlAttValueType(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlFragType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlFragType.java
new file mode 100644
index 0000000..46897dd
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/NotXmlFragType.java
@@ -0,0 +1,29 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP not-xml-frag element. Indicates that the request was supposed to
+ * contain a valid XML fragment body, but did not. Most likely this is because
+ * the XML in the body was malformed or not balanced.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class NotXmlFragType extends BaseXCapError
+{
+ /**
+ * Creates the XCAP not-xml-frag error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public NotXmlFragType(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/SchemaValidationErrorType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/SchemaValidationErrorType.java
new file mode 100644
index 0000000..43c5533
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/SchemaValidationErrorType.java
@@ -0,0 +1,28 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP schema-validation-error element. Indicates that the document was not
+ * compliant to the schema after the requested operation was performed.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class SchemaValidationErrorType extends BaseXCapError
+{
+ /**
+ * Creates the XCAP schema-validation-error error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public SchemaValidationErrorType(String phrase)
+ {
+ super(phrase);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/UniquenessFailureType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/UniquenessFailureType.java
new file mode 100644
index 0000000..a78e462
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/UniquenessFailureType.java
@@ -0,0 +1,118 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+import java.util.*;
+
+/**
+ * The XCAP uniqueness-failure element. Indicates that the requested operation
+ * would result in a document that did not meet a uniqueness constraint defined
+ * by the application usage. For each URI, element, or attribute specified by
+ * the client that is not unique, an exists element is present as the content of
+ * the error element. Each exists element has a "field" attribute that contains
+ * a relative URI identifying the XML element or attribute whose value needs to
+ * be unique, but wasn't. The relative URI is relative to the document itself,
+ * and will therefore start with the root element. The query component of the
+ * URI MUST be present if the node selector portion of the URI contains
+ * namespace prefixes. Since the "field" node selector is a valid HTTP URI, it
+ * MUST be percent-encoded. The exists element can optionally contain a list of
+ * alt-value elements. Each one is a suggested alternate value that does not
+ * currently exist on the server.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class UniquenessFailureType extends BaseXCapError
+{
+ /**
+ * The list of exists elements.
+ */
+ protected List<ExistsType> exists;
+
+ /**
+ * Creates the XCAP uniqueness-failure error.
+ */
+ UniquenessFailureType()
+ {
+ super(null);
+ }
+
+ /**
+ * Creates the XCAP uniqueness-failure error with phrase attribute.
+ *
+ * @param phrase the phrase to set.
+ */
+ public UniquenessFailureType(String phrase)
+ {
+ super(phrase);
+ }
+
+ /**
+ * Gets the exists attribute.
+ *
+ * @return the exists property.
+ */
+ public List<ExistsType> getExists()
+ {
+ if (exists == null)
+ {
+ exists = new ArrayList<ExistsType>();
+ }
+ return this.exists;
+ }
+
+ /**
+ * The XCAP exists element.
+ */
+ public static class ExistsType
+ {
+ /**
+ * The list of alt-value elements.
+ */
+ protected List<String> altValue;
+
+ /**
+ * The field attribute.
+ */
+ protected String field;
+
+ /**
+ * Gets the altValue attribute.
+ *
+ * @return the altValue property.
+ */
+ public List<String> getAltValue()
+ {
+ if (altValue == null)
+ {
+ altValue = new ArrayList<String>();
+ }
+ return this.altValue;
+ }
+
+ /**
+ * Gets the field attribute.
+ *
+ * @return the field property.
+ */
+ public String getField()
+ {
+ return field;
+ }
+
+ /**
+ * Sets the value of the field property.
+ *
+ * @param field the field to set.
+ */
+ public void setField(String field)
+ {
+ this.field = field;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapError.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapError.java
new file mode 100644
index 0000000..e49ab03
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapError.java
@@ -0,0 +1,22 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP error inteface.
+ *
+ * @author Grigorii Balutsel
+ */
+public interface XCapError
+{
+ /**
+ * Gets the phrase attribute.
+ *
+ * @return User readable error description.
+ */
+ public String getPhrase();
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorParser.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorParser.java
new file mode 100644
index 0000000..f757916
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorParser.java
@@ -0,0 +1,514 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.*;
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.StringUtils.*;
+import static net.java.sip.communicator.impl.protocol.sip.xcap.model.XmlUtils.*;
+import org.w3c.dom.*;
+
+/**
+ * Utility class that helps to converts xcap-error xml to the object model and
+ * object model to the xcap-error xml.
+ *
+ * @author Grigorii Balutsel
+ */
+
+public final class XCapErrorParser
+{
+ private static final String NAMESPACE = "urn:ietf:params:xml:ns:xcap-error";
+
+ private static final String XCAP_ERROR_ELEMENT = "xcap-error";
+
+ private static final String CANNOT_DELETE_ELEMENT = "cannot-delete";
+
+ private static final String CANNOT_INSERT_ELEMENT = "cannot-insert";
+
+ private static final String CONSTRAINT_FAILURE_ELEMENT =
+ "constraint-failure";
+
+ private static final String EXTENSION_ELEMENT = "extension";
+
+ private static final String NOPARENT_ELEMENT = "no-parent";
+
+ private static final String NOPARENT_ANCESTOR_ELEMENT = "ancestor";
+
+ private static final String NOT_UTF8_ELEMENT = "not-utf-8";
+
+ private static final String NOT_WELL_FORMED_ELEMENT = "not-well-formed";
+
+ private static final String NOT_XML_ATT_VALUE_ELEMENT = "not-xml-att-value";
+
+ private static final String NOT_XMLF_FRAG_ELEMENT = "not-xml-frag";
+
+ private static final String SCHEMA_VALIDATION_ERROR_ELEMENT =
+ "schema-validation-error";
+
+ private static final String UNIQUENESS_FAILURE_ELEMENT =
+ "uniqueness-failure";
+
+ private static final String UNIQUENESS_FAILURE_EXISTS_ELEMENT =
+ "exists";
+
+ private static final String UNIQUENESS_FAILURE_EXISTS_FIELD_ATTR =
+ "field";
+
+ private static final String UNIQUENESS_FAILURE_EXISTS_ALT_VALUE_ELEMENT =
+ "alt-value";
+
+ private static final String PHRASE_ATTR = "phrase";
+
+ /**
+ * Creates xcap-error object from the element.
+ *
+ * @param xml the XML to analyze.
+ * @return the resource-lists object.
+ * @throws ParsingException if there is some error during parsing.
+ */
+ public static XCapErrorType fromXml(String xml)
+ throws ParsingException
+ {
+ if (isNullOrEmpty(xml))
+ {
+ throw new IllegalArgumentException("XML cannot be null or empty");
+ }
+ try
+ {
+ XCapErrorType error = new XCapErrorType();
+ Document document = createDocument(xml);
+ Element xCapErrorElement = document.getDocumentElement();
+ if (XCAP_ERROR_ELEMENT.equals(xCapErrorElement.getLocalName()) &&
+ !NAMESPACE.equals(xCapErrorElement.getNamespaceURI()))
+ {
+ throw new Exception("Document doesn't contain xcap-error " +
+ "element");
+ }
+ // Process attributes
+ NamedNodeMap attributes = xCapErrorElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("xcap-error element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ throw new Exception("xcap-error element is invalid");
+ }
+ // Process elements
+ NodeList childNodes = xCapErrorElement.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element element = (Element) node;
+ String namespaceUri = getNamespaceUri(element);
+ if (!NAMESPACE.equals(namespaceUri))
+ {
+ throw new Exception("xcap-error element is invalid");
+ }
+ error.setError(errorFromElement(element));
+ }
+ return error;
+ }
+ catch (Exception ex)
+ {
+ throw new ParsingException(ex);
+ }
+ }
+
+ /**
+ * Creates xcap-error object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the list object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static XCapError errorFromElement(Element element)
+ throws Exception
+ {
+ XCapError error;
+ if (!NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("error-element element is invalid");
+ }
+ String localName = element.getLocalName();
+ if (CANNOT_DELETE_ELEMENT.equals(localName))
+ {
+ error = new CannotDeleteType(getPhraseAttribute(element));
+ }
+ else if (CANNOT_INSERT_ELEMENT.equals(localName))
+ {
+ error = new CannotInsertType(getPhraseAttribute(element));
+ }
+ else if (CONSTRAINT_FAILURE_ELEMENT.equals(localName))
+ {
+ error = new ConstraintFailureType(getPhraseAttribute(element));
+ }
+ else if (EXTENSION_ELEMENT.equals(localName))
+ {
+ error = getExtensionFromElement(element);
+ }
+ else if (NOPARENT_ELEMENT.equals(localName))
+ {
+ error = getNoParentFromElement(element);
+ }
+ else if (NOT_UTF8_ELEMENT.equals(localName))
+ {
+ error = new NotUtf8Type(getPhraseAttribute(element));
+ }
+ else if (NOT_WELL_FORMED_ELEMENT.equals(localName))
+ {
+ error = new NotWellFormedType(getPhraseAttribute(element));
+ }
+ else if (NOT_XML_ATT_VALUE_ELEMENT.equals(localName))
+ {
+ error = new NotXmlAttValueType(getPhraseAttribute(element));
+ }
+ else if (NOT_XMLF_FRAG_ELEMENT.equals(localName))
+ {
+ error = new NotXmlAttValueType(getPhraseAttribute(element));
+ }
+ else if (SCHEMA_VALIDATION_ERROR_ELEMENT.equals(localName))
+ {
+ error = new SchemaValidationErrorType(
+ getPhraseAttribute(element));
+ }
+ else if (UNIQUENESS_FAILURE_ELEMENT.equals(element.getLocalName()))
+ {
+ error = getUniquenessFailureFromElement(element);
+ }
+ else
+ {
+ throw new Exception("content element is invalid");
+ }
+ return error;
+ }
+
+ /**
+ * Gets phrase value from the element.
+ *
+ * @param element the element to analyze.
+ * @return the list object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static String getPhraseAttribute(Element element)
+ throws Exception
+ {
+ String result = null;
+ if (!NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("error element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("data element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (!NAMESPACE.equals(namespaceUri) ||
+ !PHRASE_ATTR.equals(attribute.getLocalName()) ||
+ result != null)
+ {
+ throw new Exception("error element is invalid");
+ }
+ result = attribute.getValue();
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ throw new Exception("error element is invalid");
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates extension object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the list object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static ExtensionType getExtensionFromElement(Element element)
+ throws Exception
+ {
+ ExtensionType result = new ExtensionType();
+ if (!EXTENSION_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("extension element is invalid");
+ }
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("extension element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ throw new Exception("extension element is invalid");
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element childElement = (Element) node;
+ String namespaceUri = getNamespaceUri(childElement);
+ if (namespaceUri == null)
+ {
+ throw new Exception("extension element is invalid");
+ }
+ if (NAMESPACE.equals(namespaceUri))
+ {
+ throw new Exception("extension element is invalid");
+ }
+ result.getAny().add(childElement);
+ }
+ return result;
+ }
+
+ /**
+ * Creates no-parent object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the list object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static NoParentType getNoParentFromElement(Element element)
+ throws Exception
+ {
+ NoParentType result = new NoParentType();
+ if (!NOPARENT_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("no-parent element is invalid");
+ }
+ String phrase = null;
+ String ancestor = null;
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("no-parent element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (!NAMESPACE.equals(namespaceUri) ||
+ !PHRASE_ATTR.equals(attribute.getLocalName()) ||
+ phrase != null)
+ {
+ throw new Exception("no-parent element is invalid");
+ }
+ phrase = attribute.getValue();
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element childElement = (Element) node;
+ String namespaceUri = getNamespaceUri(childElement);
+ String localName = childElement.getLocalName();
+ if (namespaceUri == null)
+ {
+ throw new Exception("no-parent element is invalid");
+ }
+ if (!NAMESPACE.equals(namespaceUri) ||
+ !NOPARENT_ANCESTOR_ELEMENT.equals(localName) ||
+ ancestor != null)
+ {
+ throw new Exception("no-parent element is invalid");
+ }
+ ancestor = childElement.getTextContent();
+ }
+ result.setPhrase(phrase);
+ result.setAncestor(ancestor);
+ return result;
+ }
+
+ /**
+ * Creates uniqueness-failure object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the list object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static UniquenessFailureType getUniquenessFailureFromElement(
+ Element element)
+ throws Exception
+ {
+ UniquenessFailureType result = new UniquenessFailureType();
+ if (!UNIQUENESS_FAILURE_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("uniqueness-failure element is invalid");
+ }
+ String phrase = null;
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("uniqueness-failure element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (!NAMESPACE.equals(namespaceUri) ||
+ !PHRASE_ATTR.equals(attribute.getLocalName()) ||
+ phrase != null)
+ {
+ throw new Exception("uniqueness-failure element is invalid");
+ }
+ phrase = attribute.getValue();
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element childElement = (Element) node;
+ String namespaceUri = getNamespaceUri(childElement);
+ String localName = childElement.getLocalName();
+ if (namespaceUri == null)
+ {
+ throw new Exception("uniqueness-failure element is invalid");
+ }
+ if (!NAMESPACE.equals(namespaceUri) ||
+ !UNIQUENESS_FAILURE_EXISTS_ELEMENT.equals(localName))
+ {
+ throw new Exception("uniqueness-failure element is invalid");
+ }
+ result.getExists().add(getExistsFromElement(childElement));
+ }
+ result.setPhrase(phrase);
+ return result;
+ }
+
+ /**
+ * Creates exists object from the element.
+ *
+ * @param element the element to analyze.
+ * @return the list object.
+ * @throws Exception if there is some error during parsing.
+ */
+ private static UniquenessFailureType.ExistsType getExistsFromElement(
+ Element element)
+ throws Exception
+ {
+ UniquenessFailureType.ExistsType result =
+ new UniquenessFailureType.ExistsType();
+ if (!UNIQUENESS_FAILURE_EXISTS_ELEMENT.equals(element.getLocalName()) ||
+ !NAMESPACE.equals(getNamespaceUri(element)))
+ {
+ throw new Exception("exists element is invalid");
+ }
+ String field = null;
+ // Process attributes
+ NamedNodeMap attributes = element.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++)
+ {
+ Attr attribute = (Attr) attributes.item(i);
+ String namespaceUri = getNamespaceUri(attribute);
+ if (namespaceUri == null)
+ {
+ throw new Exception("exists element is invalid");
+ }
+ if (isStandartXmlNamespace(namespaceUri))
+ {
+ continue;
+ }
+ if (!NAMESPACE.equals(namespaceUri) ||
+ !UNIQUENESS_FAILURE_EXISTS_FIELD_ATTR
+ .equals(attribute.getLocalName()) ||
+ field != null)
+ {
+ throw new Exception("exists element is invalid");
+ }
+ field = attribute.getValue();
+ }
+ // Process elements
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++)
+ {
+ Node node = childNodes.item(i);
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ {
+ continue;
+ }
+ Element childElement = (Element) node;
+ String namespaceUri = getNamespaceUri(childElement);
+ String localName = childElement.getLocalName();
+ if (namespaceUri == null)
+ {
+ throw new Exception("exists element is invalid");
+ }
+ if (!NAMESPACE.equals(namespaceUri) ||
+ !UNIQUENESS_FAILURE_EXISTS_ALT_VALUE_ELEMENT
+ .equals(localName))
+ {
+ throw new Exception("exists element is invalid");
+ }
+ result.getAltValue().add(childElement.getTextContent());
+ }
+ if (field == null)
+ {
+ throw new Exception("exists element is invalid");
+ }
+ result.setField(field);
+ return result;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorType.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorType.java
new file mode 100644
index 0000000..a6524ba
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/XCapErrorType.java
@@ -0,0 +1,42 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror;
+
+/**
+ * The XCAP xcap-error element. Indicates the reason for the error.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class XCapErrorType
+{
+ /**
+ * The error element.
+ */
+ private XCapError error;
+
+ /**
+ * Gets the value of the error property.
+ *
+ * @return the error property.
+ */
+ public XCapError getError()
+ {
+ return error;
+ }
+
+ /**
+ * Sets the value of the error property.
+ *
+ * @param error the uri to set.
+ */
+ public void setError(XCapError error)
+ {
+ this.error = error;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/xcap-error.xsd b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/xcap-error.xsd
new file mode 100644
index 0000000..9efbfe5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/model/xcaperror/xcap-error.xsd
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="urn:ietf:params:xml:ns:xcap-error"
+ xmlns="urn:ietf:params:xml:ns:xcap-error"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xs:element name="error-element" abstract="true"/>
+ <xs:element name="xcap-error">
+ <xs:annotation>
+ <xs:documentation>Indicates the reason for the error.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="error-element"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="extension" substitutionGroup="error-element">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:any namespace="##any" processContents="lax"
+ minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="schema-validation-error"
+ substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This element indicates that the document was not
+ compliant to the schema after the requested operation was
+ performed.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="not-xml-frag" substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the request was supposed to
+ contain a valid XML fragment body, but did not.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="no-parent" substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that an attempt to insert an
+ element, attribute, or document failed because the document or
+ element into which the insertion was supposed to occur does not
+ exist.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="ancestor" type="xs:anyURI" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Contains an HTTP URI that points to
+ the element that is the closest ancestor that does
+ exist.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="cannot-insert" substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the requested PUT operation
+ could not be performed because a GET of that resource after the
+ PUT would not yield the content of the PUT request.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="not-xml-att-value"
+ substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the request was supposed to
+ contain a valid XML attribute value, but did not.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="uniqueness-failure"
+ substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the requested operation would
+ result in a document that did not meet a uniqueness constraint
+ defined by the application usage.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="exists" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>For each URI, element, or attribute
+ specified by the client that is not unique, one of
+ these is present.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence minOccurs="0">
+ <xs:element name="alt-value" type="xs:string"
+ maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>An optional set of
+ alternate values can be provided.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="field" type="xs:string"
+ use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="not-well-formed"
+ substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the body of the request was
+ not a well-formed document.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="constraint-failure"
+ substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the requested operation would
+ result in a document that failed a data constraint defined by
+ the application usage, but not enforced by the schema or a
+ uniqueness constraint.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="cannot-delete" substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the requested DELETE
+ operation could not be performed because it would not be
+ idempotent.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="not-utf-8" substitutionGroup="error-element">
+ <xs:annotation>
+ <xs:documentation>This indicates that the request could not be
+ completed because it would have produced a document not encoded
+ in UTF-8.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="phrase" type="xs:string" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/xcap/utils/StreamUtils.java b/src/net/java/sip/communicator/impl/protocol/sip/xcap/utils/StreamUtils.java
new file mode 100644
index 0000000..de28cc8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/sip/xcap/utils/StreamUtils.java
@@ -0,0 +1,66 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.sip.xcap.utils;
+
+import java.io.*;
+
+/**
+ * Base HTTP XCAP client implementation.
+ * <p/>
+ * Compliant with rfc4825
+ *
+ * @author Grigorii Balutsel
+ */
+public class StreamUtils
+{
+ /**
+ * The buffer size (1kb).
+ */
+ private static int BUFFER_SIZE = 1024;
+
+ /**
+ * This class cannot be instanced.
+ */
+ private StreamUtils()
+ {
+ }
+
+ /**
+ * Reads content from the stream.
+ *
+ * @param source the input stream.
+ * @return the content.
+ * @throws IOException if there is some error during read
+ * operation.
+ * @throws IllegalArgumentException if source is null.
+ */
+ public static byte[] read(InputStream source)
+ throws IOException
+ {
+ if (source == null)
+ {
+ throw new IllegalArgumentException("Input parameter can't be null");
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try
+ {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int bytesRead;
+ while ((bytesRead = source.read(buffer)) > -1)
+ {
+ out.write(buffer, 0, bytesRead);
+ }
+ return out.toByteArray();
+ }
+ finally
+ {
+ source.close();
+ out.close();
+ }
+ }
+}
+
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java
index a9eea7a..f0c1ccf 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/PresencePanel.java
@@ -16,42 +16,79 @@ import net.java.sip.communicator.util.swing.*;
* The <tt>PresencePanel</tt> is the one containing presence information.
*
* @author Yana Stamcheva
+ * @author Grigorii Balutsel
*/
public class PresencePanel
- extends TransparentPanel
+ extends TransparentPanel
{
private JPanel presenceOpPanel
- = new TransparentPanel(new BorderLayout(10, 10));
+ = new TransparentPanel(new BorderLayout(10, 10));
private JPanel buttonsPresOpPanel =
- new TransparentPanel(new GridLayout(0, 1, 10, 10));
+ new TransparentPanel(new GridLayout(0, 1, 10, 10));
private JPanel labelsPresOpPanel
- = new TransparentPanel(new GridLayout(0, 1, 10, 10));
+ = new TransparentPanel(new GridLayout(0, 1, 10, 10));
private JPanel valuesPresOpPanel
- = new TransparentPanel(new GridLayout(0, 1, 10, 10));
+ = new TransparentPanel(new GridLayout(0, 1, 10, 10));
private JCheckBox enablePresOpButton =
- new SIPCommCheckBox(Resources
- .getString("plugin.sipaccregwizz.ENABLE_PRESENCE"), true);
+ new SIPCommCheckBox(Resources
+ .getString("plugin.sipaccregwizz.ENABLE_PRESENCE"), true);
private JCheckBox forceP2PPresOpButton =
- new SIPCommCheckBox(Resources
- .getString("plugin.sipaccregwizz.FORCE_P2P_PRESENCE"), false);
+ new SIPCommCheckBox(Resources
+ .getString("plugin.sipaccregwizz.FORCE_P2P_PRESENCE"),
+ false);
private JLabel pollPeriodLabel = new JLabel(
- Resources.getString(
- "plugin.sipaccregwizz.OFFLINE_CONTACT_POLLING_PERIOD"));
+ Resources.getString(
+ "plugin.sipaccregwizz.OFFLINE_CONTACT_POLLING_PERIOD"));
private JLabel subscribeExpiresLabel = new JLabel(
- Resources.getString("plugin.sipaccregwizz.SUBSCRIPTION_EXPIRATION"));
+ Resources.getString("plugin.sipaccregwizz.SUBSCRIPTION_EXPIRATION"));
private JTextField pollPeriodField
- = new JTextField(SIPAccountRegistration.DEFAULT_POLL_PERIOD);
+ = new JTextField(SIPAccountRegistration.DEFAULT_POLL_PERIOD);
private JTextField subscribeExpiresField =
- new JTextField(SIPAccountRegistration.DEFAULT_SUBSCRIBE_EXPIRES);
+ new JTextField(SIPAccountRegistration.DEFAULT_SUBSCRIBE_EXPIRES);
+
+ private JPanel xCapPanel
+ = new TransparentPanel(new BorderLayout(10, 10));
+
+ private JPanel xCapButtonsPanel
+ = new TransparentPanel(new GridLayout(0, 1, 10, 10));
+
+ private JPanel xCapLabelsPanel
+ = new TransparentPanel(new GridLayout(0, 1, 10, 10));
+
+ private JPanel xCapValuesPanel
+ = new TransparentPanel(new GridLayout(0, 1, 10, 10));
+
+ private JLabel xCapServerUriLabel = new JLabel(
+ Resources.getString("plugin.sipaccregwizz.XCAP_SERVER_URI"));
+
+ private JLabel xCapUserLabel = new JLabel(
+ Resources.getString("plugin.sipaccregwizz.XCAP_USER"));
+
+ private JLabel xCapPasswordLabel = new JLabel(
+ Resources.getString("plugin.sipaccregwizz.XCAP_PASSWORD"));
+
+ private JTextField xCapServerUriValue = new JTextField();
+
+ private JTextField xCapUserValue = new JTextField();
+
+ private JPasswordField xCapPasswordValue = new JPasswordField();
+
+ private JCheckBox xCapEnableBox = new SIPCommCheckBox(
+ Resources.getString("plugin.sipaccregwizz.XCAP_ENABLE"),
+ false);
+
+ private JCheckBox xCapUseSipCredetialsBox = new SIPCommCheckBox(
+ Resources.getString("plugin.sipaccregwizz.XCAP_USE_SIP_CREDETIALS"),
+ true);
/**
* Creates an instance of <tt>PresencePanel</tt>.
@@ -85,16 +122,54 @@ public class PresencePanel
presenceOpPanel.add(valuesPresOpPanel, BorderLayout.CENTER);
presenceOpPanel.setBorder(BorderFactory.createTitledBorder(
- Resources.getString("plugin.sipaccregwizz.PRESENCE_OPTIONS")));
+ Resources.getString("plugin.sipaccregwizz.PRESENCE_OPTIONS")));
+
+ xCapEnableBox.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JCheckBox checkBox = (JCheckBox) evt.getSource();
+ setXCapEnableEnabled(checkBox.isSelected());
+ }
+ });
+ xCapButtonsPanel.add(xCapEnableBox);
+
+ xCapUseSipCredetialsBox.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JCheckBox checkBox = (JCheckBox) evt.getSource();
+ setXCapUseSipCredetialsEnabled(checkBox.isSelected());
+ }
+ });
+ xCapButtonsPanel.add(xCapUseSipCredetialsBox);
+
+ setXCapEnableEnabled(xCapEnableBox.isSelected());
+
+ xCapLabelsPanel.add(xCapServerUriLabel);
+ xCapLabelsPanel.add(xCapUserLabel);
+ xCapLabelsPanel.add(xCapPasswordLabel);
+
+ xCapValuesPanel.add(xCapServerUriValue);
+ xCapValuesPanel.add(xCapUserValue);
+ xCapValuesPanel.add(xCapPasswordValue);
+
+ xCapPanel.add(xCapButtonsPanel, BorderLayout.NORTH);
+ xCapPanel.add(xCapLabelsPanel, BorderLayout.WEST);
+ xCapPanel.add(xCapValuesPanel, BorderLayout.CENTER);
+
+ xCapPanel.setBorder(BorderFactory.createTitledBorder(
+ Resources.getString("plugin.sipaccregwizz.XCAP_OPTIONS")));
this.add(presenceOpPanel, BorderLayout.NORTH);
+ this.add(xCapPanel, BorderLayout.SOUTH);
}
/**
* Enables or disable all presence related options.
*
* @param isEnabled <code>true</code> to enable the presence related
- * options, <code>false</code> - to disable them.
+ * options, <code>false</code> - to disable them.
*/
void setPresenceOptionsEnabled(boolean isEnabled)
{
@@ -104,9 +179,42 @@ public class PresencePanel
}
/**
+ * Enables or disable XCAP credetials related options.
+ *
+ * @param isEnabled <code>true</code> to enable the credetials related
+ * options, <code>false</code> - to disable them.
+ */
+ void setXCapUseSipCredetialsEnabled(boolean isEnabled)
+ {
+ xCapUserValue.setEnabled(!isEnabled);
+ xCapPasswordValue.setEnabled(!isEnabled);
+ }
+
+ /**
+ * Enables or disable XCAP related options.
+ *
+ * @param isEnabled <code>true</code> to enable the XCAP related
+ * options, <code>false</code> - to disable them.
+ */
+ void setXCapEnableEnabled(boolean isEnabled)
+ {
+ xCapUseSipCredetialsBox.setEnabled(isEnabled);
+ xCapServerUriValue.setEnabled(isEnabled);
+ if(isEnabled)
+ {
+ setXCapUseSipCredetialsEnabled(xCapUseSipCredetialsBox.isSelected());
+ }
+ else
+ {
+ setXCapUseSipCredetialsEnabled(true);
+ }
+ }
+
+ /**
* Indicates if the presence is enabled.
+ *
* @return <tt>true</tt> if the presence is enabled, <tt>false</tt> -
- * otherwise
+ * otherwise
*/
boolean isPresenceEnabled()
{
@@ -115,8 +223,9 @@ public class PresencePanel
/**
* Enables/disables the presence.
+ *
* @param isPresenceEnabled <tt>true</tt> to enable the presence,
- * <tt>false</tt> - otherwise
+ * <tt>false</tt> - otherwise
*/
void setPresenceEnabled(boolean isPresenceEnabled)
{
@@ -125,8 +234,9 @@ public class PresencePanel
/**
* Indicates if the peer-to-peer presence mode is selected.
+ *
* @return <tt>true</tt> if the peer-to-peer presence mode is selected,
- * <tt>false</tt> - otherwise.
+ * <tt>false</tt> - otherwise.
*/
boolean isForcePeerToPeerMode()
{
@@ -135,8 +245,9 @@ public class PresencePanel
/**
* Enables/disables the peer-to-peer presence mode.
+ *
* @param forceP2P <tt>true</tt> to select the peer-to-peer presence mode,
- * <tt>false</tt> - otherwise.
+ * <tt>false</tt> - otherwise.
*/
void setForcePeerToPeerMode(boolean forceP2P)
{
@@ -145,6 +256,7 @@ public class PresencePanel
/**
* Returns the poll period.
+ *
* @return the poll period
*/
String getPollPeriod()
@@ -154,6 +266,7 @@ public class PresencePanel
/**
* Sets the poll period.
+ *
* @param pollPeriod the poll period
*/
void setPollPeriod(String pollPeriod)
@@ -163,6 +276,7 @@ public class PresencePanel
/**
* Returns the subscription expiration information.
+ *
* @return the subscription expiration information
*/
String getSubscriptionExpiration()
@@ -172,10 +286,113 @@ public class PresencePanel
/**
* Sets the subscription expiration information.
+ *
* @param subscExp the subscription expiration information
*/
void setSubscriptionExpiration(String subscExp)
{
subscribeExpiresField.setText(subscExp);
}
+
+ /**
+ * Indicates if XCAP has to use its capabilities.
+ *
+ * @return <tt>true</tt> if XCAP has to use its capabilities,
+ * <tt>false</tt> - otherwise.
+ */
+ boolean isXCapEnable()
+ {
+ return xCapEnableBox.isSelected();
+ }
+
+ /**
+ * Sets if has to use its capabilities.
+ *
+ * @param xCapEnable if has to use its capabilities.
+ */
+ void setXCapEnable(boolean xCapEnable)
+ {
+ xCapEnableBox.setSelected(xCapEnable);
+ }
+
+ /**
+ * Indicates if XCAP has to use SIP account credetials.
+ *
+ * @return <tt>true</tt> if XCAP has to use SIP account credetials,
+ * <tt>false</tt> - otherwise.
+ */
+ boolean isXCapUseSipCredetials()
+ {
+ return xCapUseSipCredetialsBox.isSelected();
+ }
+
+ /**
+ * Sets if XCAP has to use SIP account credetials.
+ *
+ * @param xCapUseSipCredetials if XCAP has to use SIP account credetials.
+ */
+ void setXCapUseSipCredetials(boolean xCapUseSipCredetials)
+ {
+ xCapUseSipCredetialsBox.setSelected(xCapUseSipCredetials);
+ }
+
+ /**
+ * Gets the XCAP server uri.
+ *
+ * @return the XCAP server uri.
+ */
+ String getXCapServerUri()
+ {
+ return xCapServerUriValue.getText();
+ }
+
+ /**
+ * Sets the XCAP server uri.
+ *
+ * @param xCapServerUri the XCAP server uri.
+ */
+ void setXCapServerUri(String xCapServerUri)
+ {
+ xCapServerUriValue.setText(xCapServerUri);
+ }
+
+ /**
+ * Gets the XCAP user.
+ *
+ * @return the XCAP user.
+ */
+ String getXCapUser()
+ {
+ return xCapUserValue.getText();
+ }
+
+ /**
+ * Sets the XCAP user.
+ *
+ * @param xCapUser the XCAP user.
+ */
+ void setXCapUser(String xCapUser)
+ {
+ xCapUserValue.setText(xCapUser);
+ }
+
+ /**
+ * Gets the XCAP password.
+ *
+ * @return the XCAP password.
+ */
+ char[] getXCapPassword()
+ {
+ return xCapPasswordValue.getPassword();
+ }
+
+ /**
+ * Sets the XCAP password.
+ *
+ * @param xCapPassword the XCAP password.
+ */
+ void setXCapPassword(String xCapPassword)
+ {
+ xCapPasswordValue.setText(xCapPassword);
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java
index acb2bb2..4f3966d 100755
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistration.java
@@ -10,6 +10,7 @@ package net.java.sip.communicator.plugin.sipaccregwizz;
* through the <tt>SIPAccountRegistrationWizard</tt>.
*
* @author Yana Stamcheva
+ * @author Grigorii Balutsel
*/
public class SIPAccountRegistration
{
@@ -65,6 +66,16 @@ public class SIPAccountRegistration
private String defaultDomain = null;
+ private boolean xCapEnable = false;
+
+ private boolean xCapUseSipCredetials = true;
+
+ private String xCapServerUri;
+
+ private String xCapUser;
+
+ private String xCapPassword;
+
public String getPreferredTransport()
{
return preferredTransport;
@@ -457,4 +468,104 @@ public class SIPAccountRegistration
{
this.defaultTransport = defaultTransport;
}
+
+ /**
+ * Checks if XCAP is enabled.
+ *
+ * @return true if XCAP is enabled otherwise false.
+ */
+ public boolean isXCapEnable()
+ {
+ return xCapEnable;
+ }
+ /**
+ * Sets if XCAP is enable.
+ *
+ * @param xCapEnable XCAP enable.
+ */
+ public void setXCapEnable(boolean xCapEnable)
+ {
+ this.xCapEnable = xCapEnable;
+ }
+
+ /**
+ * Checks if XCAP has to use SIP account credetials.
+ *
+ * @return true if XCAP has to use SIP account credetials otherwise false.
+ */
+ public boolean isXCapUseSipCredetials()
+ {
+ return xCapUseSipCredetials;
+ }
+
+ /**
+ * Sets if XCAP has to use SIP account credetials.
+ *
+ * @param xCapUseSipCredetials if XCAP has to use SIP account credetials.
+ */
+ public void setXCapUseSipCredetials(boolean xCapUseSipCredetials)
+ {
+ this.xCapUseSipCredetials = xCapUseSipCredetials;
+ }
+
+ /**
+ * Gets the XCAP server uri.
+ *
+ * @return the XCAP server uri.
+ */
+ public String getXCapServerUri()
+ {
+ return xCapServerUri;
+ }
+
+ /**
+ * Sets the XCAP server uri.
+ *
+ * @param xCapServerUri the XCAP server uri.
+ */
+ public void setXCapServerUri(String xCapServerUri)
+ {
+ this.xCapServerUri = xCapServerUri;
+ }
+
+ /**
+ * Gets the XCAP user.
+ *
+ * @return the XCAP user.
+ */
+ public String getXCapUser()
+ {
+ return xCapUser;
+ }
+
+ /**
+ * Sets the XCAP user.
+ *
+ * @param xCapUser the XCAP user.
+ */
+ public void setXCapUser(String xCapUser)
+ {
+ this.xCapUser = xCapUser;
+ }
+
+ /**
+ * Gets the XCAP password.
+ *
+ * @return the XCAP password.
+ */
+ public String getXCapPassword()
+ {
+ return xCapPassword;
+ }
+
+ /**
+ * Sets the XCAP password.
+ *
+ * @param xCapPassword the XCAP password.
+ */
+ public void setXCapPassword(String xCapPassword)
+ {
+ this.xCapPassword = xCapPassword;
+ }
+
}
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java
index 275a79e..b792278 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationForm.java
@@ -11,6 +11,7 @@ import net.java.sip.communicator.util.swing.*;
* The <tt>SIPAccountRegistrationForm</tt>.
*
* @author Yana Stamcheva
+ * @author Grogorii Balutsel
*/
public class SIPAccountRegistrationForm
extends TransparentPanel
@@ -237,6 +238,14 @@ public class SIPAccountRegistrationForm
SIPAccRegWizzActivator.getUIService().getAccountRegWizardContainer()
.setBackButtonEnabled(true);
+ registration.setXCapEnable(presencePanel.isXCapEnable());
+ registration.setXCapUseSipCredetials(
+ presencePanel.isXCapUseSipCredetials());
+ registration.setXCapServerUri(presencePanel.getXCapServerUri());
+ registration.setXCapUser(presencePanel.getXCapUser());
+ registration
+ .setXCapPassword(new String(presencePanel.getXCapPassword()));
+
return true;
}
@@ -294,6 +303,17 @@ public class SIPAccountRegistrationForm
String keepAliveInterval =
accountID.getAccountPropertyString("KEEP_ALIVE_INTERVAL");
+ boolean xCapEnable = accountID
+ .getAccountPropertyBoolean("XCAP_ENABLE", false);
+ boolean xCapUseSipCredetials = accountID
+ .getAccountPropertyBoolean("XCAP_USE_SIP_CREDETIALS", true);
+ String xCapServerUri =
+ accountID.getAccountPropertyString("XCAP_SERVER_URI");
+ String xCapUser =
+ accountID.getAccountPropertyString("XCAP_USER");
+ String xCapPassword =
+ accountID.getAccountPropertyString("XCAP_PASSWORD");
+
connectionPanel.setServerOverridden(
accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.IS_SERVER_OVERRIDDEN, false));
@@ -344,6 +364,14 @@ public class SIPAccountRegistrationForm
connectionPanel.setKeepAliveMethod(keepAliveMethod);
connectionPanel.setKeepAliveInterval(keepAliveInterval);
+
+ presencePanel.setXCapEnable(xCapEnable);
+ presencePanel.setXCapEnableEnabled(xCapEnable);
+ presencePanel.setXCapUseSipCredetials(xCapUseSipCredetials);
+ presencePanel.setXCapUseSipCredetialsEnabled(xCapUseSipCredetials);
+ presencePanel.setXCapServerUri(xCapServerUri);
+ presencePanel.setXCapUser(xCapUser);
+ presencePanel.setXCapPassword(xCapPassword);
}
/**
diff --git a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java
index 4b3786d..d04cda7 100644
--- a/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java
+++ b/src/net/java/sip/communicator/plugin/sipaccregwizz/SIPAccountRegistrationWizard.java
@@ -21,6 +21,7 @@ import org.osgi.framework.*;
* the user to create and configure a new SIP account.
*
* @author Yana Stamcheva
+ * @author Grigorii Balutsel
*/
public class SIPAccountRegistrationWizard
implements AccountRegistrationWizard
@@ -130,8 +131,8 @@ public class SIPAccountRegistrationWizard
*/
public Iterator<Map.Entry<String, String>> getSummary()
{
- Hashtable<String, String> summaryTable
- = new Hashtable<String, String>();
+ LinkedHashMap<String, String> summaryTable
+ = new LinkedHashMap<String, String>();
boolean rememberPswd = registration.isRememberPassword();
String rememberPswdString = Resources.getString(
@@ -234,6 +235,36 @@ public class SIPAccountRegistrationWizard
Resources.getString("plugin.sipaccregwizz.KEEP_ALIVE_INTERVAL"),
registration.getKeepAliveInterval());
+ if (registration.isXCapEnable())
+ {
+ summaryTable.put(Resources.getString(
+ "plugin.sipaccregwizz.XCAP_ENABLE"),
+ Resources.getString("service.gui.YES"));
+
+ summaryTable.put(Resources.getString(
+ "plugin.sipaccregwizz.XCAP_SERVER_URI_SUMMARY"),
+ registration.getXCapServerUri());
+
+ if (registration.isXCapUseSipCredetials())
+ {
+ summaryTable.put(Resources.getString(
+ "plugin.sipaccregwizz.XCAP_USE_SIP_CREDETIALS_SUMMARY"),
+ Resources.getString("service.gui.YES"));
+ }
+ else
+ {
+ summaryTable.put(Resources.getString(
+ "plugin.sipaccregwizz.XCAP_USER_SUMMARY"),
+ registration.getXCapUser());
+ }
+ }
+ else
+ {
+ summaryTable.put(Resources.getString(
+ "plugin.sipaccregwizz.XCAP_ENABLE"),
+ Resources.getString("service.gui.NO"));
+ }
+
return summaryTable.entrySet().iterator();
}
@@ -405,6 +436,30 @@ public class SIPAccountRegistrationWizard
accountProperties.put("KEEP_ALIVE_INTERVAL",
registration.getKeepAliveInterval());
+ accountProperties.put("XCAP_ENABLE",
+ Boolean.toString(registration.isXCapEnable()));
+
+ if(registration.isXCapEnable())
+ {
+ accountProperties.put("XCAP_USE_SIP_CREDETIALS",
+ Boolean.toString(registration.isXCapUseSipCredetials()));
+ if (registration.getXCapServerUri() != null)
+ {
+ accountProperties
+ .put("XCAP_SERVER_URI", registration.getXCapServerUri());
+ }
+ if (registration.getXCapUser() != null)
+ {
+ accountProperties
+ .put("XCAP_USER", registration.getXCapUser());
+ }
+ if (registration.getXCapPassword() != null)
+ {
+ accountProperties
+ .put("XCAP_PASSWORD", registration.getXCapPassword());
+ }
+ }
+
if(isModification)
{
accountProperties.put(ProtocolProviderFactory.USER_ID, userName);
diff --git a/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java b/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java
index b2def52..6de70fa 100644
--- a/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java
+++ b/src/net/java/sip/communicator/service/protocol/ServerStoredDetails.java
@@ -118,8 +118,12 @@ public class ServerStoredDetails
if(!(obj instanceof GenericDetail))
return false;
- GenericDetail other = (GenericDetail)obj;
+ if(this == obj)
+ {
+ return true;
+ }
+ GenericDetail other = (GenericDetail)obj;
if(this.detailDisplayName != null // equals DisplayName
&& other.getDetailDisplayName() != null
diff --git a/test/net/java/sip/communicator/slick/protocol/sip/SipProtocolProviderServiceLick.java b/test/net/java/sip/communicator/slick/protocol/sip/SipProtocolProviderServiceLick.java
index 0e77da6..12993c4 100644
--- a/test/net/java/sip/communicator/slick/protocol/sip/SipProtocolProviderServiceLick.java
+++ b/test/net/java/sip/communicator/slick/protocol/sip/SipProtocolProviderServiceLick.java
@@ -41,7 +41,7 @@ public class SipProtocolProviderServiceLick
*/
public static final String DISABLE_ONLINE_TESTS_PROPERTY_NAME
= "accounts.sip.DISABLE_ONLINE_TESTING";
-
+
/**
* The name of the property the value of which is a formatted string that
* contains the contact list that.
@@ -50,6 +50,11 @@ public class SipProtocolProviderServiceLick
= "accounts.sip.CONTACT_LIST";
/**
+ * The name of the property the value of which is XCAP server uri.
+ */
+ public static final String XCAP_SERVER_PROPERTY_NAME = "XCAP_SERVER";
+
+ /**
* Initializes and registers all tests that we'll run as a part of this
* slick.
*
@@ -70,6 +75,9 @@ public class SipProtocolProviderServiceLick
if (offlineMode != null && offlineMode.equalsIgnoreCase("true"))
SipSlickFixture.onlineTestingDisabled = true;
+
+ // xcap parsing tests
+ addTest(TestXCapParse.suite());
//First test account installation so that the service that has
//been installed by it gets tested by the rest of the tests.
@@ -93,6 +101,9 @@ public class SipProtocolProviderServiceLick
// telephony
addTestSuite(TestOperationSetBasicTelephonySipImpl.class);
+
+ // Server stored info
+ addTest(TestOperationSetServerStoredInfo.suite());
}
//This must remain after all other tests using the accounts
diff --git a/test/net/java/sip/communicator/slick/protocol/sip/TestAccountInstallation.java b/test/net/java/sip/communicator/slick/protocol/sip/TestAccountInstallation.java
index 7c9336e..a10aae1 100644
--- a/test/net/java/sip/communicator/slick/protocol/sip/TestAccountInstallation.java
+++ b/test/net/java/sip/communicator/slick/protocol/sip/TestAccountInstallation.java
@@ -6,11 +6,12 @@
*/
package net.java.sip.communicator.slick.protocol.sip;
-import java.util.*;
-
-import org.osgi.framework.*;
import junit.framework.*;
+import net.java.sip.communicator.impl.protocol.sip.*;
import net.java.sip.communicator.service.protocol.*;
+import org.osgi.framework.*;
+
+import java.util.*;
public class TestAccountInstallation
extends TestCase
@@ -241,6 +242,20 @@ public class TestAccountInstallation
}
}
+ String xCapServerUri = System.getProperty(accountPrefix +
+ SipProtocolProviderServiceLick.XCAP_SERVER_PROPERTY_NAME, null);
+ if (xCapServerUri != null)
+ {
+ table.put(ProtocolProviderServiceSipImpl.XCAP_ENABLE,
+ Boolean.TRUE.toString());
+ table.put(ProtocolProviderServiceSipImpl.XCAP_USE_SIP_CREDETIALS,
+ Boolean.TRUE.toString());
+ table.put(ProtocolProviderServiceSipImpl.XCAP_USE_SIP_CREDETIALS,
+ Boolean.TRUE.toString());
+ table.put(ProtocolProviderServiceSipImpl.XCAP_SERVER_URI,
+ xCapServerUri);
+ }
+
table.put(ProtocolProviderFactory.FORCE_P2P_MODE,
Boolean.FALSE.toString());
diff --git a/test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfo.java b/test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfo.java
new file mode 100644
index 0000000..4aa9631
--- /dev/null
+++ b/test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfo.java
@@ -0,0 +1,356 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.slick.protocol.sip;
+
+import junit.framework.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.impl.protocol.sip.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent.*;
+
+import java.net.URI;
+import java.util.*;
+
+/**
+ * Testing of the user and account info. Tests for reading, adding, removing,
+ * replacing and error handling.
+ *
+ * @author Grigorii Balutsel
+ */
+public class TestOperationSetServerStoredInfo extends TestCase
+{
+ /**
+ * Fixture for testing.
+ */
+ private SipSlickFixture fixture = new SipSlickFixture();
+
+ /**
+ * Account Info Operation set for testing.
+ */
+ private OperationSetServerStoredAccountInfo
+ opSetServerStoredAccountInfo = null;
+
+ /**
+ * XCAP client for testing.
+ */
+ private XCapClient xCapClient;
+
+ /**
+ * Creates tests under specific name.
+ *
+ * @param name the tests name.
+ */
+ public TestOperationSetServerStoredInfo(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Get a reference to the account info operation sets.
+ *
+ * @throws Exception
+ */
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ fixture.setUp();
+ Map<String, OperationSet> supportedOperationSets =
+ fixture.provider1.getSupportedOperationSets();
+ if (supportedOperationSets == null || supportedOperationSets.size() < 1)
+ {
+ throw new NullPointerException(
+ "No OperationSet implementations are supported by this " +
+ "SIP implementation.");
+ }
+ opSetServerStoredAccountInfo = (OperationSetServerStoredAccountInfo)
+ supportedOperationSets.get(
+ OperationSetServerStoredAccountInfo.class.getName());
+ if (opSetServerStoredAccountInfo == null)
+ {
+ throw new NullPointerException(
+ "No implementation for Account Info was found");
+ }
+ if (!opSetServerStoredAccountInfo
+ .isDetailClassSupported(ServerStoredDetails.ImageDetail.class))
+ {
+ throw new NullPointerException(
+ "OperationSet does't support avatars");
+ }
+
+ // Connect to the XCAP server
+ xCapClient = createXCapClient();
+ if (!xCapClient.isConnected())
+ {
+ throw new NullPointerException("XCAP client is not connected");
+ }
+ if (!xCapClient.isPresContentSupported())
+ {
+ throw new NullPointerException(
+ "XCAP server doesn't support pres-content");
+ }
+
+ // Clean details
+ List<ServerStoredDetails.GenericDetail> details =
+ new ArrayList<ServerStoredDetails.GenericDetail>();
+ Iterator<ServerStoredDetails.GenericDetail> detailIterator =
+ opSetServerStoredAccountInfo.getAllAvailableDetails();
+ while (detailIterator.hasNext())
+ {
+ details.add(detailIterator.next());
+ }
+ for (ServerStoredDetails.GenericDetail detail : details)
+ {
+ opSetServerStoredAccountInfo.removeDetail(detail);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+ fixture.tearDown();
+ xCapClient.dicsonnect();
+ }
+
+ /**
+ * Creates a test suite containing tests of this class in a specific order.
+ * We'll first execute tests beginning with the "test" prefix and then go to
+ * ordered tests. We first execute tests for reading info, then writing.
+ * Then the ordered tests - error handling and finaly for removing details
+ *
+ * @return Test a testsuite containing all tests to execute.
+ */
+ public static Test suite()
+ {
+ if(System.getProperty(SipProtocolProviderServiceLick.ACCOUNT_1_PREFIX +
+ SipProtocolProviderServiceLick.XCAP_SERVER_PROPERTY_NAME) != null)
+ {
+ return new TestSuite(TestOperationSetServerStoredInfo.class);
+ }
+ return new TestSuite();
+ }
+
+ private XCapClient createXCapClient()
+ throws Exception
+ {
+ String userName = System.getProperty(
+ SipProtocolProviderServiceLick.ACCOUNT_1_PREFIX +
+ ProtocolProviderFactory.USER_ID);
+ String password = System.getProperty(
+ SipProtocolProviderServiceLick.ACCOUNT_1_PREFIX +
+ ProtocolProviderFactory.PASSWORD);
+ String xCapServerUri = System.getProperty(
+ SipProtocolProviderServiceLick.ACCOUNT_1_PREFIX +
+ SipProtocolProviderServiceLick
+ .XCAP_SERVER_PROPERTY_NAME);
+ XCapClient xCapClient = new XCapClientImpl();
+ xCapClient.connect(new URI(xCapServerUri),
+ ((ProtocolProviderServiceSipImpl) fixture.provider1).
+ parseAddressString(userName), password);
+ return xCapClient;
+ }
+
+ /**
+ * Tests reading info. Puts the image to the server by using XCAP client and
+ * then gets it by using Sip Communicator interfaces.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public void testReadInfo() throws Exception
+ {
+ // Add image
+ byte[] imageContent =
+ TestOperationSetServerStoredInfoData.IMAGE_CONTENT_1;
+ ServerStoredDetails.ImageDetail imageDetail1 =
+ new ServerStoredDetails.ImageDetail(null, imageContent);
+ opSetServerStoredAccountInfo.addDetail(imageDetail1);
+ // Get saved image
+ Iterator<ServerStoredDetails.GenericDetail> storedDetails =
+ opSetServerStoredAccountInfo
+ .getDetails(ServerStoredDetails.ImageDetail.class);
+ assertNotNull("Stored details cannot be null", storedDetails);
+ assertTrue("Stored details doesn't have ImageDetail",
+ storedDetails.hasNext());
+ ServerStoredDetails.GenericDetail storedImageDetail =
+ storedDetails.next();
+ assertTrue("Stored details is not ImageDetail",
+ storedImageDetail instanceof ServerStoredDetails.ImageDetail);
+ byte[] savedContent =
+ ((ServerStoredDetails.ImageDetail) storedImageDetail).getBytes();
+ assertEquals(
+ "The ImageDetail we set is not set or not read properly",
+ imageContent.length,
+ savedContent.length);
+ for (int i = 0; i < imageContent.length; i++)
+ {
+ assertSame("The ImageDetail we set has not the same content",
+ imageContent[i], savedContent[i]);
+ }
+ // Get pres-content from the server
+ ContentType presContent = xCapClient.getPresContent(
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ assertNotNull("Pres-content cannot be null", presContent);
+ assertNotNull("Pres-content data cannot be null",
+ presContent.getData());
+ assertNotNull("Pres-content data value cannot be null",
+ presContent.getData().getValue());
+ byte[] serverContent = Base64.decode(presContent.getData().getValue());
+ assertEquals(
+ "The ImageDetail we set is not set or not read properly",
+ imageContent.length, serverContent.length);
+ for (int i = 0; i < imageContent.length; i++)
+ {
+ assertSame("The ImageDetail we set has not the same content",
+ imageContent[i], serverContent[i]);
+ }
+ // Create pres-content
+// ContentType presContent = new ContentType();
+// ContentType.MimeType mimeType = new ContentType.MimeType();
+// mimeType.setValue(TestOperationSetServerStoredInfoData.IMAGE_TYPE);
+// presContent.setMimeType(mimeType);
+// ContentType.EncodingType encoding = new ContentType.EncodingType();
+// encoding.setValue("base64");
+// presContent.setEncoding(encoding);
+// ContentType.DataType data = new ContentType.DataType();
+// data.setValue(encodedImageContent);
+// presContent.setData(data);
+ // Put pres-content to the server
+// xCapClient.putPresContent(presContent,
+// ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ }
+
+ /**
+ * Tests writing info. Puts the image to the server by using Sip
+ * Communicator interfaces and then gets it by using XCAP client.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public void testWriteInfo() throws Exception
+ {
+ byte[] imageContent =
+ TestOperationSetServerStoredInfoData.IMAGE_CONTENT_1;
+ ServerStoredDetails.ImageDetail imageDetail =
+ new ServerStoredDetails.ImageDetail(null, imageContent);
+ opSetServerStoredAccountInfo.addDetail(imageDetail);
+ // Get pres-content
+ ContentType presContent = xCapClient.getPresContent(
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ assertNotNull("Pres-content cannot be null", presContent);
+ assertNotNull("Pres-content data cannot be null",
+ presContent.getData());
+ assertNotNull("Pres-content data value cannot be null",
+ presContent.getData().getValue());
+ byte[] serverContent = Base64.decode(presContent.getData().getValue());
+ assertEquals(
+ "The ImageDetail we set is not set or not read properly",
+ imageContent.length, serverContent.length);
+ for (int i = 0; i < imageContent.length; i++)
+ {
+ assertSame("The ImageDetail we set has not the same content",
+ imageContent[i], serverContent[i]);
+ }
+ // Remove saved image
+ opSetServerStoredAccountInfo.removeDetail(imageDetail);
+ }
+
+ /**
+ * Tests deleting info. Puts the image to the server by using Sip
+ * Communicator interfaces, deletes it and then gets it by using XCAP
+ * client.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public void testRemoveInfo() throws Exception
+ {
+ byte[] imageContent =
+ TestOperationSetServerStoredInfoData.IMAGE_CONTENT_1;
+ ServerStoredDetails.ImageDetail imageDetail =
+ new ServerStoredDetails.ImageDetail(null, imageContent);
+ opSetServerStoredAccountInfo.addDetail(imageDetail);
+ // Remove saved image
+ boolean removeResult =
+ opSetServerStoredAccountInfo.removeDetail(imageDetail);
+ assertTrue("The result of remove operation cannot be false",
+ removeResult);
+ // Get saved image
+ Iterator<ServerStoredDetails.GenericDetail> storedDetails =
+ opSetServerStoredAccountInfo
+ .getDetails(ServerStoredDetails.ImageDetail.class);
+ assertNotNull("Stored details cannot be null", storedDetails);
+ assertFalse("Stored details cannot have ImageDetail",
+ storedDetails.hasNext());
+ // Get pres-content
+ ContentType presContent = xCapClient.getPresContent(
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ assertNull("Pres-content cannot be not null", presContent);
+ }
+
+ /**
+ * Tests replacing info. Puts the image to the server by using Sip
+ * Communicator interfaces, replace it and then gets it by using XCAP
+ * client.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public void testReplaceInfo() throws Exception
+ {
+ byte[] imageContent1 =
+ TestOperationSetServerStoredInfoData.IMAGE_CONTENT_1;
+ byte[] imageContent2 =
+ TestOperationSetServerStoredInfoData.IMAGE_CONTENT_2;
+ ServerStoredDetails.ImageDetail imageDetail1 =
+ new ServerStoredDetails.ImageDetail(null, imageContent1);
+ ServerStoredDetails.ImageDetail imageDetail2 =
+ new ServerStoredDetails.ImageDetail(null, imageContent2);
+ opSetServerStoredAccountInfo.addDetail(imageDetail1);
+ boolean replaceResult = opSetServerStoredAccountInfo
+ .replaceDetail(imageDetail1, imageDetail2);
+ assertTrue("The result of replace operation cannot be false",
+ replaceResult);
+ // Get saved image
+ Iterator<ServerStoredDetails.GenericDetail> storedDetails =
+ opSetServerStoredAccountInfo
+ .getDetails(ServerStoredDetails.ImageDetail.class);
+ assertNotNull("Stored details cannot be null", storedDetails);
+ assertTrue("Stored details doesn't have ImageDetail",
+ storedDetails.hasNext());
+ ServerStoredDetails.GenericDetail imageDetail =
+ storedDetails.next();
+ assertTrue("Stored details is not ImageDetail",
+ imageDetail instanceof ServerStoredDetails.ImageDetail);
+ byte[] savedContent =
+ ((ServerStoredDetails.ImageDetail) imageDetail).getBytes();
+ assertEquals(
+ "The ImageDetail we set is not set or not read properly",
+ imageContent2.length,
+ savedContent.length);
+ for (int i = 0; i < imageContent2.length; i++)
+ {
+ assertSame("The ImageDetail we set has not the same content",
+ imageContent2[i], savedContent[i]);
+ }
+ // Get pres-content
+ ContentType presContent = xCapClient.getPresContent(
+ ProtocolProviderServiceSipImpl.PRES_CONTENT_IMAGE_NAME);
+ assertNotNull("Pres-content cannot be null", presContent);
+ assertNotNull("Pres-content data cannot be null",
+ presContent.getData());
+ assertNotNull("Pres-content data value cannot be null",
+ presContent.getData().getValue());
+ byte[] serverContent = Base64.decode(presContent.getData().getValue());
+ assertEquals(
+ "The ImageDetail we set is not set or not read properly",
+ imageContent2.length, serverContent.length);
+ for (int i = 0; i < imageContent2.length; i++)
+ {
+ assertSame("The ImageDetail we set has not the same content",
+ imageContent2[i], serverContent[i]);
+ }
+ // Remove saved image
+ opSetServerStoredAccountInfo.removeDetail(imageDetail2);
+ }
+}
diff --git a/test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfoData.java b/test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfoData.java
new file mode 100644
index 0000000..794d81b
--- /dev/null
+++ b/test/net/java/sip/communicator/slick/protocol/sip/TestOperationSetServerStoredInfoData.java
@@ -0,0 +1,175 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.slick.protocol.sip;
+
+/**
+ * Contains data for server stored info tests.
+ *
+ * @author Grigorii Balutsel
+ */
+public class TestOperationSetServerStoredInfoData
+{
+ /**
+ * The image content.
+ */
+ public static String IMAGE_TYPE = "image/png";
+
+ /**
+ * The image content.
+ */
+ public static byte[] IMAGE_CONTENT_1 = new byte[]{
+ -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0,
+ 1, 0, 0, 0, 1, 0, 8, 2, 0, 0, 0, -45, 16, 63, 49, 0, 0, 0, 1, 115,
+ 82, 71, 66, 0, -82, -50, 28, -23, 0, 0, 0, 4, 103, 65, 77, 65, 0, 0,
+ -79, -113, 11, -4, 97, 5, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0, 122,
+ 38, 0, 0, -128, -124, 0, 0, -6, 0, 0, 0, -128, -24, 0, 0, 117, 48,
+ 0, 0, -22, 96, 0, 0, 58, -104, 0, 0, 23, 112, -100, -70, 81, 60, 0,
+ 0, 3, 114, 73, 68, 65, 84, 120, 94, -19, -48, 49, 1, 0, 0, 0, -62,
+ -96, -11, 79, -19, 101, 11, -120, 64, 97, -64, -128, 1, 3, 6, 12,
+ 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6,
+ 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3,
+ 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1,
+ 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128,
+ 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64,
+ -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96,
+ -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48,
+ 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24,
+ 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12,
+ 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6,
+ 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3,
+ 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1,
+ 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128,
+ 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64,
+ -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96,
+ -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48,
+ 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24,
+ 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12,
+ 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6,
+ 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3,
+ 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1,
+ 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128,
+ 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64,
+ -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96,
+ -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48,
+ 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24,
+ 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12,
+ 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6,
+ 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3,
+ 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1,
+ 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128,
+ 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64,
+ -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96,
+ -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48,
+ 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24,
+ 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12,
+ 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6,
+ 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3,
+ 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1,
+ 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128,
+ 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64,
+ -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96,
+ -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48,
+ 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24,
+ 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12,
+ 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6,
+ 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3,
+ 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128, 1,
+ 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64, -128,
+ 1, 3, 6, 12, 24, 48, 96, -64, -128, 1, 3, 6, 12, 24, 48, 96, -64,
+ -64, 7, 6, 1, 45, 0, 1, 96, 53, 25, 121, 0, 0, 0, 0, 73, 69, 78, 68,
+ -82, 66, 96, -126
+ };
+
+ /**
+ * The image content.
+ */
+ public static byte[] IMAGE_CONTENT_2 = new byte[]{
+ -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0,
+ 1, 0, 0, 0, 1, 0, 8, 2, 0, 0, 0, -45, 16, 63, 49, 0, 0, 0, 4, 103,
+ 65, 77, 65, 0, 0, -79, -113, 11, -4, 97, 5, 0, 0, 4, -64, 73, 68,
+ 65, 84, 120, 94, -19, -44, -63, 13, 0, 32, 12, 3, 49, -70, -1, -48,
+ -64, -85, 75, -100, 17, 11, -60, 106, 50, -9, 120, 4, -62, 2, -65,
+ 0, 62, -127, -84, -128, -21, 39, -112, 22, 72, -121, -49, -50, -98,
+ -32, 43, -96, 0, 4, -46, 2, -23, -16, -122, -112, -128, 2, 16, 72,
+ 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40,
+ 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10,
+ -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45,
+ -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0,
+ 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37,
+ 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64,
+ 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2,
+ 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1,
+ 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23,
+ -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64,
+ 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35,
+ -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92,
+ -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127,
+ -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113,
+ -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14,
+ 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46,
+ 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2,
+ 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68,
+ -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11,
+ -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0,
+ -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10,
+ -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45,
+ -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0,
+ 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37,
+ 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64,
+ 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2,
+ 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1,
+ 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23,
+ -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64,
+ 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35,
+ -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92,
+ -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127,
+ -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113,
+ -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14,
+ 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46,
+ 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2,
+ 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68,
+ -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11,
+ -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0,
+ -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10,
+ -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45,
+ -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0,
+ 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37,
+ 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64,
+ 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2,
+ 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1,
+ 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23,
+ -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64,
+ 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35,
+ -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92,
+ -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127,
+ -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113,
+ -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14,
+ 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46,
+ 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2,
+ 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68,
+ -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11,
+ -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0,
+ -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10,
+ -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45,
+ -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0,
+ 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37,
+ 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64,
+ 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2,
+ 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1,
+ 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23,
+ -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64,
+ 32, 45, -112, 14, 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35,
+ -96, 0, 4, -46, 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92,
+ -61, -37, 63, 2, 10, 64, 32, 45, -112, 14, 111, -1, 8, 40, 0, -127,
+ -76, 64, 58, -68, -3, 35, -96, 0, 4, -46, 2, -23, -16, -10, -113,
+ -128, 2, 16, 72, 11, -92, -61, -37, 63, 2, 10, 64, 32, 45, -112, 14,
+ 111, -1, 8, 40, 0, -127, -76, 64, 58, -68, -3, 35, -96, 0, 4, -46,
+ 2, -23, -16, -10, -113, -128, 2, 16, 72, 11, -92, -61, -37, 63, 2,
+ 15, -73, -86, 16, -29, 81, -81, -102, 105, 0, 0, 0, 0, 73, 69, 78,
+ 68, -82, 66, 96, -126
+ };
+}
diff --git a/test/net/java/sip/communicator/slick/protocol/sip/TestXCapParse.java b/test/net/java/sip/communicator/slick/protocol/sip/TestXCapParse.java
new file mode 100644
index 0000000..da04692
--- /dev/null
+++ b/test/net/java/sip/communicator/slick/protocol/sip/TestXCapParse.java
@@ -0,0 +1,503 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.slick.protocol.sip;
+
+import junit.framework.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent.*;
+import net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror.*;
+import org.w3c.dom.*;
+
+import javax.xml.namespace.*;
+
+/**
+ * Contains tests of parsing xcap-caps, resource-lists, pres-content.
+ *
+ * @author Grigorii Balutsel
+ */
+public class TestXCapParse extends TestCase
+{
+ /**
+ * The resource-xml for the tests.
+ */
+ private static String RESOURCE_LISTS_XML =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<resource-lists xmlns=\"urn:ietf:params:xml:ns:resource-lists\"" +
+ " xmlns:ext=\"extension\"" +
+ " xmlns:xsi=\"htt//www.w3.org/2001/XMLSchema-instance\">" +
+ " xsi:schemaLocation=\"resource-lists.xsd \">" +
+ " <list name=\"list1\" ext:name=\"ext list1\">" +
+ " <entry uri=\"sip:entry1@example.com\"" +
+ " ext:uri=\"sip:user1@example.com\">" +
+ " <display-name>Entry1</display-name>" +
+ " <ext:display-name>Ext:Entry1</ext:display-name>" +
+ " </entry>" +
+ " <entry uri=\"sip:entry2@example.com\">" +
+ " <display-name xml:lang=\"en-US\">Entry2</display-name>" +
+ " </entry>" +
+ " <list name=\"sub_group1\"/>" +
+ " <external anchor=\"anchor_uri\">" +
+ " <display-name xml:lang=\"en-US\">External</display-name>" +
+ " </external>" +
+ " <entry-ref ref=\"ref_uri\">" +
+ " <display-name xml:lang=\"en-US\">Entry1</display-name>" +
+ " </entry-ref>" +
+ " <ext:entry uri=\"sip:user1@example.com\" " +
+ " ext:uri=\"sip:user1@example.com\"/>" +
+ " </list>" +
+ " <list name=\"list2\">" +
+ " <display-name xml:lang=\"en-US\">List2</display-name>" +
+ " </list>" +
+ "</resource-lists>";
+
+ /**
+ * The resource-xml for the tests.
+ */
+ private static String XCAP_CAPS_XML =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<xcap-caps xmlns=\"urn:ietf:params:xml:ns:xcap-caps\"" +
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
+ " xsi:schemaLocation=\"xcap-caps.xsd \">" +
+ " <auids>" +
+ " <auid>resource-lists</auid>" +
+ " <auid>rls-services</auid>" +
+ " </auids>" +
+ " <extensions>" +
+ " <!-- No extensions defined -->" +
+ " </extensions>" +
+ " <namespaces>" +
+ " <namespace>urn:ietf:params:xml:ns:xcap-caps</namespace>" +
+ " <namespace>urn:ietf:params:xml:ns:xcap-error</namespace>" +
+ " <namespace>urn:ietf:params:xml:ns:resource-lists</namespace>" +
+ " </namespaces>" +
+ "</xcap-caps>";
+
+ /**
+ * The pres-content for the tests.
+ */
+ private static String PRES_CONTENT_XML =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<content xmlns=\"urn:oma:xml:prs:pres-content\">" +
+ " <mime-type>image/png</mime-type>" +
+ " <encoding>base64</encoding>" +
+ " <description>Description</description>" +
+ " <description xml:lang=\"en-US\">Description</description>" +
+ " <data>Data</data>" +
+ "</content>";
+
+ /**
+ * The xcap-error uniqueness-failure for the tests.
+ */
+ private static String XCAP_ERROR_CANNOT_DELETE_XML =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<xcap-error xmlns=\"urn:ietf:params:xml:ns:xcap-error\">" +
+ " <cannot-delete phrase=\"Cannot Delete\"/>" +
+ "</xcap-error>";
+
+ /**
+ * The xcap-error uniqueness-failure for the tests.
+ */
+ private static String XCAP_ERROR_UNIQUENESS_FAILURE_XML =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<xcap-error xmlns=\"urn:ietf:params:xml:ns:xcap-error\">" +
+ " <uniqueness-failure>" +
+ " <exists field=\"field\">" +
+ " <alt-value>sip:entry@example.com</alt-value>" +
+ " </exists>" +
+ " </uniqueness-failure>" +
+ "</xcap-error>";
+
+ /**
+ * Creates a test suite containing tests of this class in a specific order.
+ * We'll first execute tests beginning with the "test" prefix and then go to
+ * ordered tests. We first execute tests for reading info, then writing.
+ * Then the ordered tests - error handling and finaly for removing details
+ *
+ * @return Test a testsuite containing all tests to execute.
+ */
+ public static Test suite()
+ {
+ return new TestSuite(TestXCapParse.class);
+ }
+
+ /**
+ * Tests resource-lists parsing.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public static void testResourceListsParse() throws Exception
+ {
+ ResourceListsType originalResourceLists =
+ ResourceListsParser.fromXml(RESOURCE_LISTS_XML);
+ validateResourceLists(originalResourceLists);
+ String xml = ResourceListsParser.toXml(originalResourceLists);
+ ResourceListsType storedResourceLists =
+ ResourceListsParser.fromXml(xml);
+ validateResourceLists(storedResourceLists);
+ }
+
+ /**
+ * Tests xcap-caps parsing.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public static void testXCapCapsParse() throws Exception
+ {
+ XCapCapsType originalXCapCaps =
+ XCapCapsParser.fromXml(XCAP_CAPS_XML);
+ validateXCapCaps(originalXCapCaps);
+ }
+
+ /**
+ * Tests pres-content parsing.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public static void testPresContentParse() throws Exception
+ {
+ ContentType originalContent =
+ PresContentParser.fromXml(PRES_CONTENT_XML);
+ validatePresContent(originalContent);
+ String xml = PresContentParser.toXml(originalContent);
+ ContentType storedContent = PresContentParser.fromXml(xml);
+ validatePresContent(storedContent);
+ }
+
+ /**
+ * Tests xcap-error parsing.
+ *
+ * @throws Exception if there is some error during test.
+ */
+ public static void testXCapErrorParse() throws Exception
+ {
+ XCapErrorType cannotDelete =
+ XCapErrorParser.fromXml(XCAP_ERROR_CANNOT_DELETE_XML);
+ validateXCapErrorConnotDelete(cannotDelete);
+
+ XCapErrorType uniquenessFailure =
+ XCapErrorParser.fromXml(XCAP_ERROR_UNIQUENESS_FAILURE_XML);
+ validateXCapErrorUniquenessFailure(uniquenessFailure);
+ }
+
+ /**
+ * Validates uniqueness-failure with the original XML.
+ *
+ * @param xCapError the xcap-error to analyze.
+ */
+ private static void validateXCapErrorUniquenessFailure(
+ XCapErrorType xCapError)
+ {
+ assertNotNull("xcap-error cannot be null", xCapError);
+ assertNotNull("uniqueness-failure cannot be null",
+ xCapError.getError());
+ assertTrue(
+ "The uniqueness-failure elements we set is not read properly",
+ xCapError.getError() instanceof UniquenessFailureType);
+ UniquenessFailureType uniquenessFailure = (UniquenessFailureType)
+ xCapError.getError();
+ assertNull("The phrase we set is not read properly",
+ uniquenessFailure.getPhrase());
+ assertTrue("The exists elements we set is not read properly",
+ uniquenessFailure.getExists().size() == 1);
+ UniquenessFailureType.ExistsType exists1 =
+ uniquenessFailure.getExists().get(0);
+ assertEquals("The exists[0] element we set is not read properly",
+ exists1.getField(), "field");
+ assertTrue("The exists[0]altValue we set is not read properly",
+ exists1.getAltValue().size() == 1);
+ assertEquals("The exists[0]altValue[0] we set is not read properly",
+ exists1.getAltValue().get(0), "sip:entry@example.com");
+ }
+
+ /**
+ * Validates cannot-delete with the original XML.
+ *
+ * @param xCapError the xcap-error to analyze.
+ */
+ private static void validateXCapErrorConnotDelete(
+ XCapErrorType xCapError)
+ {
+ assertNotNull("xcap-error cannot be null", xCapError);
+ assertNotNull("cannot-delete cannot be null",
+ xCapError.getError());
+ assertTrue(
+ "The cannot-delete elements we set is not read properly",
+ xCapError.getError() instanceof CannotDeleteType);
+ CannotDeleteType cannotDelete = (CannotDeleteType)
+ xCapError.getError();
+ assertEquals("The phrase we set is not read properly",
+ cannotDelete.getPhrase(), "Cannot Delete");
+ }
+
+ /**
+ * Validates resource-lists with the original XML.
+ *
+ * @param resourceLists the resource-lists to analyze.
+ */
+ private static void validateResourceLists(ResourceListsType resourceLists)
+ {
+ assertNotNull("resource-lists cannot be null", resourceLists);
+ assertTrue("The first level lists we set is not read properly",
+ resourceLists.getList().size() == 2);
+ // list1
+ ListType list1 = resourceLists.getList().get(0);
+ assertEquals(
+ "The lists[1] name we set is not read properly",
+ list1.getName(), "list1");
+ assertEquals(
+ "The lists[1] name we set is not read properly",
+ list1.getName(), "list1");
+ assertNull("The lists[1] display-name we set is not read properly",
+ list1.getDisplayName());
+ assertTrue("The lists[1] entries we set is not read properly",
+ list1.getEntries().size() == 2);
+ assertTrue("The lists[1] lists we set is not read properly",
+ list1.getLists().size() == 1);
+ assertTrue("The lists[1] externals we set is not read properly",
+ list1.getExternals().size() == 1);
+ assertTrue("The lists[1] entryRefs we set is not read properly",
+ list1.getEntryRefs().size() == 1);
+ assertTrue("The lists[1] custom attriutes we set is not read properly",
+ list1.getAnyAttributes().size() == 1);
+ assertTrue("The lists[1] custom elements we set is not read properly",
+ list1.getAnyAttributes().size() == 1);
+
+ String list1ExtAttribute = list1.getAnyAttributes().get(
+ new QName("extension", "name", "ext"));
+ assertNotNull(
+ "The lists[1]ext:display-name attribute we set is not read " +
+ "properly",
+ list1ExtAttribute);
+ assertEquals(
+ "The lists[1]ext:display-name attribute we set is not read " +
+ "properly",
+ list1ExtAttribute, "ext list1");
+
+ Element list1ExtElement = list1.getAny().get(0);
+ assertEquals(
+ "The lists[1]ext:entry attribute we set is not read " +
+ "properly",
+ list1ExtElement.getLocalName(), "entry");
+ assertEquals(
+ "The lists[1]ext:entry attribute we set is not read " +
+ "properly",
+ XmlUtils.getNamespaceUri(list1ExtElement), "extension");
+ assertEquals(
+ "The lists[1]ext:entry attribute we set is not read " +
+ "properly",
+ list1ExtElement.getPrefix(), "ext");
+
+ EntryType lis1Entry1 = list1.getEntries().get(0);
+ assertNotNull(
+ "The lists[1]entry[1] name we set is not read properly",
+ lis1Entry1.getUri());
+ assertEquals(
+ "The lists[1]entry[1] name we set is not read properly",
+ lis1Entry1.getUri(), "sip:entry1@example.com");
+ assertNotNull(
+ "The lists[1]entry[1] display-name we set is not read properly",
+ lis1Entry1.getDisplayName());
+ assertEquals(
+ "The lists[1]entry[1] display-name we set is not read properly",
+ lis1Entry1.getDisplayName().getValue(), "Entry1");
+ assertNull(
+ "The lists[1]entry[1] display-name we set is not read properly",
+ lis1Entry1.getDisplayName().getLang());
+ String enty1ExtAttribute = lis1Entry1.getAnyAttributes().get(
+ new QName("extension", "uri", "ext"));
+ assertNotNull(
+ "The lists[1]entry[1]ext:uri attribute we set is not read " +
+ "properly",
+ enty1ExtAttribute);
+ assertEquals(
+ "The lists[1]entry[1]ext:uri attribute we set is not read " +
+ "properly",
+ enty1ExtAttribute, "sip:user1@example.com");
+ Element enty1ExtElement = lis1Entry1.getAny().get(0);
+ assertEquals(
+ "The lists[1]entry[1]ext:entry element we set is not read " +
+ "properly",
+ enty1ExtElement.getLocalName(), "display-name");
+ assertEquals(
+ "The lists[1]entry[1]ext:dispaly-name element we set is not " +
+ "read properly",
+ XmlUtils.getNamespaceUri(enty1ExtElement), "extension");
+ assertEquals(
+ "The lists[1]entry[1]ext:dispaly-name element we set is not " +
+ "read properly",
+ enty1ExtElement.getPrefix(), "ext");
+ assertEquals(
+ "The lists[1]entry[1]ext:dispaly-name element we set is not " +
+ "read properly",
+ enty1ExtElement.getTextContent(), "Ext:Entry1");
+
+ EntryType lis1Entry2 = list1.getEntries().get(1);
+ assertNotNull(
+ "The lists[1]entry[2] display-name we set is not read properly",
+ lis1Entry2.getDisplayName());
+ assertNotNull(
+ "The lists[1]entry[2] name we set is not read properly",
+ lis1Entry2.getUri());
+ assertEquals(
+ "The lists[1]entry[2] name we set is not read properly",
+ lis1Entry2.getUri(), "sip:entry2@example.com");
+ assertEquals(
+ "The lists[1]entry[2] display-name we set is not read properly",
+ lis1Entry2.getDisplayName().getValue(), "Entry2");
+ assertEquals(
+ "The lists[1]entry[2] display-name we set is not read properly",
+ lis1Entry2.getDisplayName().getLang(), "en-US");
+
+ EntryRefType list1EntryRef = list1.getEntryRefs().get(0);
+ assertEquals(
+ "The lists[1]entryRef[1] name we set is not read properly",
+ list1EntryRef.getRef(), "ref_uri");
+ assertNotNull(
+ "The lists[1]entryRef[1] display-name we set is not read " +
+ "properly",
+ list1EntryRef.getDisplayName());
+ assertEquals(
+ "The llists[1]entryRef[1] display-name we set is not read " +
+ "properly",
+ list1EntryRef.getDisplayName().getValue(), "Entry1");
+ assertEquals(
+ "The lists[1]entryRef[1]display-name we set is not read " +
+ "properly",
+ list1EntryRef.getDisplayName().getLang(), "en-US");
+
+ ExternalType list1External = list1.getExternals().get(0);
+ assertEquals(
+ "The lists[1]external[1] name we set is not read properly",
+ list1External.getAnchor(), "anchor_uri");
+ assertNotNull(
+ "The lists[1]external[1] display-name we set is not read " +
+ "properly",
+ list1External.getDisplayName());
+ assertEquals(
+ "The llists[1]external[1] display-name we set is not read " +
+ "properly",
+ list1External.getDisplayName().getValue(), "External");
+ assertEquals(
+ "The lists[1]external[1]display-name we set is not read " +
+ "properly",
+ list1External.getDisplayName().getLang(), "en-US");
+ // list2
+ ListType list2 = resourceLists.getList().get(1);
+ assertEquals(
+ "The lists[2] name we set is not read properly",
+ list2.getName(), "list2");
+ assertNotNull("The lists[2] display-name we set is not read properly",
+ list2.getDisplayName());
+ assertEquals("The lists[2] display-name we set is not read properly",
+ list2.getDisplayName().getValue(), "List2");
+ assertEquals("The lists[2] display-name we set is not read properly",
+ list2.getDisplayName().getLang(), "en-US");
+ }
+
+ /**
+ * Validates xcap-caps with the original XML.
+ *
+ * @param xCapCaps the xcap-caps to analyze.
+ */
+ private static void validateXCapCaps(XCapCapsType xCapCaps)
+ {
+ assertNotNull("xcap-caps cannot be null", xCapCaps);
+
+ AuidsType auids = xCapCaps.getAuids();
+ NamespacesType namespaces = xCapCaps.getNamespaces();
+ ExtensionsType extensions = xCapCaps.getExtensions();
+
+ assertNotNull("The auids we set is not read properly", auids);
+ assertTrue("The auids we set is not read properly",
+ auids.getAuid().size() == 2);
+ assertNotNull("The namespaces we set is not read properly", namespaces);
+ assertTrue("The namespaces we set is not read properly",
+ namespaces.getNamespace().size() == 3);
+ assertNotNull("The auids we set is not read properly", extensions);
+ assertTrue("The extensions we set is not read properly",
+ extensions.getExtension().size() == 0);
+ // auids
+ assertEquals(
+ "The auids[0] name we set is not read properly",
+ auids.getAuid().get(0), "resource-lists");
+ assertEquals(
+ "The auids[1] name we set is not read properly",
+ auids.getAuid().get(1), "rls-services");
+ // namespaces
+ assertEquals(
+ "The namespaces[0] name we set is not read properly",
+ namespaces.getNamespace().get(0),
+ "urn:ietf:params:xml:ns:xcap-caps");
+ assertEquals(
+ "The namespaces[1] name we set is not read properly",
+ namespaces.getNamespace().get(1),
+ "urn:ietf:params:xml:ns:xcap-error");
+ assertEquals(
+ "The namespaces[2] name we set is not read properly",
+ namespaces.getNamespace().get(2),
+ "urn:ietf:params:xml:ns:resource-lists");
+ }
+
+ /**
+ * Validates pres-content with the original XML.
+ *
+ * @param presContent the pres-content to analyze.
+ */
+ private static void validatePresContent(ContentType presContent)
+ {
+ assertNotNull("pres-content cannot be null", presContent);
+ DataType data = presContent.getData();
+ MimeType mimeType = presContent.getMimeType();
+ EncodingType encoding = presContent.getEncoding();
+ // data
+ assertNotNull("The data we set is not read properly", data);
+ assertEquals("The data we set is not read properly",
+ data.getValue(), "Data");
+ assertTrue("The data custom elements we set is not read properly",
+ data.getAnyAttributes().size() == 0);
+ // mime-type
+ assertNotNull("The mime-type we set is not read properly", mimeType);
+ assertEquals("The mime-type we set is not read properly",
+ mimeType.getValue(), "image/png");
+ assertTrue("The mime-type custom elements we set is not read properly",
+ mimeType.getAnyAttributes().size() == 0);
+ // encoding
+ assertNotNull("The encoding we set is not read properly", encoding);
+ assertEquals("The encoding we set is not read properly",
+ encoding.getValue(), "base64");
+ assertTrue("The encoding custom elements we set is not read properly",
+ encoding.getAnyAttributes().size() == 0);
+ // description
+ assertNotNull("The description we set is not read properly",
+ presContent.getDescription());
+ assertTrue("The description we set is not read properly",
+ presContent.getDescription().size() == 2);
+ DescriptionType description1 = presContent.getDescription().get(0);
+ assertEquals(
+ "The description[0] we set is not read properly",
+ description1.getValue(), "Description");
+ assertNull(
+ "The description[0] display-name we set is not read properly",
+ description1.getLang());
+ assertTrue(
+ "The description[0] custom elements we set is not read properly",
+ description1.getAnyAttributes().size() == 0);
+
+ DescriptionType description2 = presContent.getDescription().get(1);
+ assertEquals(
+ "The description[1] we set is not read properly",
+ description2.getValue(), "Description");
+ assertEquals(
+ "The description[1] we set is not read properly",
+ description2.getLang(), "en-US");
+ assertTrue(
+ "The description[1] custom elements we set is not read properly",
+ description2.getAnyAttributes().size() == 0);
+ }
+}
diff --git a/test/net/java/sip/communicator/slick/protocol/sip/sip.provider.slick.manifest.mf b/test/net/java/sip/communicator/slick/protocol/sip/sip.provider.slick.manifest.mf
index d285dec..85b6286 100644
--- a/test/net/java/sip/communicator/slick/protocol/sip/sip.provider.slick.manifest.mf
+++ b/test/net/java/sip/communicator/slick/protocol/sip/sip.provider.slick.manifest.mf
@@ -8,7 +8,16 @@ Import-Package: net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.configuration.event,
junit.framework,
org.osgi.framework,
+ org.w3c.dom;
+ javax.xml.namespace;
net.java.sip.communicator.util,
net.java.sip.communicator.service.protocol,
- net.java.sip.communicator.service.protocol.event
-
+ net.java.sip.communicator.service.protocol.event,
+ net.java.sip.communicator.impl.protocol.sip,
+ net.java.sip.communicator.impl.protocol.sip.xcap,
+ net.java.sip.communicator.impl.protocol.sip.xcap.utils,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.xcapcaps,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.resourcelists,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.prescontent,
+ net.java.sip.communicator.impl.protocol.sip.xcap.model.xcaperror