Verwenden von SharePoint-Webdiensten mit einem Java-Client

Früher dachte ich, ein Kamel sei etwas zum Rauchen oder Reiten in der Wüste, aber das war, bevor ich eines Tages bei der Arbeit den Mund öffnete und sagte: "Sicher, ich kann diese Dokumente automatisch in SharePoint speichern." SharePoint gibt es schon lange, daher habe ich angenommen, dass es eine Java-API oder möglicherweise einige exponierte Webdienste geben muss, die ich nutzen könnte. Nun, wie sich herausstellte, habe ich die Arbeit erledigt, und wie bei vielen Dingen endete sie besser als sie begann. Aber es gab einige Hürden auf dem Weg, die ich anderen JavaWorld-Lesern gerne vermeiden möchte.

In diesem Java-Tipp werde ich Ihnen zeigen, wie Sie grundlegende CRUD-Vorgänge für einen SharePoint-Dokumentordner von einem Java-Client aus ausführen. Die Demonstration konzentriert sich auf einige der beliebtesten Methoden, die ein SharePoint-Webdienstkonsument wahrscheinlich aufruft und die in den Kopier- und Listendiensten von Microsoft enthalten sind. Für die CRUD-Operationen verwenden wir CAML (Collaborative Application Markup Language), eine XML-basierte Sprache, die in vielen der von Copyund bereitgestellten Methoden verwendet wird Lists. Sie lernen, wie Sie gültige CAML-Strukturen erstellen, die als Methodenparameter übergeben oder Objekteigenschaften zugewiesen werden, die wiederum als Parameter an diese Dienste übergeben werden.

Dieser Tipp wird Sie hoffentlich davon überzeugen, dass es CAMLs gibt, mit denen Sie Geschäftsdokumente von Punkt A nach Punkt B bringen können, ohne sich auf vier Beine und einen Buckel verlassen zu müssen.

Demonstrationscode

Mein Demonstrationscode ist sehr einfach: Ich habe keinen anderen Open Source-Code als für die Protokollierung verwendet und meine Implementierung hat keine Abhängigkeiten von der Java EE-Technologie, sodass Sie den Quellcode direkt von Eclipse in einer Standard-Java-Anwendung ausführen können.

Hintergrund

Ich arbeite in einer Gruppe, die Informationsmanagement für große Datenmengen durchführt, die schließlich in verschiedenen Data-Marts (Service, Export, Bericht usw.) gespeichert sind. Unternehmensinterne und -externe Verbraucher nutzen die Daten, um geschäftliche und persönliche Entscheidungen zu treffen. In dieser Umgebung finden verschiedene Arten der Überwachung statt, einschließlich automatisierter Audits und Berichte, die anhand der in Data Marts enthaltenen Daten ausgeführt werden. Audits stellen sicher, dass die Daten sowohl über die Marts als auch innerhalb des Marts, in dem sie sich befinden, in einem konsistenten Zustand sind. Überwachungsberichte werden per E-Mail an verschiedene Personen gesendet und dann manuell in SharePoint gespeichert.

Da die für die Überwachung verwendeten Engines ein steckbares Output-Writer-Konzept haben, war es naheliegend, einen Writer für SharePoint einzurichten. Wir haben bereits in die Datenbank, SMTP-Server und ein Dateisystem geschrieben, daher schien dies ein logischer nächster Schritt und ein Weg zu sein, um den manuellen Prozess zu vermeiden.

Der Trick bestand natürlich darin, alles zum Laufen zu bringen.

Erste Schritte: Kommunikation mit SharePoint

Die Beispielanwendung für diesen Artikel zeigt, wie Sie von einem Java-Client aus mit SharePoint kommunizieren. Ich habe die Anwendung mit Eclipse 3.6.2 und Java 1.6.0_32 geschrieben. Abbildung 1 zeigt die beiden Hauptpakete, die in der Beispielanwendung enthalten sind.

Das erste Paket com.jw.sharepoint.examplesenthält den gesamten benutzerdefinierten Code für die Lösung. Es verwendet den im com.microsoft.sharepoint.webservicesPaket enthaltenen Code , der vom Code generiert wurde.

Bevor ich mich mit der Struktur des benutzerdefinierten Codes befasse, werde ich erklären, wie das Microsoft-Paket generiert wird. Denken Sie zunächst daran, dass wir zwei Webdienste verwenden, um Dienstaufrufe aufzurufen: Copyund Lists. Sie können auf diese Dienste auf der SharePoint-Website zugreifen, mit der Sie an folgenden Orten kommunizieren möchten:

  • //server/site/_vti_bin/Lists.asmx
  • //server/site/_vti_bin/Copy.asmx

Generieren des Webdienstpakets

Zum Generieren des Codes für das von uns verwendete Webdienstpaket wsimport, das sich im binVerzeichnis Ihrer Java-Installation befindet, sofern Sie Java 1.6 oder höher verwenden. Wenn Ihre SharePoint-Website über HTTPS ausgeführt wird, tritt möglicherweise ein Problem auf, wsimportwenn Sie sie über die oben genannten URLs direkt auf Ihren Server verweisen. In diesem Fall wird ein Fehler wie der folgende angezeigt:

[ERROR] sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPath BuilderException: unable to find valid certification path to requested target

Das Problem in diesem Fall ist, dass Ihre cacertsDatei nicht über das Zertifikat von der Site verfügt. Eine einfache Möglichkeit, dies zu umgehen, besteht darin, die WSDL-Dateien lokal mit Ihrem Browser herunterzuladen. Für das unten aufgeführte Beispiel habe ich genau das getan und die WSDLs in gespeichert c:\temp\. Listing 1 und Listing 2 zeigen die Codefragmente, mit denen ich den Quellcode generiert habe, zusammen mit der Ausgabe. Sie können die Warnung für jeden Dienst ignorieren.

Listing 1. Kopieren Sie die Servicecode-Generierung

C:\temp>"%JAVA_HOME%\bin\wsimport" -d . -p com.microsoft.schemas.sharepoint.soap -keep -extension -Xnocompile Copy.wsdl parsing WSDL... [WARNING] SOAP port "CopySoap12": uses a non-standard SOAP 1.2 binding. line 229 of file:/C:/temp/Copy.wsdl generating code...

Listing 2. Listet die Servicecode-Generierung auf

C:\temp>"%JAVA_HOME%\bin\wsimport" -d . -p com.microsoft.schemas.sharepoint.soap -keep -extension -Xnocompile list.wsdl parsing WSDL... [WARNING] SOAP port "ListsSoap12": uses a non-standard SOAP 1.2 binding. line 1511 of file:/C:/temp/list.wsdl generating code...

Sobald Sie den Code generiert haben, kann er in die Lösung integriert und verwendet werden. Sie können die –XnocompileOption aus dem wsimportBefehl entfernen . Diese Option würde dazu führen, dass die Klassendateien zusammen mit dem Quellcode generiert werden. In dieser Übung kopieren wir jedoch einfach die generierten Quelldateien in die Lösung und lassen sie von Eclipse kompilieren, als hätten wir den Quellcode erstellt.

Ein Hinweis zur Sicherheit

Um die SharePoint-Dienste erfolgreich ausführen zu können, musste ich von meiner normalen Methode des Webdienstverbrauchs abweichen, bei der meistens Axis2 verwendet wird. Ich stellte schnell fest, dass Axis2 Probleme mit der NTML-Autorisierung hat. Es ist möglich, diese Fehler durch die Verwendung von JCIFS in Verbindung mit Axis2 zu überwinden (siehe Ressourcen), aber das schien für etwas relativ Einfaches übertrieben. Mit dem Ansatz, den ich demonstriere, sind keine Sicherheitshürden zu überwinden. Wenn Ihre SharePoint-Website HTTPS verwendet, müssen Sie sicherstellen, dass die cacertsDatei mit dem Zertifikat der Website aktualisiert wird (Einzelheiten finden Sie unter Ressourcen).

Da die Beispiele als Konsolenanwendungen in Eclipse ausgeführt werden sollen, übergebe ich das folgende VM-Argument in der Ausführungskonfiguration:

-Djavax.net.ssl.trustStore=path to your updated cacerts file

Benutzerdefinierter Code

Der benutzerdefinierte Code für diese Lösung befindet sich im com.jw.sharepoint.examplesPaket im Artikelquellcode. Es enthält eine benutzerdefinierte Klasse für jede der zu testenden SharePoint-Funktionen:

  1. SharePointUploadDocumentExample zeigt, wie ein Dokument in SharePoint hochgeladen wird.
  2. SharePointDeleteListItemExample zeigt, wie ein Dokument mit CAML aus SharePoint gelöscht wird, um eine Liste abzufragen und ein Listenelement zu löschen.
  3. SharePointListExample zeigt, wie ein Ordner in SharePoint mithilfe von CAML abgefragt und anschließend die Ergebnisse interpretiert werden.

Beachten Sie, dass ich die letzte Klasse nicht explizit diskutieren werde SharePointListExample. Die SharePointDeleteListItemExampleKlasse enthält Funktionen zum Abfragen, sodass SharePointListExampleSie sie selbst lernen können.

Über die benutzerdefinierten Klassen

As shown in Figure 2, each of the custom classes follows the same pattern and extends the SharePointBaseExample class, which provides basic SharePoint functionality, as well as utility functions for dealing with CAML and XML. The custom classes also use specific properties files that they load via an initialize() function that is called in main. The properties files have all the properties needed for communicating with SharePoint and any other data that is required at runtime for the class in question.

Figure 2. Class diagram for the custom code (click to enlarge)

Each of the properties files located in the demonstration code's Configuration directory has the name of the class it supports with a .properties extension. Most of the properties contained in these files should be self-explanatory. Table 1 briefly describes the additional properties contained in SharePointDeleteListItemExample.properties.

Table 1. Additional properties of the SharePointDeleteListItemExample class

Property Description Example value
username The username for authentication to the SharePoint site. This should be fully domain qualified if running on Linux or using a different ID than used for Windows authentication. Domain\bigbird
password The password to the SharePoint site sesame
wsdl URL to the Lists.asmx WSDL //abc.xyz.com/project/epms9615/_vti_bin/Lists.asmx?wsdl
Endpoint URL to the Lists.asmx //abc.xyz.com/project/epms9615/_vti_bin/Lists.asmx
Folder The name of the base folder to use. Prod Support Folder
copy.wsdl URL to the Copy.asmx WSDL //abc.xyz.com/team/eds/_vti_bin/Copy.asmx?wsdl
copy.endpoint URL to the Copy.asmx //abc.xyz.com/team/eds/_vti_bin/Copy.asmx
copy.location The location to place files for upload //abc.xyz.com/project/epms9615/Prod%20Support%20Folder/

Daily%20Monitoring%20Status/AuditDeleteTesting/

copy.sourceFile The local file to use for uploading Configuration/SharePointDeleteListItemExample.properties
delete.FileRef.base The base URL to the SharePoint site, used in delete file requests. //abc.xyz.com/

Additional configuration files

Some additional configuration files are located in the Configuration directory. These are simple XML snippets written in CAML. We'll use these files, described in Table 2, throughout the solution.

Table 2. Additional configuration files

CAML file Description
Query.xml A CAML file containing the query that we'll use to list files from the SharePoint server. This file shows an example of a query that uses three fields with two different data types (Text and DateTime), as well as two different operators (Contains and Eq).
QueryOptions.xml A static file that we'll use throughout the examples to tell a SharePoint service that we want it to search all subfolders of the current folder.
Delete.xml A CAML file that we'll use to delete SharePoint files. Strings are substituted at runtime.
DeleteListItemQuery.xml A CAML file that we'll use to perform a query of candidate files available for removal from SharePoint

First demo: Uploading a file to SharePoint

Our first exercise will be uploading a file to SharePoint via the CopySoap web service. For this we'll use some of the classes that we generated in Listing 1 and Listing 2 by executing wsimport on the Copy.asmx.

In the SharePointBaseExample class you'll notice a method named getCopySoap(). We'll use this method to return a generated CopySoap instance, which we'll then use to upload a file by calling the method uploadDocument(CopySoap port, String sourceUrl).

The getCopySoap() method is shown in Listing 3.

Listing 3. getCopySoap()

protected CopySoap getCopySoap() throws Exception { logger.info("Creating a CopySoap instance..."); Copy service = new Copy(new URL(getProperties().getProperty("copy.wsdl")), new QName("//schemas.microsoft.com/sharepoint/soap/", "Copy")); CopySoap copySoap = service.getCopySoap(); BindingProvider bp = (BindingProvider) copySoap; bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, getProperties().getProperty("username")); bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, getProperties().getProperty("password")); bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, getProperties().getProperty("copy.endpoint")); return copySoap; }

A Copy class is instantiated using a two-argument constructor, which takes the copy service's WSDL location along with the QName instance to use. We get the CopySoap instance we need from the Copy instance. Once this is done we can cast it to a BindingProvider, which performs the protocol binding and contains the associated context objects for request-and-response message processing. From the BindingProvider we can then set the username, password, and endpoint information on the request-context Map.

Listing 4 zeigt die mainMethode der Klasse SharePointUploadDocumentExample. Diese Methode ist sehr einfach; Es verwendet getCopySoap()und uploadDocument(CopySoap port, String sourceUrl)lädt ein Dokument in SharePoint hoch. Die nach SharePoint zu kopierende Quelldatei wird in der SharePointUploadDocumentExamplezugehörigen Eigenschaftendatei definiert , die uploadDocument(…)über den copy.sourceFileEigenschaftswert an die Methode übergeben wird.

Listing 4. Laden Sie die Hauptmethode des Dokuments hoch

public static void main(String[] args) { logger.debug("main..."); try { SharePointUploadDocumentExample example = new SharePointUploadDocumentExample(); example.initialize(); CopySoap p = example.getCopySoap(); example.uploadDocument(p, properties.getProperty("copy.sourceFile")); } catch (Exception ex) { logger.error("Error caught in main: ",ex); } }

uploadDocument ()

Als nächstes rufen wir die uploadDocument()Methode auf. Zu dieser Methode sind einige Dinge zu wissen: