You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2006/05/05 19:49:08 UTC

svn commit: r400121 [2/4] - in /incubator/roller/trunk: ./ nbproject/ src/org/apache/roller/presentation/webservices/ src/org/apache/roller/util/ src/org/apache/roller/webservices/ src/org/apache/roller/webservices/adminapi/ src/org/apache/roller/webse...

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/RollerWeblogHandler.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/RollerWeblogHandler.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/RollerWeblogHandler.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/RollerWeblogHandler.java Fri May  5 10:49:04 2006
@@ -0,0 +1,389 @@
+/*
+* 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.
+*/
+/*
+ * RollerWeblogHandler.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+package org.apache.roller.webservices.adminapi;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Collections;
+import java.util.Date;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jdom.Document;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.apache.roller.RollerException;
+import org.apache.roller.config.RollerRuntimeConfig;
+import org.apache.roller.model.UserManager;
+import org.apache.roller.pojos.PermissionsData;
+import org.apache.roller.pojos.UserData;
+import org.apache.roller.pojos.WebsiteData;
+import org.apache.roller.util.cache.CacheManager;
+import org.apache.roller.util.Utilities;
+import org.apache.roller.webservices.adminapi.sdk.Entry;
+import org.apache.roller.webservices.adminapi.sdk.EntrySet;
+import org.apache.roller.webservices.adminapi.sdk.MissingElementException;
+import org.apache.roller.webservices.adminapi.sdk.UnexpectedRootElementException;
+import org.apache.roller.webservices.adminapi.sdk.WeblogEntry;
+import org.apache.roller.webservices.adminapi.sdk.WeblogEntrySet;
+
+/**
+ * This class handles requests concerning Roller weblog resources.
+ *
+ * @author jtb
+ */
+class RollerWeblogHandler extends Handler {
+    private static Log log =
+            LogFactory.getFactory().getInstance(RollerWeblogHandler.class);
+    
+    /** Theme name used when creating weblogs */
+    private static final String DEFAULT_THEME = "basic";
+    
+    public RollerWeblogHandler(HttpServletRequest request) throws HandlerException {
+        super(request);
+    }
+    
+    public EntrySet processGet() throws HandlerException {
+        if (getUri().isCollection()) {
+            return getCollection();
+        } else if (getUri().isEntry()) {
+            return getEntry();
+        } else {
+            throw new BadRequestException("ERROR: Unknown GET URI type");
+        }
+    }
+    
+    public EntrySet processPost(Reader r) throws HandlerException {
+        if (getUri().isCollection()) {
+            return postCollection(r);
+        } else {
+            throw new BadRequestException("ERROR: Unknown POST URI type");
+        }
+    }
+    
+    public EntrySet processPut(Reader r) throws HandlerException {
+        if (getUri().isCollection()) {
+            return putCollection(r);
+        } else if (getUri().isEntry()) {
+            return putEntry(r);
+        } else {
+            throw new BadRequestException("ERROR: Unknown PUT URI type");
+        }
+    }
+    
+    public EntrySet processDelete() throws HandlerException {
+        if (getUri().isEntry()) {
+            return deleteEntry();
+        } else {
+            throw new BadRequestException("ERROR: Unknown DELETE URI type");
+        }
+    }
+    
+    private EntrySet getCollection() throws HandlerException {
+        try {
+            List users = getRoller().getUserManager().getUsers();
+            if (users == null) {
+                users = Collections.EMPTY_LIST;
+            }
+            EntrySet c = toWeblogEntrySet((UserData[])users.toArray(new UserData[0]));
+            
+            return c;
+        } catch (RollerException re) {
+            throw new InternalException("ERROR: Could not get weblog collection", re);
+        }
+    }
+    
+    private EntrySet getEntry() throws HandlerException {
+        String handle = getUri().getEntryId();
+        try {
+            WebsiteData wd = getRoller().getUserManager().getWebsiteByHandle(handle);
+            if (wd == null) {
+                throw new NotFoundException("ERROR: Unknown weblog handle: " + handle);
+            }
+            WebsiteData[] wds = new WebsiteData[] { wd };
+            EntrySet c = toWeblogEntrySet(wds);
+            
+            return c;
+        } catch (RollerException re) {
+            throw new InternalException("ERROR: Could not get weblog collection", re);
+        }
+    }
+    
+    private EntrySet postCollection(Reader r) throws HandlerException {
+        try {
+            SAXBuilder builder = new SAXBuilder();
+            Document collectionDoc = builder.build(r);
+            EntrySet c = new WeblogEntrySet(collectionDoc, getUrlPrefix());
+            c = createWeblogs((WeblogEntrySet)c);
+            
+            return c;
+        } catch (JDOMException je) {
+            throw new InternalException("ERROR: Could not post collection", je);
+        } catch (IOException ioe) {
+            throw new InternalException("ERROR: Could not post collection", ioe);
+        } catch (MissingElementException mee) {
+            throw new InternalException("ERROR: Could not post collection", mee);
+        } catch (UnexpectedRootElementException uree) {
+            throw new InternalException("ERROR: Could not post collection", uree);
+        }
+    }
+    
+    private EntrySet putCollection(Reader r) throws HandlerException {
+        try {
+            SAXBuilder builder = new SAXBuilder();
+            Document collectionDoc = builder.build(r);
+            EntrySet c = new WeblogEntrySet(collectionDoc, getUrlPrefix());
+            c = updateWeblogs((WeblogEntrySet)c);
+            
+            return c;
+        } catch (JDOMException je) {
+            throw new InternalException("ERROR: Could not post collection", je);
+        } catch (IOException ioe) {
+            throw new InternalException("ERROR: Could not post collection", ioe);
+        } catch (MissingElementException mee) {
+            throw new InternalException("ERROR: Could not post collection", mee);
+        } catch (UnexpectedRootElementException uree) {
+            throw new InternalException("ERROR: Could not post collection", uree);
+        }
+    }
+    
+    private EntrySet putEntry(Reader r) throws HandlerException {
+        try {
+            SAXBuilder builder = new SAXBuilder();
+            Document collectionDoc = builder.build(r);
+            EntrySet c = new WeblogEntrySet(collectionDoc, getUrlPrefix());
+            
+            if (c.getEntries().length > 1) {
+                throw new BadRequestException("ERROR: Cannot put >1 entries per request");
+            }
+            if (c.getEntries().length > 0) {
+                WeblogEntry entry = (WeblogEntry)c.getEntries()[0];
+                if (entry.getHandle() != null && !entry.getHandle().equals(getUri().getEntryId())) {
+                    throw new BadRequestException("ERROR: Content handle does not match URI handle");
+                }
+                entry.setHandle(getUri().getEntryId());
+                updateWeblogs((WeblogEntrySet)c);
+            }
+            
+            return c;
+        } catch (JDOMException je) {
+            throw new InternalException("ERROR: Could not post collection", je);
+        } catch (IOException ioe) {
+            throw new InternalException("ERROR: Could not post collection", ioe);
+        } catch (MissingElementException mee) {
+            throw new InternalException("ERROR: Could not post collection", mee);
+        } catch (UnexpectedRootElementException uree) {
+            throw new InternalException("ERROR: Could not post collection", uree);
+        }
+    }
+    
+    private WeblogEntrySet createWeblogs(WeblogEntrySet c) throws HandlerException {
+        try {
+            UserManager mgr = getRoller().getUserManager();
+            HashMap pages = null; //getRollerContext().readThemeMacros(form.getTheme());
+            
+            List websiteDatas = new ArrayList();
+            for (int i = 0; i < c.getEntries().length; i++) {
+                WeblogEntry entry = (WeblogEntry)c.getEntries()[i];
+                UserData user = mgr.getUserByUsername(entry.getCreatingUser());
+                WebsiteData wd = new WebsiteData(
+                        entry.getHandle(),
+                        user,
+                        entry.getName(),
+                        entry.getDescription(),
+                        entry.getEmailAddress(),
+                        entry.getEmailAddress(),
+                        DEFAULT_THEME,
+                        entry.getLocale().toString(),
+                        entry.getTimezone().getID());
+                
+                Date dateCreated  = entry.getDateCreated();
+                if (dateCreated == null) {
+                    dateCreated = new Date();
+                }
+                wd.setDateCreated(dateCreated);
+                
+                try {
+                    String def = RollerRuntimeConfig.getProperty("users.editor.pages");
+                    String[] defs = Utilities.stringToStringArray(def,",");
+                    wd.setEditorPage(defs[0]);
+                } catch (Exception ex) {
+                    log.error("ERROR setting default editor page for weblog", ex);
+                }
+                
+                mgr.addWebsite(wd);
+                websiteDatas.add(wd);
+            }
+            
+            getRoller().flush();
+            return toWeblogEntrySet((WebsiteData[])websiteDatas.toArray(new WebsiteData[0]));
+            
+        } catch (RollerException re) {
+            throw new InternalException("ERROR: Could not create weblogs: " + c, re);
+        }
+    }
+    
+    private WeblogEntrySet updateWeblogs(WeblogEntrySet c) throws HandlerException {
+        try {
+            UserManager mgr = getRoller().getUserManager();
+            
+            //TODO: group blogging check?
+            
+            HashMap pages = null;
+            
+            List websiteDatas = new ArrayList();
+            for (int i = 0; i < c.getEntries().length; i++) {
+                WeblogEntry entry = (WeblogEntry)c.getEntries()[i];
+                WebsiteData wd = mgr.getWebsiteByHandle(entry.getHandle());
+                if (wd == null) {
+                    throw new NotFoundException("ERROR: Uknown weblog: " + entry.getHandle());
+                }
+                updateWebsiteData(wd, entry);
+                websiteDatas.add(wd);
+            }
+            getRoller().flush();
+            return toWeblogEntrySet((WebsiteData[])websiteDatas.toArray(new WebsiteData[0]));
+        } catch (RollerException re) {
+            throw new InternalException("ERROR: Could not update weblogs: " + c, re);
+        }
+    }
+    
+    private void updateWebsiteData(WebsiteData wd, WeblogEntry entry) throws HandlerException {
+        if (entry.getName() != null) {
+            wd.setName(entry.getName());
+        }
+        if (entry.getDescription() != null) {
+            wd.setDescription(entry.getDescription());
+        }
+        if (entry.getLocale() != null) {
+            wd.setLocale(entry.getLocale().toString());
+        }
+        if (entry.getTimezone() != null) {
+            wd.setTimeZone(entry.getTimezone().getID());
+        }
+        if (entry.getEmailAddress() != null) {
+            wd.setEmailAddress(entry.getEmailAddress());
+        }
+        
+        try {
+            UserManager mgr = getRoller().getUserManager();
+            mgr.saveWebsite(wd);
+            
+            CacheManager.invalidate(wd);
+        } catch (RollerException re) {
+            throw new InternalException("ERROR: Could not update website data", re);
+        }
+    }
+    
+    private EntrySet deleteEntry() throws HandlerException {
+        String handle = getUri().getEntryId();
+        
+        try {
+            UserManager mgr = getRoller().getUserManager();
+            
+            WebsiteData wd = mgr.getWebsiteByHandle(handle);
+            if (wd == null) {
+                throw new NotFoundException("ERROR: Uknown weblog handle: " + handle);
+            }
+            
+            WebsiteData[] wds = new WebsiteData[] { wd };
+            EntrySet es = toWeblogEntrySet(wds);
+            
+            mgr.removeWebsite(wd);
+            
+            CacheManager.invalidate(wd);
+            getRoller().flush();
+            
+            return es;
+        } catch (RollerException re) {
+            throw new InternalException("ERROR: Could not delete entry: " + handle, re);
+        }
+    }
+    
+    private WeblogEntry toWeblogEntry(WebsiteData wd) throws HandlerException {
+        if (wd == null) {
+            throw new NullPointerException("ERROR: Null website data not allowed");
+        }
+        WeblogEntry we = new WeblogEntry(wd.getHandle(), getUrlPrefix());
+        we.setName(wd.getName());
+        we.setDescription(wd.getDescription());
+        we.setLocale(wd.getLocale());
+        we.setTimezone(wd.getTimeZone());
+        we.setCreatingUser(wd.getCreator().getUserName());
+        we.setEmailAddress(wd.getEmailAddress());
+        we.setDateCreated(wd.getDateCreated());
+        try {
+            AppUrl appUrl = new AppUrl(getRollerContext().getAbsoluteContextUrl(getRequest()), wd.getHandle());
+            we.setAppEntriesUrl(appUrl.getEntryUrl().toString());
+            we.setAppResourcesUrl(appUrl.getResourceUrl().toString());
+        } catch (MalformedURLException mfue) {
+            throw new InternalException("ERROR: Could not get APP URLs", mfue);
+        }
+        
+        return we;
+    }
+    
+    private WeblogEntrySet toWeblogEntrySet(UserData[] uds) throws HandlerException {
+        if (uds == null) {
+            throw new NullPointerException("ERROR: Null user data not allowed");
+        }
+        
+        WeblogEntrySet wes = new WeblogEntrySet(getUrlPrefix());
+        List entries = new ArrayList();
+        for (int i = 0; i < uds.length; i++) {
+            UserData ud = uds[i];
+            List permissions = ud.getPermissions();
+            for (Iterator j = permissions.iterator(); j.hasNext(); ) {
+                PermissionsData pd = (PermissionsData)j.next();
+                WebsiteData wd = pd.getWebsite();
+                WeblogEntry we = toWeblogEntry(wd);
+                entries.add(we);
+            }
+        }
+        wes.setEntries((Entry[])entries.toArray(new Entry[0]));
+        
+        return wes;
+    }
+    
+    private WeblogEntrySet toWeblogEntrySet(WebsiteData[] wds) throws HandlerException {
+        if (wds == null) {
+            throw new NullPointerException("ERROR: Null website datas not allowed");
+        }
+        
+        WeblogEntrySet wes = new WeblogEntrySet(getUrlPrefix());
+        List entries = new ArrayList();
+        for (int i = 0; i < wds.length; i++) {
+            WeblogEntry we = toWeblogEntry(wds[i]);
+            entries.add(we);
+        }
+        wes.setEntries((Entry[])entries.toArray(new Entry[0]));
+        
+        return wes;
+    }
+}
+

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/UnauthorizedException.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/UnauthorizedException.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/UnauthorizedException.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/UnauthorizedException.java Fri May  5 10:49:04 2006
@@ -0,0 +1,34 @@
+/*
+* 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.roller.webservices.adminapi;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Indicates to client that an internal error occured when processing
+ * the request.
+ */
+public class UnauthorizedException extends HandlerException { 
+    public UnauthorizedException(String msg) {
+        super(msg);
+    }    
+    
+    public int getStatus() {
+        return HttpServletResponse.SC_UNAUTHORIZED;
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/WSSEAuthenticator.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/WSSEAuthenticator.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/WSSEAuthenticator.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/WSSEAuthenticator.java Fri May  5 10:49:04 2006
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2005 David M Johnson (For RSS and Atom In Action)
+ *
+ * Licensed 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.
+ */
+package org.apache.roller.webservices.adminapi;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.roller.RollerException;
+import org.apache.roller.pojos.UserData;
+import org.apache.roller.util.WSSEUtilities;
+
+/**
+ * This class implements HTTP basic authentication for roller.
+ *
+ * @author jtb
+ */
+class WSSEAuthenticator extends Authenticator {
+    /** Creates a new instance of HttpBasicAuthenticator */
+    public WSSEAuthenticator(HttpServletRequest req) {
+        super(req);
+    }
+    
+    public void authenticate() throws HandlerException {
+        setUserName(null);
+        String wsseHeader = getRequest().getHeader("X-WSSE");
+        if (wsseHeader == null) {
+            throw new UnauthorizedException("ERROR: WSSE header was not set");
+        };
+        
+        String userName = null;
+        String created = null;
+        String nonce = null;
+        String passwordDigest = null;
+        String[] tokens = wsseHeader.split(",");
+        
+        for (int i = 0; i < tokens.length; i++) {
+            int index = tokens[i].indexOf('=');
+            if (index != -1) {
+                String key = tokens[i].substring(0, index).trim();
+                String value = tokens[i].substring(index + 1).trim();
+                value = value.replaceAll("\"", "");
+                if (key.startsWith("UsernameToken")) {
+                    userName = value;
+                } else if (key.equalsIgnoreCase("nonce")) {
+                    nonce = value;
+                } else if (key.equalsIgnoreCase("passworddigest")) {
+                    passwordDigest = value;
+                } else if (key.equalsIgnoreCase("created")) {
+                    created = value;
+                }
+            }
+        }
+        
+        try {
+            UserData user = getRoller().getUserManager().getUser(userName);
+            if (user == null) {
+                throw new UnauthorizedException("ERROR: User does not exist: " + userName);
+            }
+            String digest = WSSEUtilities.generateDigest(WSSEUtilities.base64Decode(nonce), created.getBytes("UTF-8"), user.getPassword().getBytes("UTF-8"));
+            if (digest.equals(passwordDigest)) {
+                setUserName(userName);
+            } else {
+                throw new UnauthorizedException("ERROR: User is not authorized to use the AAPP endpoint: " + userName);
+            }
+        } catch (RollerException re) {
+            throw new InternalException("ERROR: Could not get roller user: " + userName, re);
+        } catch (IOException ioe) {
+            throw new InternalException("ERROR: Could not get roller user: " + userName, ioe);
+        }
+        
+        // make sure the user has the admin role
+        verifyUser();
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Entry.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Entry.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Entry.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Entry.java Fri May  5 10:49:04 2006
@@ -0,0 +1,132 @@
+/*
+* 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.
+*/
+/*
+ * Entry.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import org.jdom.Document;
+import org.jdom.Namespace;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+/**
+ * This class is the abstract notion of an entry.
+ * Weblog resources are represented by sets of entries.
+ *
+ * @author jtb
+ */
+public abstract class Entry {
+    protected static final Namespace NAMESPACE = Namespace.getNamespace("http://purl.org/roller/aapp#");
+    
+    /** Entry types. */
+    public static interface Types {
+        /** 
+         * User entry.
+         * A user entry is contained within a user entry set.
+         */
+        public static final String USER = "user";
+        /**
+         * Weblog entry.
+         * A weblog entry is contained within a weblog entry set.
+         */
+        public static final String WEBLOG = "weblog";
+        /**
+         * Member entry.
+         * A member entry is contained within a member entry set.
+         */
+        public static final String MEMBER = "member";
+        /**
+         * Collection entry.
+         * A collection entry is contained within a workspace, which is
+         * contained within a service.
+         */
+        public static final String COLLECTION = "collection";
+    }
+    
+    /** XML attributes common to all entry types. */
+    protected static interface Attributes {
+        public static final String HREF = "href";
+    }
+    
+    private String href = null;
+    
+    /** Get the HREF that identifies this entry. */
+    public String getHref() {
+        return href;
+    }
+    
+    /** Set the HREF that identifies this entry. */
+    public void setHref(String href) {
+        this.href = href;
+    }
+    
+    /** This entry, as a JDOM Document object. */
+    public abstract Document toDocument();
+    
+    /** 
+     * This entry, as a String (XML).
+     */
+    public String toString() {
+        Writer writer = new StringWriter();
+        XMLOutputter outputter = new XMLOutputter();
+        outputter.setFormat(Format.getPrettyFormat());
+        try {
+            outputter.output(toDocument(), writer);
+            writer.close();
+        } catch (IOException ioe) {
+            throw new IllegalStateException(ioe.getMessage());
+        }
+        
+        return writer.toString();
+    }
+    
+    public abstract String getType();
+    
+    public boolean equals(Object o) {
+        if ( o == null || o.getClass() != this.getClass()) { 
+            return false;        
+        }
+                
+        Entry other = (Entry)o;
+        
+        if (!areEqual(getHref(), other.getHref())) {
+            return false;
+        }
+        if (!areEqual(getType(), other.getType())) {
+            return false;
+        }
+        
+        return true;
+    }
+    
+    protected static boolean areEqual(Object o1, Object o2) {
+        return o1 == null ? o2 == null : o1.equals(o2);
+    }
+    
+    protected static boolean areEqual(Object[] oa1, Object[] oa2) {
+        return oa1 == null ? oa2 == null : Arrays.equals(oa1, oa2);
+    }    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/EntrySet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/EntrySet.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/EntrySet.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/EntrySet.java Fri May  5 10:49:04 2006
@@ -0,0 +1,121 @@
+/*
+* 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.
+*/
+/*
+ * EntrySet.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.util.Arrays;
+import java.util.List;
+import org.jdom.Document;
+import org.jdom.Element;
+
+/**
+ * This class is the abstract notion of a set of entries.
+ * Weblog resources are represented by sets of entries. 
+ *
+ * @author jtb
+ */
+public abstract class EntrySet extends Entry {
+    /** Entry set types. */
+    public static interface Types {
+        /*
+         * Set of user entries. 
+         * A user entry describes a user of the weblog server.
+         */
+        public static final String USERS = "users";
+        /** 
+         * Set of weblog entries. 
+         * Note that this is not a set of entries in a weblog, but rather,
+         * a set of entries that describe the weblog itself.
+         */
+        public static final String WEBLOGS = "weblogs";
+        /** 
+         * Set of member entries.
+         * A member entry describes a user's membership to and 
+         * permission with a particular weblog.
+         */
+        public static final String MEMBERS = "members";
+         /**
+          * Set of workspace entries.
+          * This type, along with WORKSPACE and COLLECTION, define
+          * the element that describe the introspection document
+          * for the AAPP service.
+          * <p>
+          * A service is a set of workspaces, and a workspace is a set of 
+          * collections.
+          */
+        public static final String SERVICE = "service";        
+        /** Set of collection entries. */
+        public static final String WORKSPACE = "workspace";           
+    }
+    
+    private List entries = null;
+        
+    /** Get the type of this object. */
+    public abstract String getType();
+    
+    /** Get the entries in this object. */
+    public Entry[] getEntries() {
+        return (Entry[])entries.toArray(new Entry[0]);
+    }
+    
+    /** Set the entries of this object. */
+    public void setEntries(Entry[] entryArray) {
+        entries = Arrays.asList(entryArray);
+    }
+    
+    /** This object as a JDOM Document */
+    public Document toDocument() {
+        Element e = new Element(getType(), NAMESPACE);
+        Document doc = new Document(e);
+        
+        // href
+        e.setAttribute(Attributes.HREF, getHref());
+        
+        // entries
+        for (int i = 0; i < getEntries().length; i++) {
+            e.addContent(getEntries()[i].toDocument().detachRootElement());
+        }
+        
+        return doc;
+    }
+   
+    public boolean equals(Object o) {
+        if ( o == null || o.getClass() != this.getClass()) { 
+            return false;        
+        }
+                
+        EntrySet other = (EntrySet)o;
+        
+        if (!areEqual(getHref(), other.getHref())) {
+            return false;
+        }
+        if (!areEqual(getType(), other.getType())) {
+            return false;
+        }        
+        if (!areEqual(getEntries(), other.getEntries())) {
+            return false;
+        }
+        
+        return true;
+    }    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/LocaleString.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/LocaleString.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/LocaleString.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/LocaleString.java Fri May  5 10:49:04 2006
@@ -0,0 +1,53 @@
+/*
+* 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.roller.webservices.adminapi.sdk;
+
+import java.util.Locale;
+
+class LocaleString {
+    private Locale locale;
+    
+    public LocaleString(String localeString) {
+        if (localeString == null) {
+            locale = null;
+            return;
+        }
+        
+        String[] components = localeString.split("_");
+        
+        if (components == null) {
+            locale = null;
+            return;
+        }
+                
+        if (components.length == 1) {
+            locale = new Locale(components[0]);
+        } else if (components.length == 2) {
+            locale = new Locale(components[0], components[1]);
+        } else if (components.length == 3) {
+            locale = new Locale(components[0], components[1], components[2]);
+        } else {
+            throw new IllegalArgumentException("invalid locale string: " + localeString);
+        }
+    }
+    
+    public Locale getLocale() {
+        return locale;
+    }
+    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntry.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntry.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntry.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntry.java Fri May  5 10:49:04 2006
@@ -0,0 +1,182 @@
+/*
+* 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.
+*/
+/*
+ * MemberEntry.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.io.InputStream;
+import java.io.IOException;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.Text;
+import org.jdom.input.SAXBuilder;
+import org.jdom.JDOMException;
+import org.apache.roller.webservices.adminapi.sdk.Entry.Attributes;
+import org.apache.roller.webservices.adminapi.sdk.Entry.Types;
+
+/**
+ * This class describes a member entry. 
+ * A member entry is a triple consisting of a user name, a weblog handle,
+ * and a permission.
+ */
+public class MemberEntry extends Entry {
+    /** Member permissions */
+    public interface Permissions {
+        public static final String ADMIN = "ADMIN";
+        public static final String AUTHOR = "AUTHOR";
+        public static final String LIMITED = "LIMITED";
+    }
+    
+    static interface Tags {
+        public static final String MEMBER = "member";
+        public static final String NAME = "name";
+        public static final String HANDLE = "handle";
+        public static final String PERMISSION = "permission";
+    }     
+    
+    private String name;
+    private String handle;
+    private String permission;
+    
+    public MemberEntry(Element e, String urlPrefix) throws MissingElementException {
+        populate(e, urlPrefix);
+    }
+    
+    public MemberEntry(String handle, String userName, String urlPrefix) {
+        String href = urlPrefix + "/" + EntrySet.Types.MEMBERS + "/" + handle + "/" + userName;       
+	setHref(href);
+        setHandle(handle);
+        setName(userName);
+    }
+
+    public MemberEntry(InputStream stream, String urlPrefix) throws JDOMException, IOException, MissingElementException {               
+        SAXBuilder sb = new SAXBuilder();
+        Document d = sb.build(stream);
+        Element e = d.detachRootElement();
+        
+        populate(e, urlPrefix);        
+    }
+
+    private void populate(Element e, String urlPrefix) throws MissingElementException {
+        // name
+        Element nameElement = e.getChild(Tags.NAME, NAMESPACE);
+        if (nameElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.NAME);
+        }
+        setName(nameElement.getText());
+                
+        // handle
+        Element handleElement = e.getChild(Tags.HANDLE, NAMESPACE);
+        if (handleElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.HANDLE);
+        }
+        setHandle(handleElement.getText());
+
+        // href
+        setHref(urlPrefix + "/" + EntrySet.Types.MEMBERS + "/" + getHandle() + "/" + getName()); 
+        
+        // password
+        Element permissionElement = e.getChild(Tags.PERMISSION, NAMESPACE);
+        if (permissionElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.PERMISSION);
+        }
+        setPermission(permissionElement.getText());
+    }
+    
+    
+    public String getType() {
+        return Types.MEMBER;
+    }
+    
+    public Document toDocument() {
+        Element member = new Element(Tags.MEMBER, NAMESPACE);
+        Document doc = new Document(member);
+        
+        // href
+        member.setAttribute(Attributes.HREF, getHref());
+               
+        // name
+        Element name = new Element(Tags.NAME, Service.NAMESPACE);
+        Text nameText = new Text(getName());
+        name.addContent(nameText);
+        member.addContent(name);
+       
+        // handle
+        Element handle = new Element(Tags.HANDLE, NAMESPACE);
+        Text handleText = new Text(getHandle());
+        handle.addContent(handleText);
+        member.addContent(handle);
+        
+        // permission
+        Element permission = new Element(Tags.PERMISSION, NAMESPACE);
+        Text permissionText = new Text(getPermission());
+        permission.addContent(permissionText);
+        member.addContent(permission);
+                
+        return doc;
+    }
+
+    public boolean equals(Object o) {
+        if ( o == null || o.getClass() != this.getClass()) { 
+            return false;        
+        }
+        
+        MemberEntry other = (MemberEntry)o;
+        
+        if (!areEqual(getHandle(), other.getHandle())) {
+            return false;
+        }
+        if (!areEqual(getName(), other.getName())) {
+            return false;
+        }
+        if (!areEqual(getPermission(), other.getPermission())) {
+            return false;
+        }
+        
+        return super.equals(o);
+    }
+    
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getHandle() {
+        return handle;
+    }
+
+    public void setHandle(String handle) {
+        this.handle = handle;
+    }
+
+    public String getPermission() {
+        return permission;
+    }
+    
+    public void setPermission(String permission) {
+        this.permission = permission;
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntrySet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntrySet.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntrySet.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MemberEntrySet.java Fri May  5 10:49:04 2006
@@ -0,0 +1,84 @@
+/*
+* 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.
+*/
+/*
+ * WeblogEntrySet.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.apache.roller.webservices.adminapi.sdk.EntrySet.Types;
+
+/**
+ * This class describes a set of member entries. 
+ *
+ * @author jtb
+ */
+public class MemberEntrySet extends EntrySet {
+    static interface Tags {
+        public static final String MEMBERS = "members";
+    }       
+        
+    public MemberEntrySet(String urlPrefix) {
+        setHref(urlPrefix + "/" + Types.MEMBERS);        
+    }    
+
+    public MemberEntrySet(Document d, String urlPrefix) throws MissingElementException, UnexpectedRootElementException {
+        populate(d, urlPrefix);
+    }
+    
+    public MemberEntrySet(InputStream stream, String urlPrefix) throws JDOMException, IOException, MissingElementException, UnexpectedRootElementException {               
+        SAXBuilder sb = new SAXBuilder();
+        Document d = sb.build(stream);
+
+        populate(d, urlPrefix);        
+    }    
+    
+    private void populate(Document d, String urlPrefix) throws MissingElementException, UnexpectedRootElementException {
+        Element root = d.getRootElement();
+        String rootName = root.getName();
+        if (!rootName.equals(Tags.MEMBERS)) {
+            throw new UnexpectedRootElementException("ERROR: Incorrect root element", Tags.MEMBERS, rootName);
+        }
+        List members = root.getChildren(MemberEntry.Tags.MEMBER, NAMESPACE);
+        if (members != null) {
+            List entries = new ArrayList();
+            for (Iterator i = members.iterator(); i.hasNext(); ) {
+                Element member = (Element)i.next();
+                MemberEntry entry = new MemberEntry(member, urlPrefix);
+                entries.add(entry);
+            }
+            setEntries((Entry[])entries.toArray(new Entry[0]));
+        }
+        setHref(urlPrefix + "/" + Types.MEMBERS);
+    }
+        
+    public String getType() {
+        return Types.MEMBERS;
+    }    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MissingElementException.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MissingElementException.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MissingElementException.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/MissingElementException.java Fri May  5 10:49:04 2006
@@ -0,0 +1,32 @@
+/*
+* 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.roller.webservices.adminapi.sdk;
+
+public class MissingElementException extends Exception {
+    private String parent;
+    private String child;
+    
+    public MissingElementException(String msg, String parent, String child) {
+        this.parent = parent;
+        this.child = child;
+    }
+    
+    public String getMessage() {
+        return super.getMessage() + ": expected element " + child + " as a child of element " + parent;
+    }    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Service.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Service.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Service.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/Service.java Fri May  5 10:49:04 2006
@@ -0,0 +1,157 @@
+/*
+* 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.
+*/
+/*
+ * AtomAdminService.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.Namespace;
+import org.jdom.filter.Filter;
+
+/**
+ * This class describes an AAPP service (introspection document).
+ * A Service is a set of workspaces, which is a set of
+ * collections.
+ *
+ * @author jtb
+ */
+
+public class Service extends EntrySet {
+    /** This class describes a service workspace. */    
+    public static class Workspace extends EntrySet {        
+        /** This class describes a workspace collection. */
+        public static class Collection extends Entry {
+            private static interface Tags {
+                public static final String MEMBER_TYPE = "member-type";
+            }
+            
+            private static interface Attributes {
+                public static final String TITLE = "title";
+            }
+            
+            private String title;
+            private String memberType;
+            
+            public Collection() {
+                // nothing
+            }
+            
+            public String getType() {
+                return Types.COLLECTION;
+            }
+            
+            public String getTitle() {
+                return title;
+            }
+            
+            public void setTitle(String title) {
+                this.title = title;
+            }
+            
+            
+            public Document toDocument() {
+                Document doc = new Document();
+                Element element = new Element(Types.COLLECTION, NAMESPACE);
+                doc.setRootElement(element);
+                
+                element.setAttribute(Attributes.TITLE, getTitle());
+                element.setAttribute(Entry.Attributes.HREF, getHref());
+                
+                Element memberType = new Element(Tags.MEMBER_TYPE, NAMESPACE);
+                memberType.setText(getMemberType());
+                element.addContent(memberType);
+                
+                return doc;
+            }
+            
+            public String getMemberType() {
+                return memberType;
+            }
+            
+            public void setMemberType(String memberType) {
+                this.memberType = memberType;
+            }
+            
+        }
+        
+        private static interface Attributes {
+            public static final String TITLE = "title";
+        }
+        
+        private String title = null;
+        
+        public Workspace() {
+        }
+        
+        public String getType() {
+            return Types.WORKSPACE;
+        }
+        
+        public String getTitle() {
+            return title;
+        }
+        
+        public void setTitle(String title) {
+            this.title = title;
+        }
+        
+        
+        public Document toDocument() {
+            Document doc = new Document();
+            Element element = new Element(EntrySet.Types.WORKSPACE, NAMESPACE);
+            doc.setRootElement(element);
+            
+            element.setAttribute(Attributes.TITLE, getTitle());
+            for (int i = 0; i < getEntries().length; i++) {
+                Entry entry = getEntries()[i];
+                element.addContent(entry.toDocument().detachRootElement());
+            }
+            
+            return doc;
+        }
+    }
+    
+    public Service(String href) {
+        setHref(href);
+    }
+    
+    public String getType() {
+        return Types.SERVICE;
+    }
+    
+    public Document toDocument() {
+        Document doc = new Document();
+        Element root = new Element(Types.SERVICE, NAMESPACE);
+        doc.setRootElement(root);
+        
+        for (int i = 0; i < getEntries().length; i++) {
+            Entry entry = getEntries()[i];
+            root.addContent(entry.toDocument().detachRootElement());
+        }
+        
+        return doc;
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UnexpectedRootElementException.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UnexpectedRootElementException.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UnexpectedRootElementException.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UnexpectedRootElementException.java Fri May  5 10:49:04 2006
@@ -0,0 +1,32 @@
+/*
+* 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.roller.webservices.adminapi.sdk;
+
+public class UnexpectedRootElementException extends Exception {
+    private String expected;
+    private String actual;
+    
+    public UnexpectedRootElementException(String msg, String expected, String actual) {
+        this.expected = expected;
+        this.actual = actual;
+    }
+    
+    public String getMessage() {
+        return super.getMessage() + ": expected root element:  " + expected + ", was: " + actual;
+    }    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntry.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntry.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntry.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntry.java Fri May  5 10:49:04 2006
@@ -0,0 +1,326 @@
+/*
+* 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.
+*/
+/*
+ * UserEntry.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.Text;
+import org.jdom.input.SAXBuilder;
+import org.apache.roller.webservices.adminapi.sdk.Entry.Attributes;
+import org.apache.roller.webservices.adminapi.sdk.Entry.Types;
+
+/**
+ * This class describes a user entry; a user weblog resource.
+ * @author jtb
+ */
+public class UserEntry extends Entry {
+    /** XML tags that define a user entry. */
+    static interface Tags {
+        public static final String USER = "user";
+        public static final String NAME = "name";
+        public static final String FULL_NAME = "full-name";
+        public static final String PASSWORD = "password";
+        public static final String EMAIL_ADDRESS = "email-address";
+        public static final String LOCALE = "locale";
+        public static final String TIMEZONE = "timezone";
+        public static final String DATE_CREATED = "date-created";
+    }
+    
+    private String name;
+    private String fullName;
+    private String password;
+    private Locale locale;
+    private TimeZone timezone;
+    private Date dateCreated;
+    private String emailAddress;
+    
+    /** Construct an empty user entry */
+    public UserEntry(String name, String urlPrefix) {
+        setName(name);
+        String href = urlPrefix + "/" + EntrySet.Types.USERS + "/" + name;                
+        setHref(href);
+    }
+    
+    /** Construct a user entry from a JDOM element. */
+    public UserEntry(Element e, String urlPrefix) throws MissingElementException {
+        populate(e, urlPrefix);
+    }
+    
+    public UserEntry(InputStream stream, String urlPrefix) throws JDOMException, IOException, MissingElementException {               
+        SAXBuilder sb = new SAXBuilder();
+        Document d = sb.build(stream);
+        Element e = d.detachRootElement();
+        
+        populate(e, urlPrefix);        
+    }
+    
+    private void populate(Element e, String urlPrefix) throws MissingElementException {
+        // name
+        Element nameElement = e.getChild(Tags.NAME, NAMESPACE);
+        if (nameElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.NAME);
+        }
+        setName(nameElement.getText());
+        
+        // href
+        String href = urlPrefix + "/" + EntrySet.Types.USERS + "/" + getName();
+        setHref(href);
+        
+        // full name
+        Element fullNameElement = e.getChild(Tags.FULL_NAME, NAMESPACE);
+        if (fullNameElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.FULL_NAME);
+        }
+        setFullName(fullNameElement.getText());
+        
+        // password
+        // this is optional
+        Element passwordElement = e.getChild(Tags.PASSWORD, NAMESPACE);
+        if (passwordElement != null) {
+            setPassword(passwordElement.getText());            
+        }
+        
+        // locale
+        Element localeElement = e.getChild(Tags.LOCALE, Service.NAMESPACE);
+        if (localeElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.LOCALE);
+        }
+        setLocale(localeElement.getText());
+        
+        // timezone
+        Element tzElement = e.getChild(Tags.TIMEZONE, Service.NAMESPACE);
+        if (tzElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.TIMEZONE);
+        }
+        setTimezone(tzElement.getText());
+        
+        // email address
+        Element emailElement = e.getChild(Tags.EMAIL_ADDRESS, Service.NAMESPACE);
+        if (emailElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.EMAIL_ADDRESS);
+        }
+        setEmailAddress(emailElement.getText());
+        
+        // created (optional)
+        Element createdElement = e.getChild(Tags.DATE_CREATED, Service.NAMESPACE);
+        if (createdElement != null) {
+            setDateCreated(new Date(Long.valueOf(createdElement.getText()).longValue()));
+        }
+    }
+    
+        
+    public String getType() {
+        return Types.USER;
+    }
+    
+    public Document toDocument() {
+        Element userElement = new Element(Tags.USER, NAMESPACE);
+        Document doc = new Document(userElement);
+        
+        // href
+        String href = getHref();
+        if (href != null) {
+            userElement.setAttribute(Attributes.HREF, href);
+        }
+        
+        // name
+        String name = getName();
+        if (name != null) {
+            Element nameElement = new Element(Tags.NAME, Service.NAMESPACE);
+            Text nameText = new Text(getName());
+            nameElement.addContent(nameText);
+            userElement.addContent(nameElement);
+        }
+        
+        // full name
+        String fullName = getFullName();
+        if (fullName != null) {
+            Element fullNameElement = new Element(Tags.FULL_NAME, NAMESPACE);
+            Text fullNameText = new Text(getFullName());
+            fullNameElement.addContent(fullNameText);
+            userElement.addContent(fullNameElement);
+        }
+        
+        // password
+        String password = getPassword();
+        if (password != null) {
+            Element passwordElement = new Element(Tags.PASSWORD, NAMESPACE);
+            Text passwordText = new Text(getPassword());
+            passwordElement.addContent(passwordText);
+            userElement.addContent(passwordElement);
+        }
+        
+        // locale
+        Locale locale = getLocale();
+        if (locale != null ) {
+            Element localeElement = new Element(Tags.LOCALE, Service.NAMESPACE);
+            Text localeText = new Text(getLocale().toString());
+            localeElement.addContent(localeText);
+            userElement.addContent(localeElement);
+        }
+        
+        // timezone
+        TimeZone timezone = getTimezone();
+        if (timezone != null) {
+            Element timezoneElement = new Element(Tags.TIMEZONE, Service.NAMESPACE);
+            Text timezoneText = new Text(timezone.getID());
+            timezoneElement.addContent(timezoneText);
+            userElement.addContent(timezoneElement);
+        }
+        
+        // email address
+        String emailAddress = getEmailAddress();
+        if (emailAddress != null) {
+            Element emailAddressElement = new Element(Tags.EMAIL_ADDRESS, Service.NAMESPACE);
+            Text emailAddressText = new Text(String.valueOf(emailAddress));
+            emailAddressElement.addContent(emailAddressText);
+            userElement.addContent(emailAddressElement);
+        }
+        
+        // creation date (optional)
+        Date datedCreated = getDateCreated();
+        if (dateCreated != null) {
+            Element dateCreatedElement = new Element(Tags.DATE_CREATED, Service.NAMESPACE);
+            Text dateCreatedText = new Text(String.valueOf(dateCreated.getTime()));
+            dateCreatedElement.addContent(dateCreatedText);
+            userElement.addContent(dateCreatedElement);
+        }
+        
+        return doc;
+    }
+    
+    /** Get the user name of this user entry. */
+    public String getName() {
+        return name;
+    }
+    
+    /** Set of the user name of this user entry. */
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    /** Get the full name of this user entry. */
+    public String getFullName() {
+        return fullName;
+    }
+    
+    /** Set the full name of this user entry. */
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+    
+    /** Get the password of this user entry. */
+    public String getPassword() {
+        return password;
+    }
+    
+    /** Set the password of this user entry. */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+    
+    /** Get the locale string of this user entry. */
+    public Locale getLocale() {
+        return locale;
+    }
+    
+    /** Set the locale of this user entry. */
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+    
+    /** Set the locale string of this user entry. */
+    public void setLocale(String localeString) {
+        this.locale = new LocaleString(localeString).getLocale();
+    }    
+    
+    /** Get the timezone string of this user entry. */
+    public TimeZone getTimezone() {
+        return timezone;
+    }
+    
+    /** Set the timezone of this user entry. */
+    public void setTimezone(TimeZone timezone) {
+        this.timezone = timezone;
+    }
+
+    /** Set the timezone string of this user entry. */
+    public void setTimezone(String timezoneString) {
+        this.timezone = TimeZone.getTimeZone(timezoneString);
+    }
+    
+    /** Get the date created of this user entry. */
+    public Date getDateCreated() {
+        return dateCreated;
+    }
+    
+    /** Set the date created of this user entry. */
+    public void setDateCreated(Date dateCreated) {
+        this.dateCreated = dateCreated;
+    }
+    
+    /** Get the email address of this user entry. */
+    public String getEmailAddress() {
+        return emailAddress;
+    }
+    
+    /** Set the email address of this user entry. */
+    public void setEmailAddress(String emailAddress) {
+        this.emailAddress = emailAddress;
+    }
+    
+    /** Test if a user entry is equal to this user entry. */
+    public boolean equals(Object o) {
+        if ( o == null || o.getClass() != this.getClass()) { 
+            return false;        
+        }
+        
+        UserEntry other = (UserEntry)o;
+        
+        if (!areEqual(getEmailAddress(), other.getEmailAddress())) {
+            return false;
+        }
+        if (!areEqual(getFullName(), other.getFullName())) {
+            return false;
+        }
+        if (!areEqual(getLocale(), other.getLocale())) {
+            return false;
+        }
+        if (!areEqual(getName(), other.getName())) {
+            return false;
+        }
+        if (!areEqual(getTimezone(), other.getTimezone())) {
+            return false;
+        }
+        
+        return super.equals(o);
+    }
+    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntrySet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntrySet.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntrySet.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/UserEntrySet.java Fri May  5 10:49:04 2006
@@ -0,0 +1,86 @@
+/*
+* 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.
+*/
+/*
+ * UserEntrySet.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.apache.roller.webservices.adminapi.sdk.EntrySet.Types;
+
+/**
+ * This class describes a set of user entries. 
+ * @author jtb
+ */
+public class UserEntrySet extends EntrySet {
+    /** XML tags that describe a set of user entries. */
+    private static interface Tags {
+        public static final String USERS = "users";
+    }       
+        
+    /** Construct based on an array of Roller UserData objects. */
+    public UserEntrySet(String urlPrefix) {
+        setHref(urlPrefix + "/" + Types.USERS);
+    }
+    
+    /** Construct based on a JDOM Document object. */
+    public UserEntrySet(Document d, String urlPrefix) throws MissingElementException, UnexpectedRootElementException {
+        populate(d, urlPrefix);
+    }
+    
+    public UserEntrySet(InputStream stream, String urlPrefix) throws JDOMException, IOException, MissingElementException, UnexpectedRootElementException {               
+        SAXBuilder sb = new SAXBuilder();
+        Document d = sb.build(stream);
+
+        populate(d, urlPrefix);        
+    }        
+    
+    private void populate(Document d, String urlPrefix) throws MissingElementException, UnexpectedRootElementException {
+        Element root = d.getRootElement();
+        String rootName = root.getName();
+        if (!rootName.equals(Tags.USERS)) {
+            throw new UnexpectedRootElementException("ERROR: Unexpected root element", Tags.USERS, rootName);
+        }
+        List users = root.getChildren(UserEntry.Tags.USER, NAMESPACE);
+        if (users != null) {
+            List entries = new ArrayList();
+            for (Iterator i = users.iterator(); i.hasNext(); ) {
+                Element user = (Element)i.next();
+                UserEntry entry = new UserEntry(user, urlPrefix);
+                entries.add(entry);
+            }
+            setEntries((Entry[])entries.toArray(new Entry[0]));
+        }
+        setHref(urlPrefix + "/" + Types.USERS);
+    }    
+        
+    public String getType() {
+        return Types.USERS;
+    }    
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntry.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntry.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntry.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntry.java Fri May  5 10:49:04 2006
@@ -0,0 +1,360 @@
+/*
+* 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.roller.webservices.adminapi.sdk;
+/*
+ * WeblogEntry.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.Text;
+import org.jdom.input.SAXBuilder;
+import org.apache.roller.webservices.adminapi.sdk.Entry.Attributes;
+import org.apache.roller.webservices.adminapi.sdk.Entry.Types;
+
+/**
+ * This class describes a weblog entry. 
+ */
+public class WeblogEntry extends Entry {
+    static interface Tags {
+        public static final String WEBLOG = "weblog";
+        public static final String HANDLE = "handle";
+        public static final String NAME = "name";
+        public static final String DESCRIPTION = "description";
+        public static final String LOCALE = "locale";
+        public static final String TIMEZONE = "timezone";
+        public static final String DATE_CREATED = "date-created";
+        public static final String CREATING_USER = "creating-user";
+        public static final String EMAIL_ADDRESS = "email-address";
+        public static final String APP_ENTRIES_URL = "app-entries-url";        
+        public static final String APP_RESOURCES_URL = "app-resources-url";                
+    }
+    
+    private String handle;
+    private String name;
+    private String description;
+    private Locale locale;
+    private TimeZone timezone;
+    private Date dateCreated;
+    private String creatingUser;
+    private String emailAddress;
+    private String appEntriesUrl;
+    private String appResourcesUrl;
+    
+    public WeblogEntry(Element e, String urlPrefix) throws MissingElementException {
+        populate(e, urlPrefix);
+    }
+    
+    public WeblogEntry(InputStream stream, String urlPrefix) throws JDOMException, IOException, MissingElementException {               
+        SAXBuilder sb = new SAXBuilder();
+        Document d = sb.build(stream);
+        Element e = d.detachRootElement();
+        
+        populate(e, urlPrefix);        
+    }
+    
+    private void populate(Element e, String urlPrefix) throws MissingElementException {
+        // handle
+        Element handleElement = e.getChild(Tags.HANDLE, Service.NAMESPACE);
+        if (handleElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.HANDLE);
+        }
+        setHandle(handleElement.getText());
+        
+        // href
+        String href = urlPrefix + "/" + EntrySet.Types.WEBLOGS + "/" + getHandle();        
+        setHref(href);        
+        
+        // name
+        Element nameElement = e.getChild(Tags.NAME, Service.NAMESPACE);
+        if (nameElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.NAME);
+        }
+        setName(nameElement.getText());
+        
+        // description
+        Element descElement = e.getChild(Tags.DESCRIPTION, Service.NAMESPACE);
+        if (descElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.DESCRIPTION);
+        }
+        setDescription(descElement.getText());
+        
+        // locale
+        Element localeElement = e.getChild(Tags.LOCALE, Service.NAMESPACE);
+        if (localeElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.LOCALE);
+        }
+        setLocale(localeElement.getText());
+        
+        // timezone
+        Element tzElement = e.getChild(Tags.TIMEZONE, Service.NAMESPACE);
+        if (tzElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.TIMEZONE);
+        }
+        setTimezone(tzElement.getText());
+        
+        // creator
+        Element creatorElement = e.getChild(Tags.CREATING_USER, Service.NAMESPACE);
+        if (creatorElement == null) {
+            throw new MissingElementException("ERROR: Missing element", e.getName(), Tags.CREATING_USER);
+        }
+        setCreatingUser(creatorElement.getText());
+        
+        // email address
+        Element emailElement = e.getChild(Tags.EMAIL_ADDRESS, Service.NAMESPACE);
+        if (emailElement == null) {
+            throw new MissingElementException("ERROR: Missing element: ", e.getName(), Tags.EMAIL_ADDRESS);
+        }
+        setEmailAddress(emailElement.getText());        
+        
+        // created (optional)
+        Element createdElement = e.getChild(Tags.DATE_CREATED, Service.NAMESPACE);
+        if (createdElement != null) {
+            setDateCreated(new Date(Long.valueOf(createdElement.getText()).longValue()));
+        }              
+        
+        // APP entries URL (optional)
+        Element appEntriesUrlElement = e.getChild(Tags.APP_ENTRIES_URL, Service.NAMESPACE);
+        if (appEntriesUrlElement != null) {
+            setAppEntriesUrl(appEntriesUrlElement.getText());
+        }                      
+        
+        // APP resources URL (optional)
+        Element appResourcesUrlElement = e.getChild(Tags.APP_RESOURCES_URL, Service.NAMESPACE);
+        if (appResourcesUrlElement != null) {
+            setAppResourcesUrl(appResourcesUrlElement.getText());
+        }                              
+    }
+    
+    
+    public WeblogEntry(String handle, String urlPrefix) {
+        String href = urlPrefix + "/" + EntrySet.Types.WEBLOGS + "/" + handle;        
+        setHref(href);
+        setHandle(handle);
+    }
+    
+    public String getType() {
+        return Types.WEBLOG;
+    }
+    
+    public Document toDocument() {        
+        Element weblog = new Element(Tags.WEBLOG, Service.NAMESPACE);
+        Document doc = new Document(weblog);
+        
+        // link
+        weblog.setAttribute(Attributes.HREF, getHref());
+        
+        // handle
+        Element handle = new Element(Tags.HANDLE, Service.NAMESPACE);
+        Text handleText = new Text(getHandle());
+        handle.addContent(handleText);
+        weblog.addContent(handle);
+        
+        // name
+        Element name = new Element(Tags.NAME, Service.NAMESPACE);
+        Text nameText = new Text(getName());
+        name.addContent(nameText);
+        weblog.addContent(name);
+        
+        // description
+        Element desc = new Element(Tags.DESCRIPTION, Service.NAMESPACE);
+        Text descText = new Text(getDescription());
+        desc.addContent(descText);
+        weblog.addContent(desc);
+        
+        // locale
+        Element locale = new Element(Tags.LOCALE, Service.NAMESPACE);
+        Text localeText = new Text(getLocale().toString());
+        locale.addContent(localeText);
+        weblog.addContent(locale);
+        
+        // timezone
+        Element tz = new Element(Tags.TIMEZONE, Service.NAMESPACE);
+        Text tzText = new Text(getTimezone().getID());
+        tz.addContent(tzText);
+        weblog.addContent(tz);
+        
+        // creating user
+        Element creator = new Element(Tags.CREATING_USER, Service.NAMESPACE);
+        Text creatorText = new Text(String.valueOf(getCreatingUser()));
+        creator.addContent(creatorText);
+        weblog.addContent(creator);
+        
+        // email address
+        Element email = new Element(Tags.EMAIL_ADDRESS, Service.NAMESPACE);
+        Text emailText = new Text(String.valueOf(getEmailAddress()));
+        email.addContent(emailText);
+        weblog.addContent(email);        
+        
+        // creation date (optional)
+        Element created = new Element(Tags.DATE_CREATED, Service.NAMESPACE);
+        Date datedCreated = getDateCreated();
+        if (dateCreated != null) {
+            Text createdText = new Text(String.valueOf(dateCreated.getTime()));
+            created.addContent(createdText);
+            weblog.addContent(created);
+        }
+
+        // APP entries URL (optional)
+        Element appEntriesUrlElement = new Element(Tags.APP_ENTRIES_URL, Service.NAMESPACE);
+        String appEntriesUrl = getAppEntriesUrl();
+        if (appEntriesUrl != null) {
+            Text appEntriesUrlText = new Text(appEntriesUrl);
+            appEntriesUrlElement.addContent(appEntriesUrlText);
+            weblog.addContent(appEntriesUrlElement);
+        }
+
+        // APP entries URL (optional)
+        Element appResourcesUrlElement = new Element(Tags.APP_RESOURCES_URL, Service.NAMESPACE);
+        String appResourcesUrl = getAppResourcesUrl();
+        if (appResourcesUrl != null) {
+            Text appResourcesUrlText = new Text(appResourcesUrl);
+            appResourcesUrlElement.addContent(appResourcesUrlText);
+            weblog.addContent(appResourcesUrlElement);
+        }
+        
+        return doc;
+    }    
+
+    /** Test if a user entry is equal to this user entry. */
+    public boolean equals(Object o) {
+        if ( o == null || o.getClass() != this.getClass()) { 
+            return false;        
+        }
+        
+        WeblogEntry other = (WeblogEntry)o;
+        
+        if (!areEqual(getEmailAddress(), other.getEmailAddress())) {
+            return false;
+        }
+        if (!areEqual(getHandle(), other.getHandle())) {
+            return false;
+        }
+        if (!areEqual(getLocale(), other.getLocale())) {
+            return false;
+        }
+        if (!areEqual(getName(), other.getName())) {
+            return false;
+        }
+        if (!areEqual(getDescription(), other.getDescription())) {
+            return false;
+        }
+        if (!areEqual(getTimezone(), other.getTimezone())) {
+            return false;
+        }
+        
+        return super.equals(o);
+    }
+    
+    public String getHandle() {
+        return handle;
+    }
+    
+    public void setHandle(String handle) {
+        this.handle = handle;
+    }
+    
+    public String getDescription() {
+        return description;
+    }
+    
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    
+    public Locale getLocale() {
+        return locale;
+    }
+    
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+    
+    public void setLocale(String localeString) {
+        this.locale = new LocaleString(localeString).getLocale();
+    }    
+    
+    
+    public TimeZone getTimezone() {
+        return timezone;
+    }
+    
+    public void setTimezone(TimeZone timezone) {
+        this.timezone = timezone;
+    }
+
+    public void setTimezone(String timezoneString) {
+        this.timezone = TimeZone.getTimeZone(timezoneString);
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public Date getDateCreated() {
+        return dateCreated;
+    }
+    
+    public void setDateCreated(Date dateCreated) {
+        this.dateCreated = dateCreated;
+    }
+    
+    public String getCreatingUser() {
+        return creatingUser;
+    }
+    
+    public void setCreatingUser(String creatingUser) {
+        this.creatingUser = creatingUser;
+    }
+
+    public String getEmailAddress() {
+        return emailAddress;
+    }
+
+    public void setEmailAddress(String emailAddress) {
+        this.emailAddress = emailAddress;
+    }
+
+    public String getAppEntriesUrl() {
+        return appEntriesUrl;
+    }
+
+    public void setAppEntriesUrl(String appEntriesUrl) {
+        this.appEntriesUrl = appEntriesUrl;
+    }
+
+    public String getAppResourcesUrl() {
+        return appResourcesUrl;
+    }
+
+    public void setAppResourcesUrl(String appResourcesUrl) {
+        this.appResourcesUrl = appResourcesUrl;
+    }
+}

Added: incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntrySet.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntrySet.java?rev=400121&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntrySet.java (added)
+++ incubator/roller/trunk/src/org/apache/roller/webservices/adminapi/sdk/WeblogEntrySet.java Fri May  5 10:49:04 2006
@@ -0,0 +1,83 @@
+/*
+* 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.
+*/
+/*
+ * WeblogEntrySet.java
+ *
+ * Created on January 17, 2006, 12:44 PM
+ */
+
+package org.apache.roller.webservices.adminapi.sdk;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.apache.roller.webservices.adminapi.sdk.EntrySet.Types;
+
+/**
+ * This class describes a set of weblog entries. 
+ * @author jtb
+ */
+public class WeblogEntrySet extends EntrySet {
+    static interface Tags {
+        public static final String WEBLOGS = "weblogs";
+    }      
+    
+    public WeblogEntrySet(String urlPrefix) {
+        setHref(urlPrefix + "/" + Types.WEBLOGS);
+    }
+    
+    public WeblogEntrySet(Document d, String urlPrefix) throws MissingElementException, UnexpectedRootElementException {
+        populate(d, urlPrefix);
+    }
+    
+    public WeblogEntrySet(InputStream stream, String urlPrefix) throws JDOMException, IOException, MissingElementException, UnexpectedRootElementException {               
+        SAXBuilder sb = new SAXBuilder();
+        Document d = sb.build(stream);
+
+        populate(d, urlPrefix);        
+    }    
+    
+    private void populate(Document d, String urlPrefix) throws MissingElementException, UnexpectedRootElementException {
+        Element root = d.getRootElement();
+        String rootName = root.getName();
+        if (!rootName.equals(Tags.WEBLOGS)) {
+            throw new UnexpectedRootElementException("ERROR: Unexpected root element", Tags.WEBLOGS, rootName);
+        }
+        List weblogs = root.getChildren(WeblogEntry.Tags.WEBLOG, Service.NAMESPACE);
+        if (weblogs != null) {
+            List entries = new ArrayList();
+            for (Iterator i = weblogs.iterator(); i.hasNext(); ) {
+                Element weblog = (Element)i.next();
+                WeblogEntry entry = new WeblogEntry(weblog, urlPrefix);
+                entries.add(entry);
+            }
+            setEntries((Entry[])entries.toArray(new Entry[0]));
+        }
+        setHref(urlPrefix + "/" + Types.WEBLOGS);
+    }    
+       
+    public String getType() {
+        return Types.WEBLOGS;
+    }    
+}