Return-Path: Delivered-To: apmail-incubator-abdera-commits-archive@locus.apache.org Received: (qmail 14701 invoked from network); 9 Feb 2008 20:14:28 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 9 Feb 2008 20:14:28 -0000 Received: (qmail 45396 invoked by uid 500); 9 Feb 2008 20:14:21 -0000 Delivered-To: apmail-incubator-abdera-commits-archive@incubator.apache.org Received: (qmail 45381 invoked by uid 500); 9 Feb 2008 20:14:21 -0000 Mailing-List: contact abdera-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: abdera-dev@incubator.apache.org Delivered-To: mailing list abdera-commits@incubator.apache.org Received: (qmail 45372 invoked by uid 99); 9 Feb 2008 20:14:21 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 09 Feb 2008 12:14:21 -0800 X-ASF-Spam-Status: No, hits=-1998.5 required=10.0 tests=ALL_TRUSTED,WEIRD_PORT X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 09 Feb 2008 20:13:34 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id CE8AC1A9832; Sat, 9 Feb 2008 12:13:46 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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... Date: Sat, 09 Feb 2008 20:13:45 -0000 To: abdera-commits@incubator.apache.org From: jmsnell@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080209201349.CE8AC1A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 entries = new ArrayList(); + List 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 params = new HashMap(); + 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 params = new HashMap(); + 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 { + 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(""); + } + } + + 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 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 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_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 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_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_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