Skip to main content

Fifty ways to leave your bookmark: An experiment in social authoring

Frank Jania, Technical Evangelist, IBM
Frank Jania is currently the Technical Evangelist for IBM's Real Time Collaboration and Social Computing Technologies. Take a look at his social software blog.
Sacha Chua (sachac@ca.ibm.com), Application Developer, Web Technologies, IBM
Sacha Chua (sachac@ca.ibm.com) is a technical evangelist, storyteller, and geek. Her personal blog is at http://sachachua.com .
Axel Magard (axel_magard@de.ibm.com), Project Manager, IBM
Axel Magard (axel_magard@de.ibm.com) is a project manager who sometimes also loves to do some computer programming. You can read his personal blog.
Jeff Lowrey (jlowrey@us.ibm.com), Application Developer, IBM
Jeff Lowrey (jlowrey@us.ibm.com) works for IBM Software Services for WebSphere as a Message Broker and MQ consultant and posts way too much, but not enough to his blog.
Andy Piper (andy.piper@uk.ibm.com), WebSphere Consultant, IBM
Andy Piper (andy.piper@uk.ibm.com) is a consultant working in IBM Software Services for WebSphere in the UK. His personal blog is at http://andypiper.co.uk/ .
Suzanne O Minassian (minassian@us.ibm.com), Product manager, IBM Lotus Connections, IBM
Suzanne O Minassian (minassian@us.ibm.com) is the product manager for Lotus Connections. Her landing page is http://www.tekmoda.com .
Dave Griffiths (dgriff@uk.ibm.com), Software Developer, IBM
Dave Griffiths (dgriff@uk.ibm.com) is a Java service drone. His home page is http://w3.hursley.ibm.com/~dgriff .
Chris Gambrell (chris_gambrell@us.ibm.com), Software Architect, IBM
Chris Gambrell (chris_gambrell@us.ibm.com) is a software architect for IBM Lotus Sametime and other real-time collaboration projects.
Adam Reed (reedna@us.ibm.com) is an intern/soon-to-be part-time web developer for IBM Lotus Connections - Activities.
Bill Grant (billgrant@us.ibm.com), Technical Sales manager, IBM
Bill Grant (billgrant@us.ibm.com) is a technical sales manager for IBM Rational Software on Wall Street. His personal blog is at http://billgrant.org .
Caroline Maynard (caroline.maynard@uk.ibm.com), Strategy Scenario Analyst, IBM
Caroline Maynard (caroline.maynard@uk.ibm.com) is a software engineer at the IBM Laboratory in Hursley, England, who has recently worked on open-source extensions for PHP.

Summary:  Last year, a pool of potential authors were challenged to write an example of code, each from a different programming language, using the Atom Publishing Protocol (AtomPub) and Dogear as the AtomPub-enabled service. This article presents the results of this unique social authoring experiment.

Date:  06 May 2008 (Published 08 Apr 2008)
Level:  Intermediate
Activity:  3477 views

"The problem's all inside your code," she said to me
"The answer is easy if you take it logically
I'd like to help you in your struggle to be free
There must be fifty ways to leave your bookmark...”

Introduction

Fifty ways to leave your bookmark was an experiment in social authoring and a challenge to see whether a developerWorks® article could be generated in a fixed time frame. The experiment and the article were explained and kicked off with an email to potential participants:

Fifty Ways to Leave Your Bookmark - You are invited to participate!

The ultimate goal of this experiment is to have a group of people contribute the content for a developerWorks article, in the span of one day, that shows how to use Atom Publishing Protocol (AtomPub) from as many programming languages as possible. To build on the momentum of several articles about the Lotus Connections API, we'll use Dogear as our AtomPub-enabled service.

Anyone and everyone who would like to join the effort is welcome – everyone who contributes will be recognized as a co-author.

We'll take entries at any time that it's Friday, 10 Aug 2007 somewhere in the world. So accounting (roughly) for some zigs and zags in the International Date Line and for Daylight Saving time, let’s say from midnight in Kiritimati (6:00am EDT, Thursday, 10 Aug) to midnight in Honolulu (6:00am EDT, Saturday, 12 Aug).

If you'd like to contribute an example to the article, go to the Fifty ways to leave your bookmark wiki, review the instructions, and add your example.

We’re looking for examples in languages such as Ruby, PHP, Java, Python, Flash ActionScript, C#, LotusScript, and JavaScript. But we'll also want to show how versatile a service that exposes an APP API can be. If you can pull it off in APL, COBOL, PL/1, PostScript, or another language , go ahead.

We used an internal wiki for collecting everyone’s submissions and for posting the instructions for the authors. The overview instructions were as follows:

You (the contributing author) will stake your claim to cover a language by adding a new wiki page, starting from 10 (adding 1 for each additional language) and noting the name of the language, for example, “10 - Java.” Follow the format that shows how to post the bookmark in the language you have chosen. You can choose as many languages as you like; just put each one on a separate page.

The authors also needed to know what specifically they would have to code to show an example AtomPub call on the Dogear server, so they were given these instructions as well:

The AtomPub Call Format

We’ll be making the same call in each language. We'll programmatically bookmark the Lotus Connections home page (http://ibm.com/lotus/connections), tag it with "lotus," "connections," and "50WaysToLeaveYourBookmark," set the description to "I posted this from <language>" and the title to "The Lotus Connections Page."

Since an AtomPub call is really just an HTTP call, here is the raw format of the data that we'll be passing to the server:

POST /dogear/api/app?email=user@company.com HTTP/1.1
Host: www.company.com
Content-Type: application/atom+xml
Authorization: Basic RG9uIFA1aXhvdAAAAm9jaW5hAARl

<?xml version="1.0" encoding="utf-8"?>
 <entry xmlns="http://www.w3.org/2005/Atom">
  <author><name>Author</name></author>
  <title>The Lotus Connections Page</title>
  <content type="html"><![CDATA[I posed this from <language>]]>
  </content>
  <category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="bookmark" />
  <category term="lotus" />
  <category term="connections" />
  <category term="50WaysToLeaveYourBookmark" />
  <link href="http://www.ibm.com/lotus/connections" />
 </entry>

With that, the challenge was set forward. Each author selected a programming language and wrote an example that posts a bookmark on a running Dogear server. They posted the same link, with a mention of the language from which it was posted, in the bookmark's description (see figure 1).


Figure 1. Example bookmark description
Example bookmark description

After the day was finished, we had fewer entries than we would have liked, so we extended the deadline until the following week.

All the examples that follow in this article represent language-specific ways to make this call.

For more details about the Dogear API and the AtomPub protocol, refer to the developerWorks article, “Deploying IBM Lotus Connections: Integrating with other systems.”


Code samples

What follows are the 17 samples collected over the designated period during which authors had to submit their samples. Each sample contains the language used, any libraries that were relied on, any comments by the author, and, of course, the code itself.

The examples below work with Dogear 1.0.x and are a good starting point for accessing data in the other Lotus Connections services. Please note, however, that the Lotus Connections Activities 1.0.2 API requires that you set the user-agent field in your requests.


Java
by James Snell (via snellspace.com)

Libraries used

Apache Abdera - Atom parsing and generation

Code

Abdera abdera = new Abdera();
Client client = new CommonsClient(abdera);
client.addCredentials("http://dogear.tap.ibm.com/api/app", null, null, new 
   UsernamePasswordCredentials("userid","password"));

ClientResponse resp = client.get("http://dogear.tap.ibm.com/api/app");
Document<Service> service_doc = resp.getDocument();
Service service = service_doc.getRoot();
Collection collection = service.getCollection("My Bookmarks", "Entries");
String coll_uri = collection.getResolvedHref().toASCIIString();

Entry entry = abdera.newEntry();
entry.setId("");            //ignored by the server, required by APP
entry.addAuthor("james"); //ignored by the server, required by APP
entry.addLink("http://ibm.com/lotus/connections"); // the url being bookmarked
entry.setTitle("The Lotus Connections Page");
entry.setContentAsHtml("I posted this from Java");
entry.addCategory("lotus");
entry.addCategory("connections");
entry.addCategory("50WaysToLeaveYourBookmark");
// optional in dogear
entry.addCategory("http://www.ibm.com/xmlns/prod/sn/type","bookmark",null);

resp = client.post(coll_uri, entry);

switch(resp.getType()) {
   case SUCCESS:
      String location = resp.getLocation().toASCIIString();
      System.out.println("New entry created at: " + location);
      break;
   default:
      System.out.println("Error: " + resp.getStatusText());
}


Java
by Dave Griffiths

Libraries used

None

Code

import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import javax.net.*;

/* Bare metal Java version! */

public class Bookmark {
    public static void main(String[] args) throws Exception {
        SocketFactory factory = SSLSocketFactory.getDefault();
        Socket socket = factory.createSocket("dogear.tap.ibm.com", 443);
        OutputStreamWriter out = 
        new OutputStreamWriter(socket.getOutputStream(), "UTF8");
        out.write("POST /api/app?email=dgriff@uk.ibm.com HTTP/1.1\r\n");
        out.write("Host: www.ibm.com\r\n");
        String encoding = 
        new sun.misc.BASE64Encoder().encode("dgriff@uk.ibm.com:password".getBytes());
        out.write("Authorization: Basic " + encoding + "\r\n");
        String data = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
            "<entry xmlns=\"http://www.w3.org/2005/Atom\">\r\n" +
            "<author><name>Author</name></author>\r\n" +
            "<title>The Lotus Connections Page</title>\r\n" +
            "<content type=
            \"html\"><![CDATA[I posted this from Java]]></content>\r\n" +
            "<category scheme=\"http://www.ibm.com/xmlns/prod/sn/type\" 
            term=\"bookmark\" />\r\n" +
            "<category term=\"lotus\" />\r\n" +
            "<category term=\"connections\" />\r\n" +
            "<category term=\"50WaysToLeaveYourBookmark\" />\r\n" +
            "<link href=\"http://www.ibm.com/lotus/connections\" />\r\n" +
            "</entry>\r\n";
        out.write("Content-Length: " + data.length() + "\r\n");
        out.write("Content-Type: application/atom+xml\r\n");
        out.write("\r\n");
        out.write(data);
        out.flush();
        BufferedReader in = 
        new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            System.out.println(line);
        }
    }
}


PHP with cURL and xmlwriter
by Caroline Maynard

There are many ways to do this with PHP. For the purposes of this article, let’s look at a straightforward use of cURL using PHP.

The code looks longer than some examples because the XML was created programmatically through a general-purpose "create a dogear bookmark" function. If you prefer, you could reduce this to a couple of lines to include canned XML from a file or by use of a heredoc.

It was found that the CURLOPT_SSL_VERIFYPEER setting was needed to avoid the following error:

“Got 60 : SSL certificate problem, verify that the CA cert is OK.
Details: error:14090086:SSL
routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed.”

Libraries used

PHP 5.1.x with the built-in extensions for cURL and xmlwriter.

Code

<?php

try {

  $target = "https://dogear.tap.ibm.com/api/app/?email=caroline.maynard%40uk.ibm.com";
  $user = "caroline.maynard@uk.ibm.com";
  $passwd = "<password>";

  $xml = create_entry_xmlwriter();

  $headers = array("Content-Type: application/atom+xml ");
  $handle  = curl_init($target);
  $curlopt_array = array(
     CURLOPT_HTTPHEADER => $headers,
     CURLOPT_POST => true,
     CURLOPT_POSTFIELDS => $xml,
     CURLOPT_SSL_VERIFYPEER => false,
     CURLOPT_USERPWD => $user.':'.$passwd,
     CURLOPT_FOLLOWLOCATION => true);
   curl_setopt_array($handle, $curlopt_array);

   $result = curl_exec($handle);

   if ($result === false) {
     print "Got " . curl_errno($handle) . " : " . curl_error($handle) . "\n";
     curl_close ($handle);
     return;
   }

   $response_http_code = curl_getinfo ($handle, CURLINFO_HTTP_CODE);
   if ($response_http_code != 201) {
     print("HTTP status code: $response_http_code \n");
     curl_close($handle);
     return;
   }

   curl_close($handle);

} catch (Exception $e) {
  print $e;
}

function create_entry_xmlwriter($author = "Caroline Maynard",
  $title = "The Lotus Connections Page",
  $link = "http://www.ibm.com/lotus/connections",
  $categories = array('lotus', 'connections', '50WaysToLeaveYourBookmark')) {

  $xmlwriter = new XMLWriter();
  $xmlwriter->openMemory();
  $xmlwriter->startDocument("1.0", "UTF-8");
  $xmlwriter->startElement('entry');
  $xmlwriter->writeAttribute('xmlns', 'http://www.w3.org/2005/Atom');
  $xmlwriter->startElement('author');
  $xmlwriter->writeElement('name', $author);
  $xmlwriter->endElement();
  $xmlwriter->writeElement('title', $title);
  $xmlwriter->startElement('link');
  $xmlwriter->writeAttribute('href', $link);
  $xmlwriter->endElement();
  $xmlwriter->startElement('content');
  $xmlwriter->writeAttribute('type', 'html');
  $xmlwriter->text('I posted this from PHP');
  $xmlwriter->endElement();

  $xmlwriter->startElement('category');
  $xmlwriter->writeAttribute('term', 'bookmark');
  $xmlwriter->writeAttribute('scheme', 'http://www.ibm.com/xmlns/prod/sn/type');
  $xmlwriter->endElement();

  if ($categories) {
	$categories = (array)$categories;
	foreach ($categories as $category) {
	  $xmlwriter->startElement('category');
	  $xmlwriter->writeAttribute('term', $category);
	  $xmlwriter->endElement();
	}
  }

  $xmlwriter->endElement();
  $xmlwriter->endDocument();
  return $xmlwriter->outputMemory();
}

?>


Ruby
by Sacha Chua

Code

#!/usr/bin/ruby
require 'rexml/document'
require 'rexml/cdata'
require 'net/http'
require 'net/https'
require 'uri'

user = 'user@example.com'
password = 'password'

url = URI.parse('https://dogear.tap.ibm.com:443/api/app')

# Create the XML document
doc = REXML::Document.new('<entry xmlns="http://w3.org/2005/Atom"/>')
r = doc.root
r.add_element('author').add_element('name').text = 'Sacha Chua'
r.add_element('title').text = 'The Lotus Connections Page'
content = r.add_element 'content', { 'type' => 'html' }
content.text = REXML::CData.new('I posted this from Ruby')
r.add_element('category',
   { 'term' => 'bookmark',
     'scheme' => 'http://www.ibm.com/xmlns/prod/sn/type' })
r.add_element 'category', { 'term' => 'lotus' }
r.add_element 'category', { 'term' => 'connections' }
r.add_element 'category', { 'term' => '50WaysToLeaveYourBookmark' }
r.add_element 'link', { 'href' => 'http://www.ibm.com/lotus/connections' }
doc.add(REXML::XMLDecl.new('1.0', 'UTF-8'))


http = Net::HTTP.new(url.host, url.port)
# Post the document
req = Net::HTTP::Post.new(url.path + '?email=' + user)
req.basic_auth user, password
req['Content-Type'] = 'application/atom+xml'
req.body = doc.to_s
http.use_ssl = true
http.start do |http|
  response = http.request(req)
  case response
  when Net::HTTPSuccess
    puts "Posted!"  + response.body
  else
    response.error!
  end
end


JavaScript
by Adam N. Reed

Libraries used

None

Code

//Construct a standard XMLHttpRequest Object for Mozilla Firefox or Internet Explorer
var request = false;
try {
  request = new XMLHttpRequest();
} catch (trymicrosoft) {
  try {
    request = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (othermicrosoft) {
    try {
      request = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (failed) {
      request = false;
    }
  }
}
if (!request) {
    alert("Error initializing XMLHttpRequest!");
}

//Construct the XML to be sent in the request as a string
//The string is split and concatenated here for clarity. 
var postXML = '<?xml version="1.0" encoding="utf-8"?>'
  +'<entry xmlns="http://www.w3.org/2005/Atom">'
  +'<author><name>Author</name></author>'
  +'<title>The Lotus Connections Page</title>'
  +'<content type="html">I posted this from JavaScript</content>'
  +'<category scheme="http://www.ibm.com/xmlns/prod/sn/type" term="bookmark" />'
  +'<category term="lotus" />'
  +'<category term="connections" />'
  +'<category term="50WaysToLeaveYourBookmark" />'
  +'<link href="http://www.ibm.com/lotus/connections" />'
  +'</entry>';

var postURL = "http://www.company.com/dogear/api/app";

request.open("POST",postURL,true,"userid","password");
request.setRequestHeader("Content-type", "application/atom+xml");
request.setRequestHeader("Content-length", postXML.length);
request.setRequestHeader("Connection", "close");
request.onreadystatechange = postResponse;
request.send(postXML);

function postResponse() {
    //Check for success: HTTP 201 - Created 
    if (request.readyState == 4) {
        if(request.status == 201) {
            //Activity successfully created
            //Do any post-processing here...
        } else {
            alert("Error: " + request.status + " - " + request.statusText);
            //Further error processing...
        }
    }
}


Perl
by Axel Magard

Libraries used

XML::Generator - XML Generator

LWP::UserAgent - Library for WWW in Perl

Code

require LWP::UserAgent;
  use LWP::Debug qw(+ -conns);
  
  my $user = "axel_magard\@de.ibm.com";
  my $pw = "xxxxxxxx";
  my $server = "dogear.tap.ibm.com";
  my $url = "http://".$server."/api/app";
  my $port = "443";
  
  # Create a user object ...
  my $ua = LWP::UserAgent->new;
  $ua->agent("MyBookmark/0.1 ");
  $ua->credentials($server.':'.$port, 'Dogear', $user, $pw );
  push @{ $ua->requests_redirectable }, 'POST';   # Avoid the 302 return code
  
  # Create a request ...  
  my $req = HTTP::Request->new(POST => $url);
  
  use XML::Generator ':pretty';
  
  # Build XML document ...
  my $gen = XML::Generator->new(':pretty', 
  namespace => ["http://www.w3.org/2005/Atom"]);
  $content = sprintf $gen->xml($gen->entry( $gen->author("Axel Magard"),
        $gen->title("The Lotus Connections Page"),
		$gen->content({type => 'html'},"I posted this from Perl."),
		$gen->category({scheme => "http://www.ibm.com/xmlns/prod/sn/type",
		term => "bookmark"}),
		$gen->category({term=>"lotus"}),	
		$gen->category({term=>"connections"}),		
		$gen->category({term=>"50WaysToLeaveYourBookmark"}),
		$gen->link({href=>"http://www.ibm.com/lotus/connections"})	
  )
  );
  
  
  # Set request content
  $req->content_type('application/atom+xml');
  $req->content($content);
  
  # Pass request to the user agent and get a response back
  my $res = $ua->request($req);

  # Check the outcome of the response
  if ($res->is_success) {
      print "Bookmark posted.\n";
  }
  else {
      print $res->status_line, "\n";
  }


ActionScript
by Darren Shaw

Libraries used

None

Code

var xmlString = '<?xml version="1.0" encoding="utf-8"?>'
+'<entry xmlns="http://www.w3.org/2005/Atom">'
+'<author><name>Author</name></author>'
+'<title>The Lotus Connections Page</title>'
+'<content type="html"><\!\[CDATA\[I posed this from 
ActionScript\]\]></content>'
+'<category scheme="http://www.ibm.com/xmlns/prod/sn/type" 
term="bookmark" />'
+'<category term="lotus" />'
+'<category term="connections" />'
+'<category term="50WaysToLeaveYourBookmark" />'
+'<link href="http://www.ibm.com/lotus/connections" />'
+'</entry>';
// create new xml object from xml string
var xml:XML = new XML(xmlString);

// set content type
xml.contentType = "application/atom+xml";

// send to server and show result in new browser window
xml.send("https://dogear.tap.ibm.com/api/app", "_blank");


Shell script / command line
by Andy Piper (http://andypiper.co.uk )

Libraries used

cURL - a command line tool for HTTP

It is possible to invoke the APP API from various shell scripting environments by posting a file with the correct Atom XML format using cURL.

Code

curl -u "andy.piper@uk.ibm.com:passw0rd" -X POST -H 'Content-Type:application/atom+xml'
     --data-binary @atomfile.xml https://dogear.tap.ibm.com/api/app?
     email=andy.piper@uk.ibm.com


Through shell using wget
by Brian Olore (bolore@us.ibm.com)

Libraries used

wget - GNU Wget is a free software package for retrieving files using HTTP, HTTPS and FTP, the most widely-used Internet protocols.

Code

Create a bookmark - wget
wget --header="Content-type: application/atom+xml" --post-file=content.txt 
      --http-user=bolore@us.ibm.com --http-password=passw0rd
      "https://dogear.tap.ibm.com/api/app?email=bolore@us.ibm.com"


Message Broker and ESQL
by Jeff Lowrey

Use a basic Compute Node, with ComputeMode set to Message And Local Environment. Connect this Compute Node to an HTTPRequest node. You'll need to set the URL on the HTTPRequest node to something - it doesn't really matter what. You'll also need to put in some kind of an Input node to start the flow. I used an MQInput node, but it doesn't matter. One could ideally create user and password as UserDefinedProperties, so that they would be set by the admin at deployment time.

Code

DECLARE user CHARACTER;
DECLARE password CHARACTER;

CALL CopyMessageHeaders();
-- CALL CopyEntireMessage();

SET user = 'user';
SET password = 'password';

SET OutputRoot.MQMD = NULL;
SET OutputRoot.Properties.MessageDomain = 'XMLNS';

-- set the HTTP destination URL, and various HTTP headers
-- these will be used by the HTTPRequest node
SET OutputLocalEnvironment.Destination.HTTP.RequestURL = 
'https://dogear.tap.ibm.com/api/app?email='||user;
SET OutputRoot.HTTPRequestHeader."Content-Type"= 'application/atom+xml';
SET OutputRoot.HTTPRequestHeader."Authorization" = 
'Basic '||b64Encode(CAST(user||':
'||password as BLOB CCSID InputRoot.Properties.CodedCharSetId));

-- create the message body which contains the Atom
-- format XML required to create the bookmark
SET OutputRoot.XMLNSC.(XMLNSC.XmlDeclaration)*.(XMLNSC.Attribute)Version = '1.0';
SET OutputRoot.XMLNSC.(XMLNSC.XmlDeclaration)*.(XMLNSC.Attribute)Encoding = 'UTF-8';
SET OutputRoot.XMLNSC.entry.author.name='Jeff Lowrey';
SET OutputRoot.XMLNSC.entry.(XMLNSC.NamespaceDecl)xmlns:xmlns = 
'http://www.w3.org/2005/Atom';

DECLARE outRef REFERENCE TO OutputRoot.XMLNSC.entry;

SET outRef.title='The Lotus Connections Page';
SET outRef.(XMLNSC.CDataField)content = 'I posted this from Message Broker using ESQL';
SET outRef.content.(XMLNSC.Attribute)"type" = 'html';
SET outRef.category[1].(XMLNSC.Attribute)"scheme" = 
'http://www.ibm.com/xmlns/prod/sn/type';
SET outRef.category[1].(XMLNSC.Attribute)"term" = 'bookmark';
SET outRef.category[2].(XMLNSC.Attribute)"term" = 'lotus';
SET outRef.category[3].(XMLNSC.Attribute)"term" = 'connections';
SET outRef.category[4].(XMLNSC.Attribute)"term" = 
'50WaysToLeaveYourBookmark';
SET outRef.link.(XMLNSC.Attribute)"href"='http://www.ibm.com/lotus/connections';

There's an additional declaration needed, in the ESQL file but outside the Compute module. It allows you to leverage a built-in base64 encoding routine, which is used in setting up the HTTP Basic Auth values in the header.

CREATE PROCEDURE b64Encode(IN source BLOB) 
RETURNS CHARACTER 
LANGUAGE JAVA 
EXTERNAL NAME "com.ibm.broker.javacompute.Base64.encode";


AppleScript
by Andy Piper (http://andypiper.co.uk)

Libraries used

cURL - a command line tool for HTTP (which happens to be built in to OS X)

XML Tools Scripting Addition - extension for building XML in AppleScript

Code

set outputfile to (((path to desktop) as string) & "atomentry.xml")
as file specification
set atomfile to POSIX path of outputfile as text

-- NB the XML tools extension does not support CDATA so the content is
typed "text" rather than "html"
-- also can't use an attribute named 'scheme' as it seems to get generated strangely
set theXML to 
	{class:XML element, XML tag:"entry", 
	XML attributes:{xmlns:"http://www.w3.org/2005/Atom"}, XML contents:{
{class:XML element, XML tag:"author", XML contents:
{class:XML element, XML tag:"name", XML contents:{
	"Author"}}}, 
	{class:XML element, XML tag:"title", XML contents:{"The Lotus
	Connections Page"}},
	{class:XML element, XML tag:"content", XML attributes:{type:"text"},
	XML contents:{"I posted this from Applescript"}}, 
	{class:XML element, XML tag:"category", XML attributes:{term:"bookmark"}},
	{class:XML element, XML tag:"category", XML attributes:{term:"lotus"}}, 
	{class:XML element, XML tag:"category", XML attributes:{term:"connections"}},
	{class:XML element, XML tag:"category", XML
	attributes:{term:"50WaysToLeaveYourBookmark"}},
	{class:XML element, XML tag:"link", XML
	attributes:{href:"http://www.ibm.com/lotus/connections"}}}}

generate XML theXML saving as (outputfile) with generating UTF8

set results to do shell script "curl --user 'andy.piper@uk.ibm.com:passw0rd' -X
POST -H 'Content-Type:application/atom+xml' --data-binary @" & atomfile &
"https://dogear.tap.ibm.com/api/app?email=andy.piper@uk.ibm.com"

if results = "" then
	set results to "Successfully published the bookmark"
end if

display dialog results buttons "OK"

-- delete the generated Atom XML file to clean up
tell application "Finder"
	delete file outputfile
end tell


ColdFusion 8.0
by Suzanne Minassian

Code

<cfxml variable="postMe">
	<?xml version="1.0" encoding="utf-8"?>
		  <entry xmlns="http://www.w3.org/2005/Atom">
		  <author><name>Author</name></author>
		  <title>The Lotus Connections Page</title>
		  <content type="html"><![CDATA[I posted this from 
		  ColdFusion]]></content>
		  <category scheme="http://www.ibm.com/xmlns/prod/sn/type" 
		  term="bookmark" />
		  <category term="lotus" />
		  <category term="connections" />
		  <category term="50WaysToLeaveYourBookmark" />
		  <link href="http://www.ibm.com/lotus/connections" />
	 </entry>
</cfxml>

<cfhttp
	method="POST"
	url="https://dogear.tap.ibm.com/api/app/?email=minassian@us.ibm.com"
	username="minassian@us.ibm.com"
	password="myPasswordHere">

	<cfhttpparam
	   type = "XML"
	   value = "#postMe#">

</cfhttp>


VB.NET
by Ben Rubinger

Libraries used

Microsoft® .NET Framework 2.0

Code

Module Module1

    Sub Main()
        Dim mymemstream As New System.IO.MemoryStream()
        Dim mystreamwriter As New System.IO.StreamWriter(mymemstream)

        Dim mywriter As New System.Xml.XmlTextWriter(mystreamwriter)

        mywriter.WriteStartDocument()
        mywriter.WriteStartElement("entry", "")
        mywriter.WriteAttributeString("xmlns", "http://www.w3.org/2005/Atom")

        mywriter.WriteStartElement("author")
        mywriter.WriteElementString("name", "Ben Rubinger")
        mywriter.WriteEndElement()

        mywriter.WriteElementString("title", "The Lotus Connections Page")

        mywriter.WriteStartElement("content", "")
        mywriter.WriteAttributeString("type", "html")
        mywriter.WriteValue("I posted this from VB.NET")
        mywriter.WriteEndElement()

        mywriter.WriteStartElement("category", "")

        mywriter.WriteAttributeString("scheme", "http://www.ibm.com/xmlns/prod/sn/type")
        mywriter.WriteAttributeString("term", "bookmark")
        mywriter.WriteEndElement()

        mywriter.WriteStartElement("category")
        mywriter.WriteAttributeString("term", "lotus")
        mywriter.WriteEndElement()

        mywriter.WriteStartElement("category")
        mywriter.WriteAttributeString("term", "connections")
        mywriter.WriteEndElement()

        mywriter.WriteStartElement("category")
        mywriter.WriteAttributeString("term", "50WaysToLeaveYourBookmark")
        mywriter.WriteEndElement()

        mywriter.WriteStartElement("link", "")
        mywriter.WriteAttributeString("href", "http://www.ibm.com/lotus/connections")
        mywriter.WriteEndElement()

        mywriter.WriteEndElement()
        mywriter.WriteEndDocument()

        mywriter.Flush()

        Dim myrequest As System.Net.HttpWebRequest = 
        System.Net.WebRequest.Create
        ("http://dogear.tap.ibm.com/api/app?email=rubinger@us.ibm.com")

        myrequest.Method = "POST"
        Dim mycredentials As New System.Net.NetworkCredential
        ("rubinger@us.ibm.com", "********")
        myrequest.Credentials = mycredentials
        myrequest.ContentType = "application/atom+xml"
        myrequest.ContentLength = mymemstream.Length

        Dim poststream As IO.Stream
        Try
            poststream = myrequest.GetRequestStream()
            poststream.Write(mymemstream.GetBuffer(), 0, mymemstream.Length)
        Catch ex As Exception

        Finally
            If Not poststream Is Nothing Then poststream.Close()
        End Try
        mywriter.Close()
    End Sub

End Module


C#
by Chris Gambrell

Libraries used

Microsoft .NET Framework

Code

using System;
using System.Net;
using System.IO;
using System.Text;

namespace ConsoleApplication1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
  WebResponse webResponse = null;

  NetworkCredential credentials = new NetworkCredential();
  credentials.UserName = "chris_gambrell@us.ibm.com";
  credentials.Password = "passw0rd";

  string bookmark = 
    "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
    "<entry xmlns=\"http://www.w3.org/2005/Atom\">" +
    "<author><name>Author</name></author>" +
    "<title>The Lotus Connections Page</title>" +
    "<content type=
    \"html\"><![CDATA[I posted this from C#]]></content>" +
    "<category scheme=\"http://www.ibm.com/xmlns/prod/sn/type\" term=
    \"bookmark\" />" +
    "<category term=\"lotus\" />" +
    "<category term=\"connections\" />" +
    "<category term=\"50WaysToLeaveYourBookmark\" />" +
    "<link href=\"http://www.ibm.com/lotus/connections\" />" +
    "</entry>";

  try
  {
    WebRequest request = WebRequest.Create
    ("https://dogear.tap.ibm.com/api/app?email=chris_gambrell@us.ibm.com");

    request.Method = "POST";

    byte[] byteArray = Encoding.UTF8.GetBytes(bookmark);
                
    request.ContentType = "application/atom+xml";
                              
    request.ContentLength = byteArray.Length;
                           
    if (credentials != null)
    request.Credentials = credentials;

    Stream requestStream = request.GetRequestStream();
    requestStream.Write(byteArray, 0, byteArray.Length);
    requestStream.Close();
                
    webResponse = request.GetResponse();
    if (webResponse == null) 
    {
      Console.WriteLine("response is null");
    }
	  else
	    {
	    StreamReader responseReader = new StreamReader(webResponse.
	    GetResponseStream(), Encoding.UTF8);
      Console.WriteLine("response = " + responseReader.ReadToEnd().Trim());
    }
  }
  catch (Exception e)
  {
    Console.WriteLine("Exception: " + e);
  }
  finally
  {
    if (webResponse != null)
    {
      webResponse.Close();
   }
  }           
	}
	}
}


Groovy
by Andy Piper (http://andypiper.co.uk)

Libraries used

Groovy

Apache Commons HttpClient - included with Groovy, but need to add commons-codec-1.3.jar to the Groovy lib directory

Code


import groovy.xml.StreamingMarkupBuilder
import org.apache.commons.httpclient.*
import org.apache.commons.httpclient.methods.*

def xml = new StreamingMarkupBuilder().bind{
  mkp.yieldUnescaped '<?xml version="1.0" encoding="UTF-8"?>\n'
  entry(xmlns:"http://www.w3.org/2005/Atom") {
    author()  {
        name 'Andy Piper'
        }
    title 'The Lotus Connections Page'
    content(type:'html') {  
     mkp.yieldUnescaped '<![CDATA[' 
     mkp.yieldUnescaped 'I posted this from Groovy'    
     mkp.yieldUnescaped ']]>'
     }
    category(scheme:'http://www.ibm.com/xmlns/prod/sn/type', term:'bookmark')
    category(term:'lotus')
    category(term:'connections')
    category(term:'50WaysToLeaveYourBookmark')
    link(href:'http://www.ibm.com/lotus/connections')
    }
}

println xml.toString()

username = "andy.piper@uk.ibm.com"
password = "passw0rd"
url = "https://dogear.tap.ibm.com/api/app?email=andy.piper@uk.ibm.com"

creds = new UsernamePasswordCredentials(username, password)

client = new HttpClient()
client.getState().setCredentials(null, null, creds)

post = new PostMethod(url)
post.setRequestHeader('Content-Type','application/atom+xml')
post.setRequestBody(xml.toString())

status = client.executeMethod( post )

println(status + "\n" + post.getResponseBodyAsString())

post.releaseConnection()


VBScript
by Jeff K. Wilson

Code

url="https://dogear.tap.ibm.com/api/app"

entry = "<?xml version='1.0' encoding='utf-8'?>" &_
        "<entry xmlns='http://www.w3.org/2005/Atom'>" &_
        "<author><name>Author</name></author>" &_
        "<title>The Lotus Connections Page</title>" &;_
        "<content type='html'>I posted this from VBScript</content>" &_
        "<category scheme='http://www.ibm.com/xmlns/prod/sn/type' 
        term='bookmark' />" &_
        "<category term='lotus' />" &_
        "<category term='connections' />" &_
        "<category term='50WaysToLeaveYourBookmark' />" &_
        "<link href='http://www.ibm.com/lotus/connections' />" &_
        "</entry>"

Set objHTTP = CreateObject("Microsoft.XMLHTTP")
objHTTP.open "POST", url, False, "wilsonje@us.ibm.com", "passw0rd"
objHTTP.setRequestHeader "Content-Type", "application/atom+xml"
objHTTP.send entry
Document.Write objHTTP.statusText
Set objHTTP = Nothing


Python
by Bill Grant (billgrant.org)

Libraries used

base64 - encoding module

xml.dom.minidom - simple DOM module

urllib2 - url fetch module

Code

import string
import base64
import xml.dom.minidom
import urllib2
from urllib2 import Request, urlopen, HTTPError, URLError

def create_bookmark(user, pw):
    doc = xml.dom.minidom.Document()
    doc.encoding = "utf-8"

    entry = doc.createElement("entry")
    entry.setAttribute("xmlns", "http://www.w3.org/2005/Atom")
    doc.appendChild(entry)

    # Author
    # <author><name>Author</name></author>
    author = doc.createElement("author")
    entry.appendChild(author)
    name = doc.createElement("name")
    author.appendChild(name)
    nameTXT = doc.createTextNode("Author")
    name.appendChild(nameTXT)

    # Title
    # <title>The Lotus Connections Page</title>
    title = doc.createElement("title")
    entry.appendChild(title)
    titleTXT = doc.createTextNode("The Lotus Connections Page")
    title.appendChild(titleTXT)

    # content
    # <content type="html"><![CDATA[I posed this from <language>]]>
    </content>
    content = doc.createElement("content")
    content.setAttribute("type", "html")
    contentTXT = doc.createCDATASection("I posted this from Python")
    content.appendChild(contentTXT)
    entry.appendChild(content)

    # category
    # <category scheme="http://www.ibm.com/xmlns/prod/sn/type" 
    term="bookmark" />
    category = doc.createElement("category")
    category.setAttribute("scheme", "http://www.ibm.com/xmlns/prod/sn/type")
    category.setAttribute("term", "bookmark")
    entry.appendChild(category)

    # category: tags
    # <category term="lotus" />
    # <category term="connections" />
    # <category term="50WaysToLeaveYourBookmark" />
    categoryTerm1 = doc.createElement("category")
    categoryTerm1.setAttribute("term", "lotus")
    entry.appendChild(categoryTerm1)
    categoryTerm2 = doc.createElement("category")
    categoryTerm2.setAttribute("term", "connections")
    entry.appendChild(categoryTerm2)
    categoryTerm3 = doc.createElement("category")
    categoryTerm3.setAttribute("term", "50WaysToLeaveYourBookmark")
    entry.appendChild(categoryTerm3)

    # link
    # <link href="http://www.ibm.com/lotus/connections" />
    link = doc.createElement("link")
    link.setAttribute("href", "http://www.ibm.com/lotus/connections")
    entry.appendChild(link)

    theData = doc.toxml("utf-8")

    # headers
    # Host: www.company.com
    # Content-Type: application/atom+xml
    # Authorization: Basic RG9uIFF1aXhvdGU6Um9jaW5hbnRl
    theRequest = urllib2.Request("https://dogear.tap.ibm.com/api/app", theData)
    theRequest.add_header("Host", "dogear.tap.ibm.com") # dogear.tap.ibm.com
    theRequest.add_header("Content-Type", "application/atom+xml")
    theRequest.add_header("Authorization", 
    string.strip("Basic " + base64.encodestring("%s:%s" % (user, pw))))

    try:
        theResponse = urllib2.urlopen(theRequest)
    except HTTPError, e:
        if (e.code == 201):
            print "Bookmark created successfully."
        else:
            print "Bookmark was not created. (" + str(e.code) + ")"

if __name__ == '__main__':
    create_bookmark("myemail@us.ibm.com", "mypassword")


Conclusion

Well, we didn’t quite make 50, but as the 18 examples show, there are many different ways to access the AtomPub-based API on the Dogear server. The authors have shown that writing a bookmark to the server is possible using a variety of techniques and languages.

We’ve seen instances where the author has relied entirely on shell utilities such as cURL or wget, others that use libraries for HTTP access and atom entry creation, and yet others that rely on few libraries at all. Check the resources below for a link to the Lotus Greenhouse if you’d like to check out Dogear for yourself.


Resources

Learn

Discuss

About the authors

Frank Jania is currently the Technical Evangelist for IBM's Real Time Collaboration and Social Computing Technologies. Take a look at his social software blog.

Sacha Chua (sachac@ca.ibm.com) is a technical evangelist, storyteller, and geek. Her personal blog is at http://sachachua.com .

Axel Magard (axel_magard@de.ibm.com) is a project manager who sometimes also loves to do some computer programming. You can read his personal blog.

Jeff Lowrey (jlowrey@us.ibm.com) works for IBM Software Services for WebSphere as a Message Broker and MQ consultant and posts way too much, but not enough to his blog.

Andy Piper (andy.piper@uk.ibm.com) is a consultant working in IBM Software Services for WebSphere in the UK. His personal blog is at http://andypiper.co.uk/ .

Suzanne O Minassian (minassian@us.ibm.com) is the product manager for Lotus Connections. Her landing page is http://www.tekmoda.com .

Dave Griffiths (dgriff@uk.ibm.com) is a Java service drone. His home page is http://w3.hursley.ibm.com/~dgriff .

Chris Gambrell (chris_gambrell@us.ibm.com) is a software architect for IBM Lotus Sametime and other real-time collaboration projects.

Adam Reed (reedna@us.ibm.com) is an intern/soon-to-be part-time web developer for IBM Lotus Connections - Activities.

Bill Grant (billgrant@us.ibm.com) is a technical sales manager for IBM Rational Software on Wall Street. His personal blog is at http://billgrant.org .

Caroline Maynard (caroline.maynard@uk.ibm.com) is a software engineer at the IBM Laboratory in Hursley, England, who has recently worked on open-source extensions for PHP.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Lotus
ArticleID=299925
ArticleTitle=Fifty ways to leave your bookmark: An experiment in social authoring
publish-date=05062008
author1-email=fjania@us.ibm.com
author1-email-cc=
author2-email=sachac@ca.ibm.com
author2-email-cc=
author3-email=axel_magard@de.ibm.com
author3-email-cc=
author4-email=jlowrey@us.ibm.com
author4-email-cc=
author5-email=andy.piper@uk.ibm.com
author5-email-cc=
author6-email=minassian@us.ibm.com
author6-email-cc=
author7-email=dgriff@uk.ibm.com
author7-email-cc=
author8-email=chris_gambrell@us.ibm.com
author8-email-cc=
author9-email=reedna@us.ibm.com
author9-email-cc=
author10-email=billgrant@us.ibm.com
author10-email-cc=
author11-email=caroline.maynard@uk.ibm.com
author11-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers