Archive

Posts Tagged ‘netbeans’

Creating SharePoint list items with java: tutorial

February 15, 2010 17 comments

This post completes the 2nd part of my series of “Using external business data with SharePoint”: SharePoint Web Services and Java

When I first tried to experiment with Java and SharePoint I really wondered why Microsoft didn’t invest a bit more into interoperability concerning their SharePoint platform. The potential is here: they have a market-leading product with rich Web Services. So why only support Microsoft languages? Why is there barely any Java documentation, support or examples? Or even (god forbid) a SharePoint Java library with some helper classes? I bet it would certainly attract new segments and stimulate the usage of SharePoint (or SharePoint Online) in heterogeneous IT ecosystems, what I’ve often seen in smaller companies… That would be a win-win situation for Microsoft and its customers in my opinion.

SharePoint Java Application screenshot

Tutorial introduction

In this post I will show a way to insert, update and delete SharePoint list items from Java. In case you want to build such an app from scratch, I invite you to read the three first steps of my previous tutorial that describe how to generate the Lists Web Service stub classes and how to authenticate to the Web Service. As usual, I’ve tested it with NetBeans and SharePoint Online, but it should work with MOSS 2007 and other Java IDEs. Please keep in mind that this is my take at Java and SharePoint and that there might be more efficient ways to do it, but hey, it works for me!

The challenge here will be to create a Lists request “wrapper” that will be able to do construct a basic CAML query skeleton. To better understand the structure of the request, the first stop is of course MSDN’s UpdateListItems doc. The problem is that MSDN often points fractions of the required CAML structure in their examples, but that’s not always enough, as we need to have a full SOAP sample for our Java app. What I found to be the most helpful was to fire up my browser and go to the URL of my Web Service method I was interested in. In this case, it will be UpdateListsItem, that can usually be found at sharepointsite/Lists/_vti_bin/Lists.asmx?op=UpdateListItems.

Tutorial: Creating list items from Java

In a hurry? You can download the full source code of what’s been covered until now here (GPLv2 license). Enjoy!

Here we go:

  1. Code the Lists request wrapper class. Basically this class will contain the XML SOAP request with the correct structure for the Lists Web Service. I included the imports below to avoid any ambiguity when fixing imports.
    import java.util.HashMap;
    import java.util.Map;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Text;
    
    /**
     *   @author David Dudok de Wit
     *   @version 13 Feb. 2010
     */
    public class ListsRequest {
    
        private Document rootDocument;
        private Element rootDocContent;
    
        /**
         * @return the rootDocument
         */
        public Document getRootDocument() {
            return rootDocument;
        }
    
        /**
         * @return the rootDocContent
         */
        public Element getRootDocContent() {
            return rootDocContent;
        }
    }
    
    

     

  2. Code the ListsRequest constructor. This will construct a generic “New”, “Update” or “Delete” CAML request. In order to avoid errors I’ve added some requestType control checks. Moreover, to keep the constructor signature simple, I made it initialize less relevant parameters automatically (like try to insert each item of the batch operation, even if one fails).
        /**
         * This class creates a generic XML SOAP request pre-formatted for SharePoint
         * Lists web services requests (aka CAML query). What remains to be added are
         * the specific parameters (XML Elements with attributes).
         * For an example of a CAML Doc http://msdn.microsoft.com/en-us/library/lists.lists.updatelistitems.aspx
         * @param requestType Either New, Update or Delete
         * @throws Exception
         */
        public ListsRequest(String requestType) throws Exception {
            if (requestType != null) {
                if (requestType.equals("New") || requestType.equals("Update") || requestType.equals("Delete")) {
                    try {
                        Element rootElement = null;
                        DocumentBuilder docBuilder = null;
                        DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
                        docBuilder = dbfac.newDocumentBuilder();
                        rootDocument = docBuilder.newDocument();
    
                        //Creates the root element
                        rootElement = rootDocument.createElement("Batch");
                        rootDocument.appendChild(rootElement);
    
                        //Creates the batch attributes
                        rootElement.setAttribute("ListVersion", "1");
                        rootElement.setAttribute("OnError", "Continue");
                        rootDocContent = rootDocument.createElement("Method");
                        rootDocContent.setAttribute("Cmd", requestType);
                        rootDocContent.setAttribute("ID", "1");
                        rootDocument.getElementsByTagName("Batch").item(0).appendChild(rootDocContent);
                    } catch (ParserConfigurationException ex) {
                        ex.printStackTrace();
                        throw (new Exception(ex.toString()));
                    }
                } else {
                    String err = "Unsupported request type";
                    throw (new Exception(err));
                }
            } else {
                String err = "Null parameters";
                throw (new Exception(err));
            }
        }
    
  3. Code the createListItem function. This function will inject a HashMap of attributes and their values into the ListsRequest CAML query, under an XML syntax.
        /**
         * Creates a SharePoint list item in the CAML format, and adds it to the rootRequest.
         * In SharePoint, this corresponds to a line in a list. The parameters given
         * here would correspond respectively to the name of the column where to
         * insert the info, and then the info itself.
         * The requestTypeElement should already be initialized before calling this
         * method.
         * XML example output:
         * < Field Name="ID" >4< Field >
         * < Field Name="Field_Name" >Value< /Field >
         * @param fields Contains a HashMap with attribute names as keys, and attributes
         * values as content
         * @return true if the item has been successfully added to the caml request
         */
        public boolean createListItem(HashMap<String, String> fields) {
            //params check
            if (fields != null && getRootDocContent() != null && this.getRootDocument() != null && !fields.isEmpty()) {
                Element createdElement = null;
                //Adds attribute by attribute to fields
                for (Map.Entry<String, String> aField : fields.entrySet()) {
                    createdElement = this.getRootDocument().createElement("Field");
                    createdElement.setAttribute("Name", aField.getKey());
                    Text attributeValue = getRootDocument().createTextNode("" + aField.getValue());
                    createdElement.appendChild(attributeValue);
                    this.getRootDocContent().appendChild(createdElement);
                }
                return true;
            }
            return false;
        }
    

     

  4. Code a higher level manager function. That’s from where we’ll authenticate, as well as decipher the error messages, and more importantly apply the business logic. This can be added in the Manager.java file. The example below is pretty basic doesn’t do basic existence checks, which means that the item will be inserted regardless if there’s already an item with the same attributes. It will however print the request in the console for debugging purposes (see the step 4 of my previous tutorial for the xmlToString function).
        /**
         * This function will insert the given item in the SharePoint that corresponds
         * to the list name given (or list GUID).
         * @param port an already authentificated SharePoint SOAP port
         * @param listName SharePoint list name or list GUID (guid must be enclosed in braces)
         * @param itemAttributes This represents the content of the item that need to be inserted.
         * The key represents the type of attribute (SharePoint column name) and the
         * value corresponds to the item attribute value.
         */
        public static void insertListItem(ListsSoap port, String listName, HashMap<String, String> itemAttributes) {
    
            //Parameters validity check
            if (port != null && listName != null && itemAttributes != null && !itemAttributes.isEmpty()) {
                try {
    
                    //Building the CAML query with one item to add, and printing request
                    ListsRequest newCompanyRequest = new ListsRequest("New");
                    newCompanyRequest.createListItem(itemAttributes);
                    System.out.println("REQUEST:"
                            + xmlToString(newCompanyRequest.getRootDocument()));
    
                    //initializing the Web Service operation here
                    Updates updates = new UpdateListItems.Updates();
    
                    //Preparing the request for the update
                    Object docObj = (Object) newCompanyRequest.getRootDocument().getDocumentElement();
                    updates.getContent().add(0, docObj);
    
                    //Sending the insert request to the Lists.UpdateListItems Web Service
                    UpdateListItemsResult result = port.updateListItems(listName, updates);
    
                    /*
                     *Printing the response in the console.
                     *If successful, the inserted item will be returned
                     */
                    System.out.println("RESPONSE : "
                            + xmlToString((org.w3c.dom.Document) (((ElementNSImpl) result.getContent().get(0)).getOwnerDocument())));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    

     

  5. Testing the code. Just put a few lines in main to test the whole thing. Note that if you have a column name that contains a space, you’ll have to replace the space character with _x0020_ in your attributes.
                 //Authentication parameters
                String userName = "yourusername";
                String password = "yourpassword";
                String sharePointListsWebServiceUrl = "https://yoursharepointsite.com/_vti_bin/Lists.asmx";
    
                //Opening the SOAP port of the Lists Web Service
                ListsSoap port = Manager.sharePointListsAuth(userName, password, sharePointListsWebServiceUrl);
    
                //Name or GUID (with braces) of the list
                String listName = "TempList";
    
               //Create the attributes with the format "Column name" => "value"
                HashMap<String, String> item = new HashMap<String,String>();
                item.put("Title", "Michael Drummond");
                item.put("Address", "USA");
    
                //If your column name has a space in it, replace the space with _x0020_
                item.put("Premium_x0020_customer", "1");
                Manager.insertListItem(port, listName, item);
    
  6. Updating or deleting an item is very similar; you just have to specify the “ID” of the List item (which can be extracted by reading the list first), just like we did in the previous step with the attributes.

 

That’s it!
Keep in mind that this is a simple example that’s not guaranteed to be appropriate for a production environment. For example, It would be interesting to tweak the code to do allow batch inserts/deletes as well as a transaction system that would be able to cache the requests in case of failure. I hope you found this post helpful.

Reading a SharePoint list with Java: tutorial

February 10, 2010 119 comments

Using external business data with SharePoint part 2: SharePoint Web Services and Java

In this tutorial I will show how to consume and use a SharePoint Lists Web Service from java with Netbeans. The objective will be to read the items of a SharePoint list from a java application. The functions coded in this tutorial will be needed later on if you’re trying to use external business data with SharePoint (my next post will describe how to the create/update/delete items in a list). Sounds pretty basic? Well, I haven’t found any other tutorials of this kind for Java, so enjoy!

SharePoint Java Application Netbeans Screenshot

Tutorial: reading a list

This tutorial has been tested Netbeans 6.8 and SharePoint Online, however any other Java IDE should be suitable. It should work with MOSS 2007 too (please let me know if it doesn’t). First of all, I’d recommend reading my previous post about the challenges to expect while coding such an application in Java. Before you begin, make sure you have a Sharepoint list that’s populated with a few items.

  1. Get the WSDL. Before launching Netbeans, you’ll need to download the Lists web service WSDL file with your browser to a local directory. The URL to your WSDL should look like: sharepointsite.com/_vti_bin/Lists.asmx?WSDL. The reason why you’ll download the WSDL instead of parsing it remotely from your Netbeans project is because you’ll want to avoid errors at build or run time. I tried with Netbeans 6.5, 6.7, 6.8, and encountered a variety of problems when I tried to access and parse the WSDL remotely (NTLM authentication errors, jaxb parsing errors, WSDL not found errors, etc)… Parsing it locally seems to be the simplest workaround to those Netbeans bugs complexities.
  2. Parse the WSDL. In order to use Sharepoints Web Services with Java, you will need to generate its stub classes with its WSDLs.
    • From Netbeans (easy): Open Netbeans and create a new Java Application. Right-click on your project and create a new Web Service Client, and choose your Lists WSDL file. Choose JAX-WS as Client Style. Click finish and that’s it. To make sure everything’s fine, clean and build your project.
    • From the console : If you’re not using Netbeans, you can generate the stub classes manually from the console, thanks to the JDK wsimport tool. Open the console (cmd.exe) and open the directory where your Lists.wsdl file is located. Run the following command to generate the classes in the directory (change the paths if necessary) “C:\Program Files\Java\jdk1.6.0_12\bin\wsimport.exe” -p com.microsoft.schemas.sharepoint.soap -keep -extension Lists.wsdl. Import those classes in your IDE.

  3. Code the SOAP authentication function. The first coding we’ll do is to create a Manager class that will take care of the Lists Web Service authentication and manipulation. If successful, it will return an open lists port (ListsSoap object) that will offer all the functions we need to use the Lists Web Service. Here’s the authentication function:
  4.     /**
         * Creates a port connected to the SharePoint Web Service given.
         * Authentication is done here. It also prints the authentication details
         * in the console.
         * @param userName SharePoint username
         * @param password SharePoint password
         * @return port ListsSoap port, connected with SharePoint
         * @throws Exception in case of invalid parameters or connection error.
         */
        public static ListsSoap sharePointListsAuth(String userName, String password) throws Exception {
            ListsSoap port = null;
            if (userName != null && password != null) {
                try {
                    Lists service = new Lists();
                    port = service.getListsSoap();
                    System.out.println("Web Service Auth Username: " + userName);
                    ((BindingProvider) port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, userName);
                    ((BindingProvider) port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
                } catch (Exception e) {
                    throw new Exception("Error: " + e.toString());
                }
            } else {
                throw new Exception("Couldn't authenticate: Invalid connection details given.");
            }
            return port;
        }
    

    Now that the auth code is made, you may call it from your main class to make sure the connection went fine. This code will display some information in the console in case of error.

  5. Code a function that’ll display XML docs in your console. Most of the time, SharePoint Web Services will return you a huge chunk of information in Microsoft’s own XML / CAML format. This is precisely what we’ll be interested in, as we’ll parse these Web Service responses later to display the lists items for instance. It’s very helpful to have such a function for debugging purposes. We’ll use the old school XML parsing tools embedded in the JDK for that job (javax.xml.transform).
  6.     /**
         * Creates a string from an XML file with start and end indicators
         * @param docToString document to convert
         * @return string of the xml document
         */
        public static String xmlToString(Document docToString) {
            String returnString = "\n-------------- XML START --------------\n";
            try {
                //create string from xml tree
                //Output the XML
                //set up a transformer
                TransformerFactory transfac = TransformerFactory.newInstance();
                Transformer trans;
                trans = transfac.newTransformer();
                trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
                trans.setOutputProperty(OutputKeys.INDENT, "yes");
                StringWriter sw = new StringWriter();
                StreamResult streamResult = new StreamResult(sw);
                DOMSource source = new DOMSource(docToString);
                trans.transform(source, streamResult);
                String xmlString = sw.toString();
                //print the XML
                returnString = returnString + xmlString;
            } catch (TransformerException ex) {
                Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
            }
            returnString = returnString + "-------------- XML END --------------";
            return returnString;
        }
    
  7. Code a function that’ll read your lists items. This function will send a getListItems request to the lists web service using the open ListsSoap port we created before. That’s the easy part! The challenging part is interpreting the dense Soap response, which has that infamous CAML structure. Basically, you have to cast the Web Service response into a classic XML document. That way, you can parse it with your favorite XML reader once you know what you’re looking for.
  8.     /**
         * Connects to a SharePoint Lists Web Service through the given open port,
         * and reads all the elements of the given list. Only the ID and the given
         * attributes (column names) are displayed, as well as a dump of the SOAP
         * response from the Web Service (for debugging purposes).
         * @param port an already authentificated SharePoint Online SOAP port
         * @param listName original name of the Sharepoint list that is going to be read
         * @param listColumnNames arraylist containing the various names of the Columns
         * of the SharePoint list that are going to be read. If the column name isn't
         * found, then an exception will be thrown
         * @param rowLimit limits the number of rows (list items) that are going to
         * be returned
         * @throws Exception
         */
        public static void displaySharePointList(ListsSoap port, String listName, ArrayList<String> listColumnNames, String rowLimit) throws Exception {
            if (port != null && listName != null && listColumnNames != null && rowLimit != null) {
                try {
    
                    //Here are additional parameters that may be set
                    String viewName = "";
                    GetListItems.ViewFields viewFields = null;
                    GetListItems.Query query = null;
                    GetListItems.QueryOptions queryOptions = null;
                    String webID = "";
    
                    //Calling the List Web Service
                    GetListItemsResponse.GetListItemsResult result = port.getListItems(listName, viewName, query, viewFields, rowLimit, queryOptions, webID);
                    Object listResult = result.getContent().get(0);
                    if ((listResult != null) && (listResult instanceof ElementNSImpl)) {
                        ElementNSImpl node = (ElementNSImpl) listResult;
    
                        //Dumps the retrieved info in the console
                        Document document = node.getOwnerDocument();
                        System.out.println("SharePoint Online Lists Web Service Response:" + Manager.xmlToString(document));
    
                        //selects a list of nodes which have z:row elements
                        NodeList list = node.getElementsByTagName("z:row");
                        System.out.println("=> " + list.getLength() + " results from SharePoint Online");
    
                        //Displaying every result received from SharePoint, with its ID
                        for (int i = 0; i < list.getLength(); i++) {
    
                            //Gets the attributes of the current row/element
                            NamedNodeMap attributes = list.item(i).getAttributes();
                            System.out.println("******** Item ID: " + attributes.getNamedItem("ows_ID").getNodeValue()+" ********");
    
                            //Displays all the attributes of the list item that correspond to the column names given
                            for (String columnName : listColumnNames) {
                                String internalColumnName = "ows_" + columnName;
                                if (attributes.getNamedItem(internalColumnName) != null) {
                                    System.out.println(columnName + ": " + attributes.getNamedItem(internalColumnName).getNodeValue());
                                } else {
                                    throw new Exception("Couldn't find the '" + columnName + "' column in the '" + listName + "' list in SharePoint.\n");
                                }
                            }
                        }
                    } else {
                        throw new Exception(listName + " list response from SharePoint is either null or corrupt\n");
                    }
                } catch (Exception ex) {
                    throw new Exception("Exception. See stacktrace." + ex.toString() + "\n");
                }
            }
        }
    
  9. Test the whole thing!
  10. Everything should be ready. Let’s test it from main (of course replace the necessary values with your own).

        public static void main(String[] args) {
            try {
    
                //Authentication parameters
                String userName = "yourUsername";
                String password = "yourPassword";
    
                //Opening the SOAP port of the Lists Web Service
                ListsSoap port = Manager.sharePointListsAuth(userName, password);
    
                /*
                 * Lists Web service parameters
                 * The list names below must be the *original* names of the list.
                 * if a list or column was renamed from SharePoint afterwards,
                 * these parameters don't change.
                 */
                String listName = "Client";
                String rowLimit = "150";
                ArrayList<String> listColumnNames = new ArrayList<String>();
                listColumnNames.add("Title");
                listColumnNames.add("otherColumnName");
    
                //Displays the lists items in the console
                Manager.displaySharePointList(port, listName, listColumnNames, rowLimit);
            } catch (Exception ex) {
                System.err.println(ex);
            }
        }
    

    This is it!I hope you found this post useful. Any thoughts? I’d be happy to hear your feedback. You can download the full source code covered in this tutorial here.

    Update 26 February 2010: Removed unnecessary web service URL in the authentication code (thanks Claus Fassing!)