You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@abdera.apache.org by jm...@apache.org on 2008/02/09 21:13:45 UTC
svn commit: r620186 - in /incubator/abdera/java/trunk/adapters/couchdb: ./
src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/abdera/ src/main/java/org/apache/abdera/protocol/
src/main/java/org/apache/ab...
Author: jmsnell
Date: Sat Feb 9 12:13:43 2008
New Revision: 620186
URL: http://svn.apache.org/viewvc?rev=620186&view=rev
Log:
simple couchdb adapter. see the readme. this has not been incorporated into the build
or fully tested yet. treat this as experimental for now.
Added:
incubator/abdera/java/trunk/adapters/couchdb/
incubator/abdera/java/trunk/adapters/couchdb/readme
incubator/abdera/java/trunk/adapters/couchdb/src/
incubator/abdera/java/trunk/adapters/couchdb/src/main/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/CouchDbAdapter.java
incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/JsonObjectResponseContext.java
incubator/abdera/java/trunk/adapters/couchdb/src/test/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/test/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/test/couchdb/
incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/test/couchdb/CouchDbTest.java
incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/
incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/abdera/
incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/abdera/adapter/
incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/abdera/adapter/couchdb.properties
Added: incubator/abdera/java/trunk/adapters/couchdb/readme
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/adapters/couchdb/readme?rev=620186&view=auto
==============================================================================
--- incubator/abdera/java/trunk/adapters/couchdb/readme (added)
+++ incubator/abdera/java/trunk/adapters/couchdb/readme Sat Feb 9 12:13:43 2008
@@ -0,0 +1,50 @@
+CouchDB Collection Adapter
+
+Dependencies:
+
+ * Abdera Core, Parser, Protocol, Server modules
+ * CouchDb4J (http://www.couchdbwiki.com/index.php?title=Getting_Started_with_Java)
+
+Using the Adapter:
+
+ The CouchDB adapter is based on Abdera Managed Adapter model. To deploy an
+ instance of the adapter, put a file called /abdera/adapter/[id].properties
+ in the classpath where [id] is the id of the service instance. For instance,
+ /abdera/adapter/couchdb.properties
+
+
+Sample *.properties file
+
+ subUri=couchdb
+ adapterClassName=org.apache.abdera.protocol.server.adapters.couchdb.CouchDbAdapter
+ title=CouchDB Feed
+ author=james
+ configFile=dummyFileLocation
+
+ # uncomment to override the defaults
+ #couchdb.host=localhost
+ #couchdb.port=5984
+
+Then, deploy the AbderaServlet using the BasicProvider in your Web application environment:
+
+Jetty deployment example:
+
+ Server server = new Server(9002);
+ Context context = new Context(server, "/", Context.SESSIONS);
+ ServletHolder servletHolder = new ServletHolder(new AbderaServlet());
+ servletHolder.setInitParameter(ServiceManager.PROVIDER, BasicAdapter.class.getName());
+ context.addServlet(servletHolder, "/*");
+ server.start();
+
+Using this example, the following resources will be served:
+
+ http://localhost:9002/ ==> Atompub Service Document
+ http://localhost:9002/couchdb ==> Atompub Collection Feed
+ http://localhost:9002/couchdb/{entry} ==> Entry document
+
+Limitations:
+
+ The adapter does not support media collections or feed paging. Persistence
+ of extension elements has not yet been fully tested.
+
+
\ No newline at end of file
Added: incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/CouchDbAdapter.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/CouchDbAdapter.java?rev=620186&view=auto
==============================================================================
--- incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/CouchDbAdapter.java (added)
+++ incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/CouchDbAdapter.java Sat Feb 9 12:13:43 2008
@@ -0,0 +1,291 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.protocol.server.adapters.couchdb;
+
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.json.JSONObject;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.i18n.text.Normalizer;
+import org.apache.abdera.i18n.text.Sanitizer;
+import org.apache.abdera.model.AtomDate;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Link;
+import org.apache.abdera.protocol.server.ProviderHelper;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.ResponseContext;
+import org.apache.abdera.protocol.server.Target;
+import org.apache.abdera.protocol.server.provider.managed.FeedConfiguration;
+import org.apache.abdera.protocol.server.provider.managed.ManagedCollectionAdapter;
+
+import com.fourspaces.couchdb.Database;
+import com.fourspaces.couchdb.Document;
+import com.fourspaces.couchdb.Session;
+import com.fourspaces.couchdb.ViewResults;
+
+public class CouchDbAdapter
+ extends ManagedCollectionAdapter {
+
+ private final DocumentComparator sorter = new DocumentComparator();
+ private final String host;
+ private final int port;
+
+ public CouchDbAdapter(
+ Abdera abdera,
+ FeedConfiguration config) {
+ this(
+ abdera,
+ config,
+ null,
+ -1);
+ }
+
+ public CouchDbAdapter(
+ Abdera abdera,
+ FeedConfiguration config,
+ String host,
+ int port) {
+ super(abdera, config);
+ if (host == null) {
+ host = (String)config.getProperty("couchdb.host");
+ if (host == null) host = "localhost";
+ }
+ if (port < 0) {
+ try {
+ port = Integer.parseInt((String)config.getProperty("couchdb.port"));
+ } catch (Exception e) {}
+ if (port < 0) port = 5984;
+ }
+ this.host = host;
+ this.port = port;
+ }
+
+ private synchronized Database getDatabase(
+ RequestContext request) {
+ String name = request.getTarget().getParameter("feed");
+ Session session = new Session(host,port);
+ Database db = null;
+ try {
+ db = session.getDatabase(name);
+ } catch (Exception e) {}
+ if (db == null)
+ db = session.createDatabase(name);
+ return db;
+ }
+
+ public ResponseContext getFeed(
+ RequestContext request) {
+ Database db = getDatabase(request);
+ ViewResults res = db.getAllDocuments();
+ List<Document> entries = new ArrayList<Document>();
+ List<Document> docs = res.getResults();
+ for (Document doc : docs) {
+ entries.add(
+ db.getDocument(doc.getString("id")));
+ }
+ Collections.sort(entries, sorter);
+ return new JsonObjectResponseContext(
+ request.getAbdera(),
+ config,
+ res,
+ entries.toArray(new Document[entries.size()]))
+ .setStatus(200)
+ .setEntityTag(res.getRev());
+ }
+
+ public ResponseContext deleteEntry(
+ RequestContext request) {
+ Target target = request.getTarget();
+ String feed = target.getParameter("feed");
+ String entry = target.getParameter("entry");
+ Session session = new Session(host,port);
+ Database db = session.getDatabase(feed);
+ Document doc = db.getDocument(entry);
+ if (doc != null) {
+ db.deleteDocument(doc);
+ return ProviderHelper.nocontent();
+ } else
+ return ProviderHelper.notfound(request);
+ }
+
+ private void setEditDetail(RequestContext request) throws IOException {
+ Target target = request.getTarget();
+ String feed = target.getParameter("feed");
+ String id = target.getParameter("entry");
+ Entry entry = (Entry) request.getDocument().getRoot();
+ entry.setEdited(new Date());
+ Link link = entry.getEditLink();
+ Map<String,Object> params = new HashMap<String,Object>();
+ params.put("feed", feed);
+ params.put("entry", id);
+ String href = request.absoluteUrlFor("entry", params);
+ if (link == null) {
+ entry.addLink(href, "edit");
+ } else {
+ link.setHref(href);
+ }
+ }
+
+ public ResponseContext postEntry(
+ RequestContext request) {
+ Target target = request.getTarget();
+ String feed = target.getParameter("feed");
+ Session session = new Session(host,port);
+ Database db = session.getDatabase(feed);
+ try {
+ CharArrayWriter cwriter = new CharArrayWriter();
+ setEditDetail(request);
+ request.getDocument().getRoot().writeTo("json", cwriter);
+ String json = new String(cwriter.toCharArray());
+ JSONObject obj = JSONObject.fromObject(json);
+ String key = createKey(request);
+ Document doc = null;
+ try {
+ doc = db.getDocument(key);
+ } catch (Exception e) {}
+ if (doc != null) {
+ return ProviderHelper.conflict(
+ request,
+ "Entry with that key already exists");
+ } else {
+ doc = new Document(obj);
+ doc.setId(key);
+ db.saveDocument(doc);
+ doc = db.getDocument(key);
+ if (doc != null) {
+ Map<String,Object> params = new HashMap<String,Object>();
+ params.put("feed", feed);
+ params.put("entry", key);
+ String urlFor = request.absoluteUrlFor("entry", params);
+ return new JsonObjectResponseContext(
+ request.getAbdera(),
+ config,
+ doc)
+ .setStatus(201)
+ .setEntityTag(doc.getRev())
+ .setLocation(urlFor);
+ } else {
+ return ProviderHelper.servererror(request, null);
+ }
+ }
+ } catch (IOException e) {
+ return ProviderHelper.servererror(request, e);
+ }
+ }
+
+ private String createKey(RequestContext request) throws IOException {
+ String slug = request.getSlug();
+ if (slug == null) {
+ slug = ((Entry)request.getDocument().getRoot()).getTitle();
+ }
+ return Sanitizer.sanitize(slug, "", true, Normalizer.Form.D);
+ }
+
+ public ResponseContext getEntry(
+ RequestContext request) {
+ Target target = request.getTarget();
+ String feed = target.getParameter("feed");
+ String entry = target.getParameter("entry");
+ Session session = new Session(host,port);
+ Database db = session.getDatabase(feed);
+ Document doc = db.getDocument(entry);
+ if (doc != null)
+ return new JsonObjectResponseContext(
+ request.getAbdera(),
+ config,
+ doc)
+ .setStatus(200)
+ .setEntityTag(doc.getRev());
+ else
+ return ProviderHelper.notfound(request);
+ }
+
+ public ResponseContext putEntry(
+ RequestContext request) {
+ Target target = request.getTarget();
+ String feed = target.getParameter("feed");
+ Session session = new Session(host,port);
+ Database db = session.getDatabase(feed);
+ try {
+ CharArrayWriter cwriter = new CharArrayWriter();
+ setEditDetail(request);
+ request.getDocument().getRoot().writeTo("json", cwriter);
+ String json = new String(cwriter.toCharArray());
+ JSONObject obj = JSONObject.fromObject(json);
+ String key = target.getParameter("entry");
+ Document doc = null;
+ try {
+ doc = db.getDocument(key);
+ } catch (Exception e) {}
+ if (doc == null) {
+ return ProviderHelper.notfound(request);
+ } else {
+ db.deleteDocument(doc);
+ doc = new Document(obj);
+ doc.setId(key);
+ db.saveDocument(doc);
+ doc = db.getDocument(key);
+ if (doc != null)
+ return new JsonObjectResponseContext(
+ request.getAbdera(),
+ config,
+ doc)
+ .setStatus(200)
+ .setEntityTag(doc.getRev());
+ else
+ return ProviderHelper.servererror(request, null);
+ }
+ } catch (IOException e) {
+ return ProviderHelper.servererror(request, e);
+ }
+ }
+
+ public ResponseContext getCategories(
+ RequestContext request) {
+ return ProviderHelper.notfound(request);
+ }
+
+ public ResponseContext extensionRequest(
+ RequestContext request) {
+ return ProviderHelper.notfound(request);
+ }
+
+ private static class DocumentComparator
+ implements Comparator<Document> {
+ public int compare(
+ Document doc1,
+ Document doc2) {
+ String ed1 = doc1.getString("edited");
+ String ed2 = doc2.getString("edited");
+ Date d1 = AtomDate.parse(ed1);
+ Date d2 = AtomDate.parse(ed2);
+ if (d1.before(d2)) return 1;
+ else if (d1.after(d2)) return -1;
+ else return 0;
+ }
+ }
+}
Added: incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/JsonObjectResponseContext.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/JsonObjectResponseContext.java?rev=620186&view=auto
==============================================================================
--- incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/JsonObjectResponseContext.java (added)
+++ incubator/abdera/java/trunk/adapters/couchdb/src/main/java/org/apache/abdera/protocol/server/adapters/couchdb/JsonObjectResponseContext.java Sat Feb 9 12:13:43 2008
@@ -0,0 +1,395 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements. The ASF licenses this file to You
+* under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License. For additional information regarding
+* copyright in this work, please see the NOTICE file in the top level
+* directory of this distribution.
+*/
+package org.apache.abdera.protocol.server.adapters.couchdb;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Text;
+import org.apache.abdera.protocol.server.context.StreamWriterResponseContext;
+import org.apache.abdera.protocol.server.provider.managed.FeedConfiguration;
+import org.apache.abdera.util.Constants;
+import org.apache.abdera.writer.StreamWriter;
+
+import com.fourspaces.couchdb.Document;
+
+public class JsonObjectResponseContext
+ extends StreamWriterResponseContext {
+
+ private final FeedConfiguration config;
+ private final Document doc;
+ private final Document[] entries;
+
+ protected JsonObjectResponseContext(
+ Abdera abdera,
+ FeedConfiguration config,
+ Document doc) {
+ this(abdera,config,doc,(Document[])null);
+ }
+
+ protected JsonObjectResponseContext(
+ Abdera abdera,
+ FeedConfiguration config,
+ Document doc,
+ Document... entries) {
+ super(abdera);
+ this.doc = doc;
+ this.entries = entries;
+ this.config = config;
+ setContentType(
+ entries != null ?
+ "application/atom+xml" :
+ "application/atom+xml;type=entry");
+ }
+
+ protected JsonObjectResponseContext(
+ Abdera abdera,
+ FeedConfiguration config,
+ String encoding,
+ Document doc,
+ Document... entries) {
+ super(abdera, encoding);
+ this.doc = doc;
+ this.entries = entries;
+ this.config = config;
+ }
+
+ protected void writeTo(
+ StreamWriter sw)
+ throws IOException {
+ sw.startDocument();
+ if (entries != null)
+ writeJsonFeed(config,doc, entries, sw);
+ else writeJsonEntry(doc, sw);
+ sw.endDocument();
+ }
+
+ public boolean hasEntity() {
+ return true;
+ }
+
+ private static void writeJsonFeed(
+ FeedConfiguration config,
+ Document doc,
+ Document[] entries,
+ StreamWriter writer) {
+ writer.startFeed();
+ writer.writeId(config.getServerConfiguration().getServerUri() + "/" + config.getFeedId())
+ .writeTitle(config.getFeedTitle())
+ .writeAuthor(config.getFeedAuthor())
+ .writeLink(config.getFeedUri())
+ .writeLink(config.getFeedUri(), "self")
+ .writeUpdated(new Date());
+ for (Document entry : entries)
+ writeJsonEntry(entry, writer);
+ writer.endFeed();
+ }
+
+ private static void writeJsonEntry(
+ Document doc,
+ StreamWriter writer) {
+ writer.startEntry();
+ writeJsonAttributes(doc.getJSONObject("attributes"), writer);
+ for (Object key : doc.keySet()) {
+ String name = (String) key;
+ if (!name.startsWith("_")) {
+ if (name.equals("id"))
+ writer.writeId(doc.getString(name));
+ else if (name.equals("title")) {
+ writeJsonTextElement(
+ Constants.TITLE,
+ doc.get(name),
+ writer);
+ } else if (name.equals("summary")) {
+ writeJsonTextElement(
+ Constants.SUMMARY,
+ doc.get(name),
+ writer);
+ } else if (name.equals("rights")) {
+ writeJsonTextElement(
+ Constants.RIGHTS,
+ doc.get(name),
+ writer);
+ } else if (name.equals("links")) {
+ JSONArray array = doc.getJSONArray(name);
+ for (int n = 0; n < array.size(); n++) {
+ JSONObject obj = array.getJSONObject(n);
+ writer.startElement(Constants.LINK);
+ writeJsonAttributes(obj, writer);
+ if (obj.containsKey("extensions"))
+ writeJsonExtensions(obj.getJSONArray("extensions"), writer);
+ writer.endElement();
+ }
+ } else if (name.equals("categories")) {
+ JSONArray array = doc.getJSONArray(name);
+ for (int n = 0; n < array.size(); n++) {
+ JSONObject obj = array.getJSONObject(n);
+ writer.startElement(Constants.CATEGORY);
+ writeJsonAttributes(obj, writer);
+ if (obj.containsKey("extensions"))
+ writeJsonExtensions(obj.getJSONArray("extensions"), writer);
+ writer.endElement();
+ }
+ } else if (name.equals("authors")) {
+ JSONArray array = doc.getJSONArray(name);
+ for (int n = 0; n < array.size(); n++) {
+ JSONObject obj = array.getJSONObject(n);
+ writeJsonPerson(Constants.AUTHOR, obj, writer);
+ }
+ } else if (name.equals("contributors")) {
+ JSONArray array = doc.getJSONArray(name);
+ for (int n = 0; n < array.size(); n++) {
+ JSONObject obj = array.getJSONObject(n);
+ writeJsonPerson(Constants.CONTRIBUTOR, obj, writer);
+ }
+ } else if (name.equals("updated")) {
+ writer.writeUpdated(doc.getString(name));
+ } else if (name.equals("published")) {
+ writer.writePublished(doc.getString(name));
+ } else if (name.equals("edited")) {
+ writer.writeEdited(doc.getString(name));
+ } else if (name.equals("content")) {
+ writeJsonContentElement(
+ doc.get(name),
+ writer);
+ } else if (name.equals("control")) {
+ JSONObject control = doc.getJSONObject("control");
+ writer.startControl();
+ writeJsonAttributes(control.getJSONObject("attributes"), writer);
+ writer.writeDraft(control.getBoolean("draft"));
+ if (control.containsKey("extensions"))
+ writeJsonExtensions(control.getJSONArray("extensions"), writer);
+ writer.endControl();
+ } else if (name.equals("source")) {
+
+ }
+ }
+ }
+ writer.endEntry();
+ }
+
+ private static void writeJsonPerson(
+ QName qname,
+ JSONObject object,
+ StreamWriter writer) {
+ writer.startPerson(qname);
+ writer.writePersonName(object.getString("name"));
+ if (object.containsKey("email"))
+ writer.writePersonEmail(object.getString("email"));
+ if (object.containsKey("uri"))
+ writer.writePersonUri(object.getString("uri"));
+ if (object.containsKey("extensions"))
+ writeJsonExtensions(object.getJSONArray("extensions"), writer);
+ writer.endPerson();
+ }
+
+ private static void writeJsonContentElement(
+ Object value,
+ StreamWriter writer) {
+ if (value instanceof String) {
+ writer.writeContent(Content.Type.TEXT, (String) value);
+ } else if (value instanceof JSONObject) {
+ writeJsonContent(
+ (JSONObject)value,
+ writer);
+ }
+ }
+
+ private static void writeJsonContent(
+ JSONObject object,
+ StreamWriter writer) {
+ String type = object.getJSONObject("attributes").getString("type");
+ Content.Type ctype = Content.Type.valueOf(type.toUpperCase());
+ writer.startContent(ctype);
+ if (ctype == Content.Type.XHTML)
+ writer.startElement(Constants.DIV);
+ JSONArray array = object.getJSONArray("children");
+ for (int n = 0; n < array.size(); n++) {
+ Object child = array.get(n);
+ if (child instanceof String) {
+ writer.writeElementText((String)child);
+ } else if (child instanceof JSONObject) {
+ writeJsonTextMarkup(
+ (JSONObject) child,
+ writer,
+ ctype == Content.Type.XHTML);
+ }
+ }
+ if (ctype == Content.Type.XHTML)
+ writer.endElement();
+ writer.endElement();
+ }
+
+ private static void writeJsonTextElement(
+ QName qname,
+ Object value,
+ StreamWriter writer) {
+ if (value instanceof String) {
+ writer.writeText(qname, Text.Type.TEXT, (String) value);
+ } else if (value instanceof JSONObject) {
+ writeJsonText(
+ qname,
+ (JSONObject)value,
+ writer);
+ }
+ }
+
+ private static void writeJsonText(
+ QName qname,
+ JSONObject object,
+ StreamWriter writer) {
+ String type = object.getJSONObject("attributes").getString("type");
+ Text.Type texttype = Text.Type.valueOf(type.toUpperCase());
+ writer.startText(qname,texttype);
+ if (texttype == Text.Type.XHTML)
+ writer.startElement(Constants.DIV);
+ JSONArray array = object.getJSONArray("children");
+ for (int n = 0; n < array.size(); n++) {
+ Object child = array.get(n);
+ if (child instanceof String) {
+ writer.writeElementText((String)child);
+ } else if (child instanceof JSONObject) {
+ writeJsonTextMarkup(
+ (JSONObject) child,
+ writer,
+ texttype == Text.Type.XHTML);
+ }
+ }
+ if (texttype == Text.Type.XHTML)
+ writer.endElement();
+ writer.endElement();
+ }
+
+ private static void writeJsonTextMarkup(
+ JSONObject object,
+ StreamWriter writer,
+ boolean xhtml) {
+ String name = object.getString("name");
+ if (xhtml) {
+ writer.startElement(name, Constants.XHTML_NS);
+ writeJsonAttributes(object.getJSONObject("attributes"), writer);
+ JSONArray array = object.getJSONArray("children");
+ for (int n = 0; n < array.size(); n++) {
+ Object obj = array.get(n);
+ if (obj instanceof String) {
+ writer.writeElementText((String) obj);
+ } else if (obj instanceof JSONObject) {
+ writeJsonTextMarkup((JSONObject) obj, writer, xhtml);
+ }
+ }
+ writer.endElement();
+ } else {
+ writer.writeElementText("<" + name);
+
+ JSONObject attrs = object.getJSONObject("attributes");
+ for (Object attr : attrs.entrySet()) {
+ Map.Entry<?,?> entry = (Map.Entry<?,?>)attr;
+ String attrname = (String) entry.getKey();
+ String value = (String) entry.getValue();
+ writer.writeElementText(" " + attrname + "=\"" + value + "\"");
+ }
+
+ writer.writeElementText(">");
+ JSONArray array = object.getJSONArray("children");
+ for (int n = 0; n < array.size(); n++) {
+ Object obj = array.get(n);
+ if (obj instanceof String) {
+ writer.writeElementText((String) obj);
+ } else if (obj instanceof JSONObject) {
+ writeJsonTextMarkup((JSONObject) obj, writer, xhtml);
+ }
+ }
+ writer.writeElementText("</" + name + ">");
+ }
+ }
+
+ private static void writeJsonAttributes(
+ JSONObject object,
+ StreamWriter writer) {
+ for (Object key : object.keySet()) {
+ String name = (String) key;
+ if (!name.startsWith("xmlns:")) {
+ Object value = object.get(name);
+ if (value instanceof String) {
+ writer.writeAttribute(name, (String)value);
+ } else if (value instanceof JSONObject){
+ JSONObject valueObj = (JSONObject) value;
+ String namespace = null;
+ JSONObject valueAttrs = valueObj.getJSONObject("attributes");
+ for (Object vkey : valueAttrs.keySet()) {
+ namespace = valueAttrs.getString((String) vkey);
+ break;
+ }
+ String[] namesplit = name.split(":",2);
+ writer.writeAttribute(
+ namesplit[1],
+ namespace,
+ namesplit[0],
+ valueObj.getString("value"));
+ }
+ }
+ }
+ }
+
+ private static void writeJsonExtensions(
+ JSONArray array,
+ StreamWriter writer) {
+ for (int n = 0; n < array.size(); n++) {
+ JSONObject object = array.getJSONObject(n);
+ writeJsonObject(object,writer);
+ }
+ }
+
+ private static void writeJsonObject(
+ JSONObject object,
+ StreamWriter writer) {
+ String namespace = null;
+ JSONObject valueAttrs = object.getJSONObject("attributes");
+ for (Object vkey : valueAttrs.keySet()) {
+ String svkey = (String) vkey;
+ if (svkey.startsWith("xmlns:"))
+ namespace = valueAttrs.getString(svkey);
+ break;
+ }
+ String name = object.getString("name");
+ String[] namesplit = name.split(":",2);
+ if (namesplit.length > 1)
+ writer.startElement(namesplit[1], namespace, namesplit[0]);
+ else
+ writer.startElement(name, namespace);
+ writeJsonAttributes(valueAttrs, writer);
+ JSONArray children = object.getJSONArray("children");
+ for (int i = 0; i < children.size(); i++) {
+ Object child = children.get(i);
+ if (child instanceof String) {
+ writer.writeElementText((String)child);
+ } else if (child instanceof JSONObject) {
+ writeJsonObject((JSONObject) child,writer);
+ }
+ }
+ writer.endElement();
+ }
+}
Added: incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/test/couchdb/CouchDbTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/test/couchdb/CouchDbTest.java?rev=620186&view=auto
==============================================================================
--- incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/test/couchdb/CouchDbTest.java (added)
+++ incubator/abdera/java/trunk/adapters/couchdb/src/test/java/org/apache/abdera/protocol/server/test/couchdb/CouchDbTest.java Sat Feb 9 12:13:43 2008
@@ -0,0 +1,151 @@
+package org.apache.abdera.protocol.server.test.couchdb;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Base;
+import org.apache.abdera.model.Collection;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Service;
+import org.apache.abdera.model.Workspace;
+import org.apache.abdera.protocol.Response.ResponseType;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.abdera.protocol.server.provider.basic.BasicProvider;
+import org.apache.abdera.protocol.server.test.JettyServer;
+import org.apache.abdera.util.Constants;
+import org.apache.abdera.util.MimeTypeHelper;
+import org.apache.abdera.writer.Writer;
+import org.apache.abdera.writer.WriterFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class CouchDbTest extends Assert {
+
+ private static JettyServer server;
+ private static Abdera abdera = Abdera.getInstance();
+ private static AbderaClient client = new AbderaClient();
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ if (server == null) {
+ server = new JettyServer();
+ server.start(BasicProvider.class);
+ }
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ server.stop();
+ }
+
+ protected void prettyPrint(Base doc) throws IOException {
+ WriterFactory factory = abdera.getWriterFactory();
+ Writer writer = factory.getWriter("prettyxml");
+ writer.writeTo(doc, System.out);
+ System.out.println();
+ }
+
+ @Test
+ public void testGetService() {
+ ClientResponse resp = client.get("http://localhost:9002/");
+ assertNotNull(resp);
+ assertEquals(resp.getType(), ResponseType.SUCCESS);
+ assertTrue(MimeTypeHelper.isMatch(resp.getContentType().toString(), Constants.APP_MEDIA_TYPE));
+ Document<Service> doc = resp.getDocument();
+ Service service = doc.getRoot();
+ assertEquals(service.getWorkspaces().size(), 1);
+ Workspace workspace = service.getWorkspace("Abdera");
+ assertEquals(workspace.getCollections().size(), 2);
+ Collection collection = workspace.getCollection("CouchDB Feed");
+ assertNotNull(collection);
+ assertTrue(collection.acceptsEntry());
+ assertEquals(collection.getResolvedHref().toString(), "http://localhost:9002/couchdb");
+ }
+ @Test
+ public void testGetFeed() {
+ ClientResponse resp = client.get("http://localhost:9002/couchdb");
+ assertNotNull(resp);
+ assertEquals(resp.getType(), ResponseType.SUCCESS);
+ assertTrue(MimeTypeHelper.isMatch(resp.getContentType().toString(), Constants.ATOM_MEDIA_TYPE));
+ Document<Feed> doc = resp.getDocument();
+ Feed feed = doc.getRoot();
+ assertEquals(feed.getId().toString(), "http://localhost:9002/couchdb");
+ assertEquals(feed.getTitle(), "CouchDB Feed");
+ assertEquals(feed.getAuthor().getName(), "james");
+ assertEquals(feed.getEntries().size(), 0);
+ resp.release();
+ }
+ @Test
+ public void testPostEntry() {
+ Entry entry = abdera.newEntry();
+ entry.setId("http://localhost:9002/couchdb/foo");
+ entry.setTitle("test entry");
+ entry.setContent("Test Content");
+ entry.addLink("http://example.org");
+ entry.setUpdated(new Date());
+ entry.addAuthor("James");
+ ClientResponse resp = client.post("http://localhost:9002/couchdb", entry);
+ assertNotNull(resp);
+ assertEquals(resp.getType(), ResponseType.SUCCESS);
+ assertEquals(resp.getStatus(), 201);
+ assertEquals(resp.getLocation().toString(), "http://localhost:9002/couchdb/test_entry");
+ resp = client.get("http://localhost:9002/couchdb");
+ Document<Feed> feed_doc = resp.getDocument();
+ Feed feed = feed_doc.getRoot();
+ assertEquals(feed.getEntries().size(), 1);
+ resp.release();
+ }
+ @Test
+ public void testPostMedia() {
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[] {0x01, 0x02, 0x03, 0x04});
+ RequestOptions options = client.getDefaultRequestOptions();
+ options.setContentType("application/octet-stream");
+ ClientResponse resp = client.post("http://localhost:9002/couchdb", in, options);
+ assertEquals(resp.getType(), ResponseType.CLIENT_ERROR);
+ assertEquals(resp.getStatus(), 415);
+ resp.release();
+ }
+ @Test
+ public void testPutEntry() {
+ ClientResponse resp = client.get("http://localhost:9002/couchdb/test_entry");
+ Document<Entry> doc = resp.getDocument();
+ Entry entry = (Entry) doc.getRoot().clone();
+ entry.setTitle("This is the modified title");
+ resp.release();
+ resp = client.put("http://localhost:9002/couchdb/test_entry", entry);
+ assertEquals(resp.getType(), ResponseType.SUCCESS);
+ assertEquals(resp.getStatus(), 200);
+ resp.release();
+ resp = client.get("http://localhost:9002/couchdb/test_entry");
+ doc = resp.getDocument();
+ entry = doc.getRoot();
+ assertEquals(entry.getTitle(), "This is the modified title");
+ resp.release();
+ resp = client.get("http://localhost:9002/couchdb");
+ Document<Feed> feed_doc = resp.getDocument();
+ Feed feed = feed_doc.getRoot();
+ assertEquals(feed.getEntries().size(), 1);
+ resp.release();
+ }
+
+ @Test
+ public void testDeleteEntry() {
+ ClientResponse resp = client.delete("http://localhost:9002/couchdb/test_entry");
+ assertEquals(resp.getType(), ResponseType.SUCCESS);
+ resp.release();
+ resp = client.get("http://localhost:9002/couchdb");
+ Document<Feed> feed_doc = resp.getDocument();
+ Feed feed = feed_doc.getRoot();
+ assertEquals(feed.getEntries().size(), 0);
+ resp.release();
+ }
+}
Added: incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/abdera/adapter/couchdb.properties
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/abdera/adapter/couchdb.properties?rev=620186&view=auto
==============================================================================
--- incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/abdera/adapter/couchdb.properties (added)
+++ incubator/abdera/java/trunk/adapters/couchdb/src/test/resources/abdera/adapter/couchdb.properties Sat Feb 9 12:13:43 2008
@@ -0,0 +1,9 @@
+subUri=couchdb
+adapterClassName=org.apache.abdera.protocol.server.adapters.couchdb.CouchDbAdapter
+title=CouchDB Feed
+author=james
+configFile=dummyFileLocation
+
+# uncomment to override the defaults
+#couchdb.host=localhost
+#couchdb.port=5984
\ No newline at end of file