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 2005/10/21 23:46:28 UTC

svn commit: r327589 [30/72] - in /incubator/roller/branches/roller_1.x: ./ contrib/ contrib/lib/ contrib/plugins/ contrib/plugins/src/ contrib/plugins/src/org/ contrib/plugins/src/org/roller/ contrib/plugins/src/org/roller/presentation/ contrib/plugins...

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/RollerAtomHandler.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/RollerAtomHandler.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/RollerAtomHandler.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/RollerAtomHandler.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,881 @@
+/*
+ * 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.roller.presentation.atomapi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.util.RequestUtils;
+import org.roller.model.FileManager;
+import org.roller.model.Roller;
+import org.roller.model.WeblogManager;
+import org.roller.pojos.UserData;
+import org.roller.pojos.WeblogCategoryData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.LoginServlet;
+import org.roller.presentation.RollerContext;
+import org.roller.util.RollerMessages;
+import org.roller.util.Utilities;
+
+import com.sun.syndication.feed.atom.Content;
+import com.sun.syndication.feed.atom.Entry;
+import com.sun.syndication.feed.atom.Link;
+import com.sun.syndication.io.impl.Base64;
+
+/**
+ * Roller's Atom Protocol implementation.
+ * <pre>
+ * Here are the URIs suppored:
+ * 
+ *    URI type             URI form                          Handled by
+ *    --------             --------                          ----------                                        
+ *    Introspection URI    /blog-name                        getIntrosection()               
+ *    Collection URI       /blog-name/<collection-name>      getCollection()
+ *    Collection-next URI  /blog-name/<collection-name>/id   getCollection()
+ *    Member URI           /blog-name/<object-name>          post<object-name>()
+ *    Member URI           /blog-name/<object-name>/id       get<object-name>()
+ *    Member URI           /blog-name/<object-name>/id       put<object-name>()
+ *    Member URI           /blog-name/<object-name>/id       delete<object-name>()
+ * 
+ *    Until group blogging is supported username == blogname.
+ * 
+ *    Collection-names   Object-names
+ *    ----------------   ------------
+ *       entries           entry
+ *       resources         resource
+ *       categories        categories
+ * soon:
+ *       users             user
+ *       templates         template
+ * </pre>
+ *
+ * @author David M Johnson
+ */
+public class RollerAtomHandler implements AtomHandler
+{
+    private HttpServletRequest mRequest; 
+    private Roller             mRoller; 
+    private RollerContext      mRollerContext;
+    private String             mUsername;
+    private int                mMaxEntries = 20;
+    //private MessageDigest    md5Helper = null;
+    //private MD5Encoder       md5Encoder = new MD5Encoder();
+    
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(RollerAtomHandler.class);
+    
+    private SimpleDateFormat timestampFormat = 
+        new SimpleDateFormat("yyyyMMddHHmmss" );
+
+    //---------------------------------------------------------------- construction
+    
+    /** 
+     * Create Atom handler for a request and attempt to authenticate user.
+     * If user is authenticated, then getAuthenticatedUsername() will return 
+     * then user's name, otherwise it will return null.
+     */
+    public RollerAtomHandler(HttpServletRequest request)
+    {
+        mRequest = request;
+        mRoller = RollerContext.getRoller(request);
+        mRollerContext = RollerContext.getRollerContext(request);
+        
+        // TODO: decide what to do about authentication, is WSSE going to fly?
+        mUsername = authenticateWSSE(request);
+        //mUsername = authenticateBASIC(request);  
+ 
+        if (mUsername != null) 
+        {
+            try
+            {
+                UserData user = mRoller.getUserManager().getUser(mUsername);
+                mRoller.setUser(user);
+            }
+            catch (Exception e)
+            {
+                mLogger.error("ERROR: setting user", e);
+            }
+        }                 
+        //        try
+        //        {
+        //            md5Helper = MessageDigest.getInstance("MD5");
+        //        }
+        //        catch (NoSuchAlgorithmException e)
+        //        {
+        //            mLogger.debug("ERROR creating MD5 helper", e);
+        //        }
+    }
+    
+    /**
+     * Return username of authenticated user or null if there is none.
+     */
+    public String getAuthenticatedUsername()
+    {
+        return mUsername;
+    }
+  
+    //---------------------------------------------------------------- introspection
+    
+    /**
+     * Return Atom service document for site, getting blog-name from pathInfo.
+     * Since a user can (currently) have only one blog, one workspace is returned.
+     * The workspace will contain collections for entries, categories and resources.
+     */
+    public AtomService getIntrospection(String[] pathInfo) throws Exception 
+    {
+        if (pathInfo.length == 1) 
+        {
+            String username = pathInfo[0];
+            String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest);
+            
+            AtomService service = new AtomService();
+
+            AtomService.Workspace workspace = new AtomService.Workspace();
+            workspace.setTitle("Workspace: Collections for " + username);
+            service.addWorkspace(workspace);
+
+            AtomService.Collection entryCol = new AtomService.Collection();
+            entryCol.setTitle("Collection: Weblog Entries for " + username);
+            entryCol.setContents("entries");
+            entryCol.setHref(absUrl + "/atom/"+mUsername+"/entries");
+            workspace.addCollection(entryCol);
+            
+            AtomService.Collection catCol = new AtomService.Collection();
+            catCol.setTitle("Collection: Categories for " + username);
+            catCol.setContents("categories");
+            catCol.setHref(absUrl + "/atom/"+mUsername+"/categories");            
+            workspace.addCollection(catCol);
+            
+            AtomService.Collection uploadCol = new AtomService.Collection();
+            uploadCol.setTitle("Collection: File uploads for " + username);
+            uploadCol.setContents("generic");
+            uploadCol.setHref(absUrl + "/atom/"+mUsername+"/resources");            
+            workspace.addCollection(uploadCol);
+            
+            return service;
+        }
+        throw new Exception("ERROR: bad URL in getIntrospection()");
+    }
+    
+    //----------------------------------------------------------------- collections
+
+    /** 
+     * Returns collection specified by pathInfo with no date range specified.
+     * Just calls the other getCollection(), but with offset = -1.
+     */
+    public AtomCollection getCollection(String[] pathInfo) throws Exception
+    {
+        return getCollection(pathInfo, null, new Date(), -1);
+    }
+
+    /**
+     * Returns collection specified by pathInfo, constrained by a date range and
+     * starting at an offset within the collection.Returns 20 items at a time.
+     * <pre>
+     * Supports these three collection URI forms:
+     *    /<blog-name>/entries
+     *    /<blog-name>/resources
+     *    /<blog-name>/categories
+     * </pre>
+     * @param pathInfo Path info from URI
+     * @param start    Don't include members updated before this date (null allowed)
+     * @param end      Don't include members updated after this date (null allowed)
+     * @param offset   Offset within collection (for paging)
+     */
+    public AtomCollection getCollection(
+            String[] pathInfo, Date start, Date end, int offset) 
+        throws Exception
+    {
+        if (pathInfo.length > 0 && pathInfo[1].equals("entries"))
+        {
+            return getCollectionOfEntries(pathInfo, start, end, offset);
+        }
+        else if (pathInfo.length > 0 && pathInfo[1].equals("resources"))
+        {
+            return getCollectionOfResources(pathInfo, start, end, offset);
+        }
+        else if (pathInfo.length > 0 && pathInfo[1].equals("categories"))
+        {
+            return getCollectionOfCategories(pathInfo, start, end, offset);
+        }
+        throw new Exception("ERROR: bad URL in getCollection()");
+    }
+
+    /**
+     * Helper method that returns collection of entries, called by getCollection().
+     */
+    public AtomCollection getCollectionOfEntries(
+            String[] pathInfo, Date start, Date end, int offset) 
+        throws Exception
+    {
+        String username = pathInfo[0];
+        String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest);
+        WebsiteData website = mRoller.getUserManager().getWebsite(username);
+        List entries = null;
+        if (canView(website)) 
+        {
+            if (pathInfo.length == 2) // handle /blogname/entries
+            {
+                // return most recent blog entries
+                if (offset == -1)
+                {
+                    entries = mRoller.getWeblogManager().getWeblogEntries(
+                            website,           // website
+                            start,             // startDate
+                            end,               // endDate
+                            null,              // catName
+                            WeblogManager.ALL, // status
+                            new Integer(mMaxEntries + 1)); // maxEntries
+                }
+                else
+                {
+                    entries = mRoller.getWeblogManager().getWeblogEntries(
+                            website,           // website
+                            start,             // startDate
+                            end,               // endDate
+                            null,              // catName
+                            WeblogManager.ALL, // status
+                            offset,            // offset (for range paging)
+                            mMaxEntries + 1);  // maxEntries
+                }
+            }
+            else if (pathInfo.length == 3) // handle /blogname/entries/entryid
+            {
+                // return entries previous to entry specified by pathInfo
+                String entryid = pathInfo[2];               
+                WeblogManager wmgr = mRoller.getWeblogManager();
+                WeblogEntryData entry = wmgr.retrieveWeblogEntry(entryid);
+                entries = wmgr.getPreviousEntries(entry, null, mMaxEntries + 1);
+            }
+            else throw new Exception("ERROR: bad URL");
+            
+            // build collection
+            AtomCollection col = new AtomCollection();
+            if (entries.size() > mMaxEntries) 
+            {
+                // there are more entries, so include next link
+                WeblogEntryData lastEntry = 
+                    (WeblogEntryData)entries.get(entries.size() - 1);
+                col.setNext(createNextLink(lastEntry, start, end, offset));
+            }
+            // add up to max entries to collection 
+            int count = 0;
+            Iterator iter = entries.iterator();
+            while (iter.hasNext() && count++ < mMaxEntries)
+            {
+                WeblogEntryData rollerEntry = (WeblogEntryData)iter.next();
+                AtomCollection.Member member = new AtomCollection.Member();
+                member.setTitle(rollerEntry.getDisplayTitle());
+                member.setUpdated(rollerEntry.getUpdateTime());
+                member.setHref(absUrl 
+                    + "/atom/" + username + "/entry/" + rollerEntry.getId());
+                col.addMember(member);
+            }
+            return col;
+        }
+        throw new Exception("ERROR: not authorized");
+    }
+    
+    /**
+     * Helper method that returns collection of resources, called by getCollection().
+     */
+    public AtomCollection getCollectionOfResources(
+            String[] pathInfo, Date start, Date end, int offset) throws Exception
+    {
+        String username = pathInfo[0];
+        String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest);
+        WebsiteData website = mRoller.getUserManager().getWebsite(username);
+        FileManager fmgr = mRoller.getFileManager();
+        File[] files = fmgr.getFiles(website);
+        if (canView(website)) 
+        {
+            AtomCollection col = new AtomCollection();
+            for (int i=0; i<files.length; i++)
+            {
+                AtomCollection.Member member = new AtomCollection.Member();
+                member.setTitle(files[i].getName());
+                member.setUpdated(new Date(files[i].lastModified()));
+                member.setHref(absUrl 
+                    + "/atom/" + username + "/resource/" + files[i].getName() );
+                col.addMember(member);
+            }
+            return col;
+        }
+        throw new Exception("ERROR: not authorized");       
+    }
+
+    /**
+     * Helper method that returns collection of categories, called by getCollection().
+     */
+    public AtomCollection getCollectionOfCategories(
+            String[] pathInfo, Date start, Date end, int offset) throws Exception
+    {
+        String username = pathInfo[0];
+        String absUrl = mRollerContext.getAbsoluteContextUrl(mRequest);
+        WebsiteData website = mRoller.getUserManager().getWebsite(username);
+        WeblogManager wmgr = mRoller.getWeblogManager();
+        List items = wmgr.getWeblogCategories(website);
+        if (canView(website)) 
+        {
+            AtomCollection col = new AtomCollection();
+            Iterator iter = items.iterator();
+            Date now = new Date();
+            while (iter.hasNext())
+            {
+                WeblogCategoryData item = (WeblogCategoryData)iter.next();
+                AtomCollection.Member member = new AtomCollection.Member();
+                member.setTitle(item.getPath());
+                member.setUpdated(now);
+                member.setHref(
+                    absUrl + "/atom/" + username + "/category/" + item.getId());
+                col.addMember(member);
+            }
+            return col;
+        }
+        throw new Exception("ERROR: not authorized");       
+    }
+
+    //--------------------------------------------------------------------- entries
+    
+    /**
+     * Create entry in the entry collection (a Roller blog has only one).
+     */
+    public Entry postEntry(String[] pathInfo, Entry entry) throws Exception
+    {
+        // authenticated client posted a weblog entry
+        String username = pathInfo[0];
+        WebsiteData website = mRoller.getUserManager().getWebsite(username);
+        if (canEdit(website))
+        {            
+            // Save it and commit it
+            WeblogEntryData rollerEntry = createRollerEntry(website, entry);
+            rollerEntry.save();   
+            mRoller.commit();
+                        
+            // Throttle one entry per second 
+            // (MySQL timestamp has 1 sec resolution, damnit)
+            Thread.sleep(1000);
+                        
+            // TODO: ping the appropriate ping
+            // TODO: flush the cache on Atom post
+            //flushPageCache(mRequest);
+            
+            return createAtomEntry(rollerEntry);
+        }
+        throw new Exception("ERROR not authorized to edit website");
+    }
+    
+    /**
+     * Retrieve entry, URI like this /blog-name/entry/id
+     */
+    public Entry getEntry(String[] pathInfo) throws Exception
+    {
+        if (pathInfo.length == 3) // URI is /blogname/entries/entryid
+        {
+            WeblogEntryData entry = 
+                mRoller.getWeblogManager().retrieveWeblogEntry(pathInfo[2]);
+            if (!canView(entry))
+            {
+                throw new Exception("ERROR not authorized to view entry");
+            }
+            else if (entry != null) 
+            {
+                return createAtomEntry(entry);
+            }
+            throw new Exception("ERROR: entry not found");
+        }
+        throw new Exception("ERROR: bad URI");
+    }
+
+    /**
+     * Update entry, URI like this /blog-name/entry/id
+     */
+    public Entry putEntry(String[] pathInfo, Entry entry) throws Exception
+    {
+        if (pathInfo.length == 3) // URI is /blogname/entries/entryid
+        { 
+            WeblogEntryData rollerEntry = 
+                mRoller.getWeblogManager().retrieveWeblogEntry(pathInfo[2]);
+            if (canEdit(rollerEntry))
+            {    
+                rollerEntry.setTitle(entry.getTitle());
+                rollerEntry.setText(((Content)entry.getContents().get(0)).getValue());
+                rollerEntry.setUpdateTime(new Timestamp(new Date().getTime()));
+                rollerEntry.save();
+                mRoller.commit();
+                return createAtomEntry(rollerEntry);
+            }
+            throw new Exception("ERROR not authorized to put entry");
+        }
+        throw new Exception("ERROR: bad URI");
+    }
+
+    /**
+     * Delete entry, URI like this /blog-name/entry/id
+     */
+    public void deleteEntry(String[] pathInfo) throws Exception
+    {
+        if (pathInfo.length == 3) // URI is /blogname/entries/entryid
+        { 
+            WeblogEntryData rollerEntry = 
+                mRoller.getWeblogManager().retrieveWeblogEntry(pathInfo[2]);
+            if (canEdit(rollerEntry))
+            {    
+                rollerEntry.remove();
+                mRoller.commit();
+                return;
+            }
+            throw new Exception("ERROR not authorized to delete entry");
+        }
+        throw new Exception("ERROR: bad URI");
+    }
+
+    //-------------------------------------------------------------------- resources
+
+    /**
+     * Create new resource in generic collection (a Roller blog has only one).
+     * TODO: can we avoid saving temporary file?
+     * TODO: do we need to handle mutli-part MIME uploads?
+     * TODO: use Jakarta Commons File-upload?
+     */
+    public String postResource(String[] pathInfo, 
+            String name, String contentType, InputStream is)
+            throws Exception
+    {
+        // authenticated client posted a weblog entry
+        String username = pathInfo[0];
+        WebsiteData website = mRoller.getUserManager().getWebsite(username);
+        if (canEdit(website) && pathInfo.length > 1)
+        {
+            try
+            {
+                FileManager fmgr = mRoller.getFileManager();
+                RollerMessages msgs = new RollerMessages();
+                
+                // save to temp file
+                if (name == null) 
+                {
+                    throw new Exception(
+                        "ERROR[postResource]: No 'name' present in HTTP headers");
+                }
+                File tempFile = File.createTempFile(name,"tmp");
+                FileOutputStream fos = new FileOutputStream(tempFile);
+                Utilities.copyInputToOutput(is, fos);
+                fos.close();
+                
+                // If save is allowed by Roller system-wide policies   
+                if (fmgr.canSave(website, name, tempFile.length(), msgs)) 
+                {
+                    // Then save the file
+                    FileInputStream fis = new FileInputStream(tempFile);
+                    fmgr.saveFile(website, name, tempFile.length(), fis);
+                    fis.close();
+                    
+                    // TODO: build URL to uploaded file should be done in FileManager
+                    String uploadPath = RollerContext.getUploadPath(
+                        mRequest.getSession(true).getServletContext());
+                    uploadPath += "/" + website.getUser().getUserName() + "/" + name;
+                    return RequestUtils.printableURL(
+                        RequestUtils.absoluteURL(mRequest, uploadPath));                    
+                }
+                tempFile.delete();
+                throw new Exception("File upload denied because:" + msgs.toString());
+            }
+            catch (Exception e)
+            {
+                String msg = "ERROR in atom.postResource";
+                mLogger.error(msg,e);
+                throw new Exception(msg);
+            }
+        }
+        throw new Exception("ERROR not authorized to edit website");
+    }
+        
+    /** 
+     * Get absolute path to resource specified by path info.
+     */
+    public String getResourceFilePath(String[] pathInfo) throws Exception
+    {
+        // ==> /<blogname>/resources/<filename>
+        String uploadPath = RollerContext.getUploadPath(
+                mRequest.getSession(true).getServletContext());
+        return uploadPath + File.separator + pathInfo[2];
+    }    
+    
+    /**
+     * Update resource specified by pathInfo using data from input stream.
+     * Expects pathInfo of form /blog-name/resources/name
+     */
+    public void putResource(String[] pathInfo, 
+            String contentType, InputStream is) throws Exception
+    {
+        if (pathInfo.length > 2)
+        {
+           String name = pathInfo[2];  
+           postResource(pathInfo, name, contentType, is);
+        }
+        throw new Exception("ERROR: bad pathInfo");
+    }
+
+    /**
+     * Delete resource specified by pathInfo.
+     * Expects pathInfo of form /blog-name/resources/name
+     */
+    public void deleteResource(String[] pathInfo) throws Exception
+    {
+        // authenticated client posted a weblog entry
+        String username = pathInfo[0];
+        WebsiteData website = mRoller.getUserManager().getWebsite(username);
+        if (canEdit(website) && pathInfo.length > 1)
+        {
+            try
+            {
+                FileManager fmgr = mRoller.getFileManager();
+                fmgr.deleteFile(website, pathInfo[2]);
+            }
+            catch (Exception e)
+            {
+                String msg = "ERROR in atom.deleteResource";
+                mLogger.error(msg,e);
+                throw new Exception(msg);
+            }
+        }
+        throw new Exception("ERROR not authorized to edit website");
+    }
+
+    //------------------------------------------------------------------ URI testers
+    
+    /**
+     * True if URL is the introspection URI.
+     */
+    public boolean isIntrospectionURI(String[] pathInfo)
+    {
+        if (pathInfo.length == 1 && pathInfo[0].equals(mUsername)) return true;
+        return false;
+    }
+    
+    /**
+     * True if URL is a entry URI.
+     */
+    public boolean isEntryURI(String[] pathInfo)     
+    {
+        if (pathInfo.length > 1 && pathInfo[1].equals("entry")) return true;
+        return false;
+    }
+
+    /**
+     * True if URL is a resource URI.
+     */
+   public boolean isResourceURI(String[] pathInfo)     
+    {
+        if (pathInfo.length > 1 && pathInfo[1].equals("resource")) return true;
+        return false;
+    }
+
+    /**
+     * True if URL is a category URI.
+     */
+    public boolean isCategoryURI(String[] pathInfo)     
+    {
+        if (pathInfo.length > 1 && pathInfo[1].equals("category")) return true;
+        return false;
+    }
+
+    /**
+     * True if URL is a collection URI of any sort.
+     */
+    public boolean isCollectionURI(String[] pathInfo) 
+    {
+        if (pathInfo.length > 1 && pathInfo[1].equals("entries")) return true;
+        if (pathInfo.length > 1 && pathInfo[1].equals("resources")) return true;
+        if (pathInfo.length > 1 && pathInfo[1].equals("categories")) return true;
+        return false;
+    }
+
+    /**
+     * True if URL is a entry collection URI.
+     */
+    public boolean isEntryCollectionURI(String[] pathInfo) 
+    {
+        if (pathInfo.length > 1 && pathInfo[1].equals("entries")) return true;
+        return false;
+    }
+
+    /**
+     * True if URL is a resource collection URI.
+     */
+    public boolean isResourceCollectionURI(String[] pathInfo) 
+    {
+        if (pathInfo.length > 1 && pathInfo[1].equals("resources")) return true;
+        return false;
+    }
+
+    /**
+     * True if URL is a category collection URI.
+     */
+    public boolean isCategoryCollectionURI(String[] pathInfo) 
+    {
+        if (pathInfo.length > 1 && pathInfo[1].equals("categories")) return true;
+        return false;
+    }
+
+    //------------------------------------------------------------------ permissions
+    
+    /**
+     * Return true if user is allowed to edit an entry.
+     */
+    private boolean canEdit(WeblogEntryData entry)
+    {
+        return entry.getWebsite().getUser().getUserName().equals(mUsername);
+    }
+    
+    /**
+     * Return true if user is allowed to edit a website.
+     */
+    private boolean canEdit(WebsiteData website)
+    {
+        return website.getUser().getUserName().equals(mUsername);
+    }
+    
+    /**
+     * Return true if user is allowed to view an entry.
+     */
+    private boolean canView(WeblogEntryData entry)
+    {
+        return canEdit(entry);
+    }
+    
+    /**
+     * Return true if user is allowed to view a website.
+     */
+    private boolean canView(WebsiteData website)
+    {
+        return canEdit(website);
+    }
+
+    //-------------------------------------------------------------- authentication
+
+    /** 
+     * Perform WSSE authentication based on information in request.
+     * Will not work if Roller password encryption is turned on. 
+     */
+    protected String authenticateWSSE(HttpServletRequest request) 
+    {
+        String wsseHeader = request.getHeader("X-WSSE");
+        if (wsseHeader == null) return null;
+        
+        String ret = null;
+        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;
+                }
+            }
+        }
+        String digest = null;
+        try
+        {
+            UserData user = mRoller.getUserManager().getUser(userName);
+            digest = WSSEUtilities.generateDigest(
+                        WSSEUtilities.base64Decode(nonce), 
+                        created.getBytes("UTF-8"), 
+                        user.getPassword().getBytes("UTF-8"));
+            if (digest.equals(passwordDigest))
+            {
+                ret = userName;
+            }
+        }
+        catch (Exception e)
+        {
+            mLogger.error("ERROR in wsseAuthenticataion: " + e.getMessage(), e);
+        }
+        return ret;
+    }
+
+    /** 
+     * Untested (and currently unused) implementation of BASIC authentication 
+     */
+    public String authenticateBASIC(HttpServletRequest request)
+    {
+        boolean valid = false;
+        String userID = null;
+        String password = null;
+        try 
+        {
+            String authHeader = request.getHeader("Authorization");
+            if (authHeader != null) 
+            {
+               StringTokenizer st = new StringTokenizer(authHeader);
+               if (st.hasMoreTokens()) 
+               {
+                  String basic = st.nextToken();
+                  if (basic.equalsIgnoreCase("Basic")) 
+                  {
+                     String credentials = st.nextToken();
+                     String userPass = new String(Base64.decode(credentials));
+                     int p = userPass.indexOf(":");
+                     if (p != -1) 
+                     {
+                        userID = userPass.substring(0, p);
+                        UserData user = mRoller.getUserManager().getUser(userID);
+                        String realpassword = LoginServlet.getEncryptedPassword(
+                            request, user.getUserName(), user.getPassword());
+                        password = userPass.substring(p+1);
+                        if (    (!userID.trim().equals(user.getUserName())) 
+                             && (!password.trim().equals(realpassword))) 
+                        {
+                           valid = true;
+                        }
+                     }
+                  }
+               }
+            }
+        }
+        catch (Exception e) 
+        {
+            mLogger.debug(e);
+        }
+        if (valid) return userID;
+        return null;
+    }
+ 
+    //----------------------------------------------------------- internal utilities
+    
+    /**
+     * Create next member list suitable for use in entry collection.
+     * Puts state date, end date and off set in request parameters.
+     */
+    private String createNextLink(
+            WeblogEntryData entry, Date start, Date end, int offset)
+    {
+        SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" );
+        String absUrl = mRollerContext.getAbsoluteContextUrl();
+        String url = absUrl + "/atom/" + mUsername + "/entries/" + entry.getId();
+        if (offset != -1 && start != null && end != null) 
+        {
+            url  = url + "?Range=" + df.format(start) + "/" + df.format(end); 
+        }
+        else if (offset != -1 && start != null)
+        {
+            url  = url + "?Range=" + df.format(start) + "/";
+        }
+        else if (offset != -1 && end != null)
+        {
+            url  = url + "?Range=/" + df.format(end); 
+        }
+        if (offset != -1)
+        {
+            url = url + "&offset=" + (offset + mMaxEntries);
+        }
+        return url;
+    }    
+    
+    /**
+     * Create a Rome Atom entry based on a Roller entry.
+     * Content is escaped.
+     * Link is stored as rel=alternate link.
+     */
+    private Entry createAtomEntry(WeblogEntryData entry)
+    {
+        Entry atomEntry = new Entry();
+        Content content = new Content();
+        content.setMode(Content.ESCAPED);
+        content.setValue(entry.getText());
+        List contents = new ArrayList();
+        contents.add(content);
+        
+        atomEntry.setId(       entry.getId()); 
+        atomEntry.setTitle(    entry.getTitle());
+        atomEntry.setContents( contents);
+        atomEntry.setIssued(   entry.getPubTime()); 
+        atomEntry.setModified( entry.getUpdateTime());
+       
+        List links = new ArrayList();
+        Link altlink = new Link();
+        altlink.setRel("alternate");
+        altlink.setHref(entry.getPermaLink());
+        links.add(altlink);
+        atomEntry.setAlternateLinks(links);
+        
+        return atomEntry;
+    }
+    
+    /**
+     * Create a Roller weblog entry based on a Rome Atom entry object
+     */
+    private WeblogEntryData createRollerEntry(WebsiteData website, Entry entry)
+    {
+        Timestamp current = new Timestamp(System.currentTimeMillis());
+        Timestamp pubTime = current;
+        Timestamp updateTime = current;
+        if (entry.getIssued() != null)
+        {
+            pubTime = new Timestamp( entry.getIssued().getTime() );
+        }
+        if (entry.getModified() != null)
+        {
+            updateTime = new Timestamp( entry.getModified().getTime() );
+        }
+        WeblogEntryData rollerEntry = new WeblogEntryData();
+        rollerEntry.setTitle(entry.getTitle());
+        rollerEntry.setText( ((Content)entry.getContents().get(0)).getValue() );
+        rollerEntry.setPubTime(pubTime);
+        rollerEntry.setUpdateTime(updateTime);
+        rollerEntry.setWebsite(website);
+        rollerEntry.setPublishEntry( Boolean.TRUE );
+        rollerEntry.setCategory(website.getBloggerCategory());
+        
+        return rollerEntry;
+    }    
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/WSSEUtilities.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/WSSEUtilities.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/WSSEUtilities.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/WSSEUtilities.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2005, Dave Johnson
+ * 
+ * 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.roller.presentation.atomapi;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * Utilties to support WSSE authentication.
+ * @author Dave Johnson
+ */
+public class WSSEUtilities {
+    public static synchronized String generateDigest(
+            byte[] nonce, byte[] created, byte[] password) {
+        String result = null;
+        try {
+            MessageDigest digester = MessageDigest.getInstance("SHA");
+            digester.reset();
+            digester.update(nonce);
+            digester.update(created);
+            digester.update(password);
+            byte[] digest = digester.digest();
+            result = new String(base64Encode(digest));
+        }
+        catch (NoSuchAlgorithmException e) {
+            result = null;
+        }
+        return result;
+    }
+    public static byte[] base64Decode(String value) throws IOException {
+        return Base64.decodeBase64(value.getBytes("UTF-8"));
+    }
+    public static String base64Encode(byte[] value) {
+        return new String(Base64.encodeBase64(value));
+    }
+    public static String generateWSSEHeader(String userName, String password) 
+    throws UnsupportedEncodingException {  
+       
+        byte[] nonceBytes = Long.toString(new Date().getTime()).getBytes();
+        String nonce = new String(WSSEUtilities.base64Encode(nonceBytes));
+        
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+        String created = sdf.format(new Date());
+        
+        String digest = WSSEUtilities.generateDigest(
+                nonceBytes, created.getBytes("UTF-8"), password.getBytes("UTF-8"));
+        
+        StringBuffer header = new StringBuffer("UsernameToken Username=\"");
+        header.append(userName);
+        header.append("\", ");
+        header.append("PasswordDigest=\"");
+        header.append(digest);
+        header.append("\", ");
+        header.append("Nonce=\"");
+        header.append(nonce);
+        header.append("\", ");
+        header.append("Created=\"");
+        header.append(created);
+        header.append("\"");
+        return header.toString();
+    }
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/atomapi/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,10 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+ROME-based Atom Protocol implementation.
+
+</body>
+</html>

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkEditAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkEditAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkEditAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkEditAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,93 @@
+/*
+ * Created on Oct 21, 2003
+ */
+package org.roller.presentation.bookmarks.actions;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.roller.model.BookmarkManager;
+import org.roller.pojos.BookmarkData;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.bookmarks.formbeans.BookmarkFormEx;
+import org.roller.presentation.forms.BookmarkForm;
+
+import java.util.LinkedList;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @struts.action path="/editor/bookmarkEdit" name="bookmarkFormEx" validate="false"
+ * @struts.action-forward name="BookmarkForm" path="/bookmarks/BookmarkForm.jsp"
+ * 
+ * @author Dave Johnson
+ */
+public class BookmarkEditAction extends Action
+{
+    public ActionForward execute(
+        ActionMapping       mapping,
+        ActionForm          actionForm,
+        HttpServletRequest  request,
+        HttpServletResponse response)
+        throws Exception
+    {
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        WebsiteData wd = rreq.getWebsite();
+        BookmarkManager bmgr = rreq.getRoller().getBookmarkManager();
+        BookmarkFormEx form = (BookmarkFormEx)actionForm;
+        
+        FolderData parentFolder = null;
+        if (null!=rreq.getBookmark() && null==request.getParameter("correct")) 
+        {
+            // If request specifies bookmark and we are not correcting an 
+            // already submitted form then load that bookmark into the form.
+            BookmarkData bd = rreq.getBookmark();
+            form.copyFrom(bd, request.getLocale());
+            request.setAttribute("state","edit"); 
+                
+            // Pass bookmark's Folder on as attribute.                 
+            parentFolder = bd.getFolder();
+        }
+        else if (null != request.getParameter("correct"))
+        {
+            // We are correcting a previously submtted form.
+            request.setAttribute("state","correcting"); 
+                
+            // Folder is specified by request param, pass it on as attribute.                 
+            parentFolder = bmgr.retrieveFolder(rreq.getFolder().getId());        
+        }
+        else
+        {
+            // We are adding a new bookmark
+            request.setAttribute("state","add");
+            
+            // Folder is specified by request param, pass it on as attribute.                 
+            parentFolder = bmgr.retrieveFolder(rreq.getFolder().getId());        
+        }
+        
+        // Build folder path for display on page
+        if (null != parentFolder)
+        {
+            request.setAttribute(
+                RollerRequest.FOLDERID_KEY, parentFolder.getId());
+            
+            LinkedList folderPath = new LinkedList();
+            folderPath.add(0, parentFolder);
+            FolderData parent = parentFolder.getParent();
+            while (parent != null) 
+            {
+                folderPath.add(0, parent);
+                parent = parent.getParent();   
+            }
+            request.setAttribute("parentFolder", parentFolder);
+            request.setAttribute("folderPath", folderPath);
+        }
+
+        return mapping.findForward("BookmarkForm");
+    }
+    
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkSaveAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkSaveAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkSaveAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarkSaveAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,78 @@
+/*
+ * Created on Oct 21, 2003
+ */
+package org.roller.presentation.bookmarks.actions;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.roller.RollerPermissionsException;
+import org.roller.model.BookmarkManager;
+import org.roller.pojos.BookmarkData;
+import org.roller.pojos.FolderData;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.bookmarks.formbeans.BookmarkFormEx;
+
+/**
+ * @struts.action path="/editor/bookmarkSave" name="bookmarkFormEx"
+ *    validate="true" input="/editor/bookmarkEdit.do"
+ * @struts.action-forward name="Bookmarks" path="/editor/bookmarks.do?method=selectFolder"
+ * 
+ * @author Dave Johnson
+ */
+public class BookmarkSaveAction extends Action
+{
+    public ActionForward execute(
+        ActionMapping       mapping,
+        ActionForm          actionForm,
+        HttpServletRequest  request,
+        HttpServletResponse response)
+        throws Exception
+    {
+        ActionForward forward = mapping.findForward("Bookmarks");
+        try
+        {
+            BookmarkFormEx form = (BookmarkFormEx)actionForm;
+            RollerRequest rreq = RollerRequest.getRollerRequest(request);
+            BookmarkManager bmgr = rreq.getRoller().getBookmarkManager();
+            
+            BookmarkData bd = null;
+            if (null != form.getId() && !form.getId().trim().equals("")) 
+            {
+                bd = bmgr.retrieveBookmark(form.getId());
+                bd.save(); // should throw if save not permitted
+            }
+            else 
+            {
+                bd = bmgr.createBookmark();
+                
+                // Existing bookmarks already have folders, but this is a new one.
+                FolderData fd = bmgr.retrieveFolder(
+                    request.getParameter(RollerRequest.FOLDERID_KEY));
+                bd.setFolder(fd);
+            }
+            form.copyTo(bd, request.getLocale());
+            bd.save();
+            rreq.getRoller().commit();
+            
+            request.setAttribute(
+                RollerRequest.FOLDERID_KEY,bd.getFolder().getId());  
+        }
+        catch (RollerPermissionsException e)
+        {
+            ActionErrors errors = new ActionErrors();
+            errors.add(null, new ActionError("error.permissions.deniedSave"));
+            saveErrors(request, errors);
+            forward = mapping.findForward("access-denied");
+        }
+        return forward;
+        
+    }
+
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarksAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarksAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarksAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/BookmarksAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,301 @@
+/*
+ * Created on Oct 21, 2003
+ */
+package org.roller.presentation.bookmarks.actions;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.TreeSet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionMessage;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.actions.DispatchAction;
+import org.roller.RollerException;
+import org.roller.model.BookmarkManager;
+import org.roller.pojos.BookmarkData;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.bookmarks.formbeans.BookmarksForm;
+
+/**
+ * Actions that are initiated from the BookmarksForm.
+ *
+ * @struts.action name="bookmarksForm" path="/editor/bookmarks" parameter="method"
+ * @struts.action-forward name="BookmarksForm" path="/bookmarks/BookmarksForm.jsp"
+ *
+ * @author Dave Johnson
+ */
+public class BookmarksAction extends DispatchAction
+{
+    private static Log mLogger =
+        LogFactory.getFactory().getInstance(BookmarksAction.class);
+
+    /**
+     * Present the BookmarksForm loaded with folder specified by request.
+     * @param mapping Action mapping.
+     * @param actionForm Form bean.
+     * @param request Request.
+     * @param response Response.
+     * @return Forward to BookmarksForm or access-denied.
+     * @throws RollerException
+     */
+    public ActionForward selectFolder(
+        ActionMapping       mapping,
+        ActionForm          actionForm,
+        HttpServletRequest  request,
+        HttpServletResponse response)
+        throws RollerException
+    {
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        if (rreq.isUserAuthorizedToEdit())
+        {
+            addModelObjects(request, (BookmarksForm)actionForm);
+            return mapping.findForward("BookmarksForm");
+        }
+        else
+        {
+            return mapping.findForward("access-denied");
+        }
+    }
+
+    /**
+     * Delete folders and bookmarks indicated by BookmarksForm bean.
+     * @param mapping Action mapping.
+     * @param actionForm Form bean.
+     * @param request Request.
+     * @param response Response.
+     * @return Forward to BookmarksForm or access-denied.
+     * @throws RollerException
+     */
+    public ActionForward deleteSelected(
+        ActionMapping       mapping,
+        ActionForm          actionForm,
+        HttpServletRequest  request,
+        HttpServletResponse response)
+        throws RollerException
+    {
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        if (rreq.isUserAuthorizedToEdit())
+        {
+            BookmarkManager bmgr = rreq.getRoller().getBookmarkManager();
+            BookmarksForm form = (BookmarksForm)actionForm;
+
+            mLogger.debug("Deleting folders and bookmarks.");
+
+            String folders[] = form.getSelectedFolders();
+            if (null != folders)
+            {
+                for (int i = 0; i < folders.length; i++)
+                {
+                    FolderData fd = bmgr.retrieveFolder(folders[i]);
+                    fd.remove(); // removes child folders and bookmarks too
+                }
+            }
+
+            String bookmarks[] = form.getSelectedBookmarks();
+            if (null != bookmarks)
+            {
+                for (int j = 0; j < bookmarks.length; j++)
+                {
+                    bmgr.removeBookmark(bookmarks[j]);
+                }
+            }
+            rreq.getRoller().commit();
+
+            addModelObjects(request, (BookmarksForm)actionForm);
+            return mapping.findForward("BookmarksForm");
+        }
+        else
+        {
+            return mapping.findForward("access-denied");
+        }
+    }
+
+    /**
+     * Move folders and bookmarks indicated by BookmarksForm bean.
+     * @param mapping Action mapping.
+     * @param actionForm  Form bean.
+     * @param request Request.
+     * @param response Response.
+     * @return Forward to BookmarksForm or access-denied.
+     * @throws RollerException
+     */
+    public ActionForward moveSelected(
+        ActionMapping       mapping,
+        ActionForm          actionForm,
+        HttpServletRequest  request,
+        HttpServletResponse response)
+        throws RollerException
+    {
+        ActionMessages messages = new ActionMessages();
+        ActionForward forward = mapping.findForward("BookmarksForm");
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        if (rreq.isUserAuthorizedToEdit())
+        {
+            try 
+            {
+                BookmarkManager bmgr = rreq.getRoller().getBookmarkManager();
+                BookmarksForm form = (BookmarksForm)actionForm;
+    
+                mLogger.debug("Moving folders and bookmarks to folder, id="
+                    + form.getMoveToFolderId());
+    
+                // Move subfolders to new folder.
+                String folders[] = form.getSelectedFolders();
+                FolderData parent = bmgr.retrieveFolder(form.getMoveToFolderId());
+                if (null != folders)
+                {
+                    for (int i = 0; i < folders.length; i++)
+                    {
+                        FolderData fd = bmgr.retrieveFolder(folders[i]);
+    
+                        // Don't move folder into itself.
+                        if (    !fd.getId().equals(parent.getId())
+                             && !parent.descendentOf(fd))
+                        {
+                            fd.setParent(parent);
+                            fd.save();
+                        }
+                        else 
+                        {
+                            messages.add(null, new ActionMessage(
+                                "bookmarksForm.warn.notMoving",fd.getName()));
+                        }
+                    }
+                }
+    
+                // Move bookmarks.
+                String bookmarks[] = form.getSelectedBookmarks();
+                if (null != bookmarks)
+                {
+                    for (int j = 0; j < bookmarks.length; j++)
+                    {
+                        BookmarkData bd = bmgr.retrieveBookmark(bookmarks[j]);
+                        bd.setFolder(parent);
+                        bd.save();
+                    }
+                }
+                rreq.getRoller().commit();
+    
+                addModelObjects(request, (BookmarksForm)actionForm);
+                saveMessages(request, messages);
+            }
+            catch (RollerException e)
+            {
+                ActionErrors errors = new ActionErrors();
+                errors.add(null, new ActionError("bookmarksForm.error.move"));
+                saveErrors(request, errors);       
+            }
+        }
+        else
+        {
+            forward = mapping.findForward("access-denied");
+        }
+        return forward;
+    }
+
+    /**
+     * Load model objects for display in BookmarksForm.
+     * @param request
+     * @throws RollerException
+     */
+    private void addModelObjects(HttpServletRequest request, BookmarksForm form)
+        throws RollerException
+    {
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        WebsiteData wd = rreq.getWebsite();
+        BookmarkManager bmgr = rreq.getRoller().getBookmarkManager();
+
+        TreeSet allFolders = new TreeSet(new FolderPathComparator());
+
+        // Find folderid wherever it may be
+        String folderId = (String)request.getAttribute(RollerRequest.FOLDERID_KEY);
+        if (null == folderId)
+        {
+            folderId = request.getParameter(RollerRequest.FOLDERID_KEY);
+        }
+        if (null == folderId)
+        {
+            folderId = form.getFolderId();
+        }
+
+        FolderData folder = null;
+        if (null == folderId || folderId.equals("null"))
+        {
+            folder = bmgr.getRootFolder(wd);
+        }
+        else
+        {
+            folder = bmgr.retrieveFolder(folderId);
+        }
+        form.setFolderId(folder.getId());
+
+        request.setAttribute("folder", folder);
+        request.setAttribute("folders", folder.getFolders());
+        request.setAttribute("bookmarks", folder.getBookmarks());
+
+        if (null != folder.getParent())
+        {
+            LinkedList folderPath = new LinkedList();
+            folderPath.add(0, folder);
+            FolderData parent = folder.getParent();
+            while (parent != null)
+            {
+                folderPath.add(0, parent);
+                parent = parent.getParent();
+            }
+            request.setAttribute("folderPath", folderPath);
+
+            request.setAttribute(
+                RollerRequest.PARENTID_KEY, folder.getParent().getId());
+        }
+
+        // Build list of all folders, except for current one, sorted by path.
+        Iterator iter = bmgr.getAllFolders(wd).iterator();
+
+        // Build list of only children
+        //Iterator iter = folder.getFolders().iterator();
+
+        //int max = 20, count = 0;
+        while (iter.hasNext()) // && count < max)
+        {
+            //count++;
+            FolderData fd = (FolderData) iter.next();
+            if (!fd.getId().equals(folderId))
+            {
+                allFolders.add(fd);
+            }
+        }
+        request.setAttribute("allFolders", allFolders);
+    }
+
+    private static final class FolderPathComparator implements Comparator
+    {
+        public int compare(Object o1, Object o2) {
+            FolderData f1 = (FolderData)o1;
+            FolderData f2 = (FolderData)o2;
+            int res = 0;
+            try
+            {
+                res = f1.getPath().compareTo(f2.getPath());
+            }
+            catch (RollerException e)
+            {
+                mLogger.error("ERROR: sorting folders");
+            }
+            return res;
+        }
+    }
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderEditAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderEditAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderEditAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderEditAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,73 @@
+/*
+ * Created on Oct 21, 2003
+ */
+package org.roller.presentation.bookmarks.actions;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.roller.model.BookmarkManager;
+import org.roller.pojos.FolderData;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.bookmarks.formbeans.FolderFormEx;
+
+import java.util.LinkedList;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @struts.action path="/editor/folderEdit" name="folderFormEx" validate="false"
+ * @struts.action-forward name="FolderForm" path="/bookmarks/FolderForm.jsp"
+ * 
+ * @author Dave Johnson
+ */
+public class FolderEditAction extends Action
+{
+    public ActionForward execute(
+        ActionMapping       mapping,
+        ActionForm          actionForm,
+        HttpServletRequest  request,
+        HttpServletResponse response)
+        throws Exception
+    {
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        BookmarkManager bmgr = rreq.getRoller().getBookmarkManager();
+        FolderFormEx form = (FolderFormEx)actionForm;
+        
+        FolderData parentFolder = null;
+        if (null!=rreq.getFolder() && null==request.getParameter("correct")) 
+        {
+            // If request specifies folder and we are not correcting an 
+            // already submitted form then load that folder into the form.
+            request.setAttribute("state","edit"); 
+
+            FolderData fd = rreq.getFolder();
+            form.copyFrom(fd, request.getLocale());
+            parentFolder = fd.getParent();
+        }
+        else if (null != request.getParameter("correct"))
+        {
+            // We are correcting a previously submtted form.
+            request.setAttribute("state","correcting"); 
+            
+            String parentId = request.getParameter(RollerRequest.PARENTID_KEY);
+            parentFolder = bmgr.retrieveFolder(parentId);
+        }
+        else
+        {
+            // We are adding a new bookmark
+            request.setAttribute("state","add");
+            
+            String parentId = request.getParameter(RollerRequest.PARENTID_KEY);
+            parentFolder = bmgr.retrieveFolder(parentId);
+        }
+        
+        request.setAttribute(RollerRequest.PARENTID_KEY, parentFolder.getId());
+        request.setAttribute("parentFolder", parentFolder);
+        
+        return mapping.findForward("FolderForm");
+    }
+
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderSaveAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderSaveAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderSaveAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/FolderSaveAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,104 @@
+/*
+ * Created on Oct 21, 2003
+ */
+package org.roller.presentation.bookmarks.actions;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.roller.RollerException;
+import org.roller.RollerPermissionsException;
+import org.roller.model.BookmarkManager;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.bookmarks.formbeans.FolderFormEx;
+
+/**
+ * @struts.action path="/editor/folderSave" name="folderFormEx" 
+ *     validate="true" input="/editor/folderEdit.do"
+ * @struts.action-forward name="Bookmarks" path="/editor/bookmarks.do?method=selectFolder"
+ * 
+ * @author Dave Johnson
+ */
+public class FolderSaveAction extends Action
+{
+    public ActionForward execute(
+        ActionMapping       mapping,
+        ActionForm          actionForm,
+        HttpServletRequest  request,
+        HttpServletResponse response)
+        throws Exception
+    {
+        ActionForward forward = mapping.findForward("Bookmarks");
+        FolderFormEx form = (FolderFormEx)actionForm;
+        RollerRequest rreq = RollerRequest.getRollerRequest(request);
+        WebsiteData wd = rreq.getWebsite();
+        BookmarkManager bmgr = rreq.getRoller().getBookmarkManager();
+        
+        FolderData fd = null;
+        if (null != form.getId() && !form.getId().trim().equals("")) 
+        {
+            fd = bmgr.retrieveFolder(form.getId());
+            fd.save(); // should throw if save not permitted
+        }
+        else 
+        {
+            fd = bmgr.createFolder();
+        
+            String parentId = request.getParameter(RollerRequest.PARENTID_KEY);
+            FolderData parent = null;
+            if (null != parentId && !parentId.trim().equalsIgnoreCase("null"))
+            {
+                parent = bmgr.retrieveFolder(parentId);
+            }
+            else 
+            {
+                parent = bmgr.getRootFolder(wd);
+            }
+            fd.setParent(parent);
+            fd.setWebsite(wd);
+        }
+        
+        // Copy form values to object
+        form.copyTo(fd, request.getLocale());
+            
+        try 
+        {
+            // Store object and commit
+            fd.save();
+            rreq.getRoller().commit();
+        }
+        catch (RollerPermissionsException e)
+        {
+            ActionErrors errors = new ActionErrors();
+            errors.add(null, new ActionError("error.permissions.deniedSave"));
+            saveErrors(request, errors);
+            forward = mapping.findForward("access-denied");
+        }
+        catch (RollerException re)
+        {
+            rreq.getRoller().rollback();
+            ActionErrors errors = new ActionErrors();
+            String msg = (null != re.getRootCause())
+                ? re.getRootCause().toString()
+                : re.toString();
+            errors.add(ActionErrors.GLOBAL_ERROR, 
+               new ActionError("folderForm.save.exception", msg));
+            saveErrors(request,errors);            
+        }
+         
+        if (null != fd.getParent()) 
+        {
+            request.setAttribute(
+               RollerRequest.FOLDERID_KEY, fd.getParent().getId());
+        }         
+        return forward;
+    }
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/ImportBookmarksFormAction.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/ImportBookmarksFormAction.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/ImportBookmarksFormAction.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/ImportBookmarksFormAction.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,161 @@
+
+package org.roller.presentation.bookmarks.actions;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.upload.FormFile;
+import org.roller.model.BookmarkManager;
+import org.roller.presentation.RollerRequest;
+import org.roller.presentation.bookmarks.formbeans.FolderFormEx;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/////////////////////////////////////////////////////////////////////////////
+/**
+ * @struts.action name="folderFormEx" path="/editor/importBookmarks" 
+ *  scope="request" input="/bookmarks/import.jsp" validate="false"
+ * 
+ * @struts.action-forward name="importBookmarks.page" path="/bookmarks/import.jsp"
+ * 
+ * TODO Should import into folder with same name as imported file
+ */
+public final class ImportBookmarksFormAction extends Action
+{
+    private static Log mLogger = 
+        LogFactory.getFactory().getInstance(RollerRequest.class);
+
+	/** 
+     * Request to import bookmarks 
+     */
+	public ActionForward execute(
+		ActionMapping 		mapping,
+		ActionForm 			actionForm,
+		HttpServletRequest 	request,
+		HttpServletResponse response)
+		throws IOException, ServletException 
+	{
+        ActionErrors errors = new ActionErrors();
+	    FolderFormEx theForm = (FolderFormEx)actionForm;
+		ActionForward fwd = mapping.findForward("importBookmarks.page");
+	    if ( theForm.getBookmarksFile() != null )
+        {
+            //this line is here for when the input page is upload-utf8.jsp,
+            //it sets the correct character encoding for the response
+            String encoding = request.getCharacterEncoding();
+            if ((encoding != null) && (encoding.equalsIgnoreCase("utf-8")))
+            {
+                response.setContentType("text/html; charset=utf-8");
+            }
+
+            boolean writeFile = false; //theForm.getWriteFile();
+
+            //retrieve the file representation
+            FormFile file = theForm.getBookmarksFile();
+        /*
+            //retrieve the file name
+            String fileName= file.getFileName();
+
+            //retrieve the content type
+            String contentType = file.getContentType();
+
+            //retrieve the file size
+            String size = (file.getFileSize() + " bytes");
+        */
+            String data = null;
+
+            InputStream stream = null;
+            try 
+            {
+                //retrieve the file data
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                stream = file.getInputStream();
+                if (!writeFile) 
+                {
+                    //only write files out that are less than 1MB
+                    if (file.getFileSize() < (4*1024000)) {
+
+                        byte[] buffer = new byte[8192];
+                        int bytesRead = 0;
+                        while ((bytesRead=stream.read(buffer,0,8192)) != -1) {
+                            baos.write(buffer, 0, bytesRead);
+                        }
+                        data = new String(baos.toByteArray());
+
+                        SimpleDateFormat formatter = 
+                                new SimpleDateFormat("yyyyMMddHHmmss");
+                        Date now = new Date();
+                        String folderName = "imported-" + formatter.format(now);
+                        
+                        // Use Roller BookmarkManager to import bookmarks
+                        RollerRequest rreq = 
+                            RollerRequest.getRollerRequest(request);
+                        BookmarkManager bm = 
+                            rreq.getRoller().getBookmarkManager();    
+                        bm.importBookmarks(rreq.getWebsite(), folderName, data);
+                        
+                        rreq.getRoller().commit();
+                    }
+                    else 
+                    {
+                        data = "The file is greater than 4MB, " 
+                            +" and has not been written to stream." 
+                            +" File Size: "+file.getFileSize()+" bytes. " 
+                            +" This is a limitation of this particular "
+                            +" web application, hard-coded in "
+                            +" org.apache.struts.webapp.upload.UploadAction";
+                    }
+                }
+                else 
+                {
+                    //write the file to the file specified
+                    /*OutputStream bos = 
+                        new FileOutputStream(theForm.getFilePath());
+                    int bytesRead = 0;
+                    byte[] buffer = new byte[8192];
+                    while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
+                        bos.write(buffer, 0, bytesRead);
+                    }
+                    bos.close();
+                    data = "The file has been written to \"" 
+                        + theForm.getFilePath() + "\"";
+                    */
+                }
+            }
+            catch (Exception e) 
+            {
+            	errors.add(ActionErrors.GLOBAL_ERROR,
+				    new ActionError("error.importing.bookmarks",e.toString()));
+			    saveErrors(request,errors);
+                mLogger.error("ERROR: importing bookmarks",e);
+            }
+            finally 
+            {
+                if ( stream!=null )
+                {
+                    try { stream.close(); } 
+                    catch (Exception e) { mLogger.error("Closing stream",e); };
+                }
+            }
+
+            //destroy the temporary file created
+            file.destroy();
+        }
+		return fwd; 
+	}
+}
+

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/actions/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,10 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Struts actions for bookmarks and folders.
+
+</body>
+</html>

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarkFormEx.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarkFormEx.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarkFormEx.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarkFormEx.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,60 @@
+/*
+ * Created on Apr 8, 2003
+ */
+package org.roller.presentation.bookmarks.formbeans;
+
+import org.roller.RollerException;
+import org.roller.pojos.BookmarkData;
+import org.roller.presentation.forms.BookmarkForm;
+
+/**
+ * Extends the BookmarkForm so that additional properties may be added.
+ * These properties are not persistent and are only needed for the UI.
+ *
+ * @struts.form name="bookmarkFormEx"
+ */
+public class BookmarkFormEx extends BookmarkForm
+{
+    private String mFolderId = null;
+
+    /**
+     *
+     */
+    public BookmarkFormEx()
+    {
+        super();
+    }
+
+    /**
+     * @param dataHolder
+     */
+    public BookmarkFormEx(BookmarkData dataHolder, java.util.Locale locale) throws RollerException
+    {
+        copyFrom(dataHolder, locale);
+    }
+
+    /**
+     * @return
+     */
+    public String getFolderId()
+    {
+        return mFolderId;
+    }
+
+    /**
+     * @param string
+     */
+    public void setFolderId(String string)
+    {
+        mFolderId = string;
+    }
+
+    /**
+     * @see org.roller.presentation.forms.BookmarkForm#setData(org.roller.pojos.BookmarkData)
+     */
+    public void copyFrom(BookmarkData dataHolder, java.util.Locale locale) throws RollerException
+    {
+        super.copyFrom(dataHolder, locale);
+        mFolderId = dataHolder.getFolder().getId();
+    }
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarksForm.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarksForm.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarksForm.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/BookmarksForm.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,69 @@
+/*
+ * Created on Oct 21, 2003
+ */
+package org.roller.presentation.bookmarks.formbeans;
+
+import org.apache.struts.action.ActionForm;
+
+/**
+ * @struts.form name="bookmarksForm"
+ */ 
+public class BookmarksForm extends ActionForm
+{
+    private String folderId = null; 
+    private boolean moveContents = false; 
+    private String moveToFolderId = null; 
+    private String[] selectedBookmarks = null;
+    private String[] selectedFolders = null;
+    
+    public String getFolderId()
+    {
+        return folderId;
+    }
+
+    public void setFolderId(String folderId)
+    {
+        this.folderId = folderId;
+    }
+
+    public boolean isMoveContents()
+    {
+        return moveContents;
+    }
+
+    public void setMoveContents(boolean moveContents)
+    {
+        this.moveContents = moveContents;
+    }
+
+    public String getMoveToFolderId()
+    {
+        return moveToFolderId;
+    }
+
+    public void setMoveToFolderId(String moveToFolderId)
+    {
+        this.moveToFolderId = moveToFolderId;
+    }
+
+    public String[] getSelectedBookmarks()
+    {
+        return selectedBookmarks;
+    }
+
+    public void setSelectedBookmarks(String[] selectedBookmarks)
+    {
+        this.selectedBookmarks = selectedBookmarks;
+    }
+
+    public String[] getSelectedFolders()
+    {
+        return selectedFolders;
+    }
+
+    public void setSelectedFolders(String[] selectedFolders)
+    {
+        this.selectedFolders = selectedFolders;
+    }
+
+}

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/FolderFormEx.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/FolderFormEx.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/FolderFormEx.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/FolderFormEx.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,88 @@
+
+package org.roller.presentation.bookmarks.formbeans;
+
+import org.apache.struts.upload.FormFile;
+import org.roller.RollerException;
+import org.roller.pojos.FolderData;
+import org.roller.presentation.forms.FolderForm;
+
+
+/**
+ * Extends the FolderForm so that additional properties may be added.
+ * These properties are not persistent and are only needed for the UI.
+ *  
+ * @struts.form name="folderFormEx"
+ */ 
+public class FolderFormEx extends FolderForm
+{
+	private boolean mMoveContents = false; 
+	private String mMoveToFolderId = null; 
+    private String[] mSelectedBookmarks = null;
+    private String[] mSelectedFolders = null;
+    private transient FormFile mBookmarksFile = null;
+
+	public FolderFormEx()
+	{
+		super();
+	}
+
+	public FolderFormEx(FolderData folderData, java.util.Locale locale) throws RollerException
+	{
+		super(folderData, locale);
+	}
+
+    public String getShortenedDesc() 
+    {
+        if ( getDescription().length() > 20 )
+        {
+            return getDescription().substring(0,19)+"...";
+        }
+        return getDescription();
+    }
+
+    public void setShortenedDesc( String desc )
+    {
+        // readonly
+    }
+
+    //------------------------------------------------- Property bookmarksFile 
+
+    /** Bookmark file to be imported */
+    public void setBookmarksFile(FormFile file) { mBookmarksFile = file; }
+
+    /** Bookmark file to be imported */
+    public FormFile getBookmarksFile() { return mBookmarksFile; }
+
+    //-------------------------------------------------- Property moveContents
+
+	/** If true then contents should be moved when this folder is removed */
+	public boolean getMoveContents() { return mMoveContents; }
+
+	/** If true then contents should be moved when this folder is removed */
+	public void setMoveContents( boolean flag ) { mMoveContents = flag;}
+
+    //------------------------------------------------ Property moveToFolderId
+
+	/** Folder where contents should be moved if this folder is removed */ 
+	public String getMoveToFolderId() { return mMoveToFolderId; }
+
+	/** Folder where contents should be moved if this folder is removed */ 
+	public void setMoveToFolderId( String id ) { mMoveToFolderId = id;}
+
+    //--------------------------------------------- Property selectedBookmarks 
+
+    /** Get selected bookmarks */
+    public String[] getSelectedBookmarks() { return mSelectedBookmarks; }
+
+    /** Set selected bookmarks */
+    public void setSelectedBookmarks( String[] b ) { mSelectedBookmarks = b; }
+
+    //--------------------------------------------- Property selectedBookmarks 
+
+    /** Get selected folders */
+    public String[] getSelectedFolders() { return mSelectedFolders; }
+
+    /** Set selected bookmarks */
+    public void setSelectedFolders( String[] f ) { mSelectedFolders = f; }
+}
+

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/package.html
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/package.html?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/package.html (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/formbeans/package.html Fri Oct 21 14:27:36 2005
@@ -0,0 +1,10 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+Extended form beans needed for bookmarks and folders.
+
+</body>
+</html>

Added: incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/tags/ViewBookmarksTag.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/tags/ViewBookmarksTag.java?rev=327589&view=auto
==============================================================================
--- incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/tags/ViewBookmarksTag.java (added)
+++ incubator/roller/branches/roller_1.x/src/org/roller/presentation/bookmarks/tags/ViewBookmarksTag.java Fri Oct 21 14:27:36 2005
@@ -0,0 +1,234 @@
+package org.roller.presentation.bookmarks.tags;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.model.BookmarkManager;
+import org.roller.pojos.BookmarkComparator;
+import org.roller.pojos.BookmarkData;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.UserData;
+import org.roller.presentation.RollerContext;
+import org.roller.presentation.RollerRequest;
+import org.roller.util.Utilities;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.Tag;
+
+
+/**
+ * @deprecated Is this class even in use anymore? -Lance
+ * 
+ * <p>Displays a folder of bookmarks or a table that shows all folders.
+ * If the folderName property is set then this tag will display the bookmarks
+ * in that folder, separated by BR tag line breaks. If the folderName
+ * property is not set, this tag will display a table of bookmarks.
+ * </p>
+ * <p>The bookmarks table display uses the Folder Column and Row values
+ * to position the Folders in a table. The bookmarks within each folder
+ * are ordered using the Bookmark Priority value. A bookmark's HREF tag
+ * is given a CSS class of rBookmark_N where N is the Bookmark's Weight value.
+ * </p>
+ * @jsp.tag name="ViewBookmarks"
+ */
+public class ViewBookmarksTag extends org.roller.presentation.tags.HybridTag
+{
+    static final long serialVersionUID = -4357415994168654686L;
+    
+    private static Log mLogger = 
+       LogFactory.getFactory().getInstance(ViewBookmarksTag.class);
+
+    /** @jsp.attribute */
+    public String getFolderName() { return mFolderName; }
+    public void setFolderName(String v) { mFolderName = v; }
+    private String mFolderName = null;
+
+    /** @jsp.attribute */
+    public String getTitle() { return mTitle; }
+    public void setTitle(String v) { mTitle = v; }
+    private String mTitle = null;
+
+    /** @jsp.attribute */
+    public boolean getShowFolderName() { return mShowFolderName; }
+    public void setShowFolderName(boolean v) { mShowFolderName = v; }
+    private boolean mShowFolderName = true;
+
+    /** @jsp.attribute */
+    public boolean getExpandingFolder() { return mExpandingFolder; }
+    public void setExpandingFolder(boolean v) { mExpandingFolder = v; }
+    private boolean mExpandingFolder = false;
+    
+    //------------------------------------------------------------------------
+
+    public String view( String folderName, String title )
+    {
+        mFolderName = folderName;
+        mTitle = title;
+        return emit();
+    }
+
+    public String view( String folderName, boolean showFolderName )
+    {
+        mFolderName = folderName;
+        mShowFolderName = showFolderName;
+        return emit();
+    }
+
+    public String view( String folderName, boolean showFolderName, boolean expandingFolder )
+    {
+        mFolderName = folderName;
+        mShowFolderName = showFolderName;
+        mExpandingFolder = expandingFolder;
+        return emit();
+    }
+    
+    //-------------------------------------------------------------
+    /**
+     * Process start tag
+     * @return EVAL_SKIP_BODY
+     */
+    public int doStartTag( PrintWriter pw ) throws JspException
+    {
+        try
+        {
+            HttpServletRequest req =
+                (HttpServletRequest)pageContext.getRequest();
+            RollerRequest rreq = RollerRequest.getRollerRequest(req);
+            BookmarkManager bookmarkMgr =
+                rreq.getRoller().getBookmarkManager();
+            UserData user = rreq.getUser();
+
+            FolderData fd = bookmarkMgr.getFolder(
+                rreq.getWebsite(), mFolderName);
+
+            if ( fd == null )
+            {
+                pw.print("<span class=\"error\">");
+                pw.print("Error fetching folder named "+mFolderName);
+                pw.print("</span>");
+                return  Tag.SKIP_BODY;
+            }
+            emitFolderHTML( pw, pageContext, fd, user );
+            return Tag.SKIP_BODY;
+        }
+        catch (Exception e)
+        {
+            mLogger.error("Exception",e);
+            throw new JspException(
+                e.getClass().toString()+": "+e.getMessage(),e);
+        }
+    }
+
+    //------------------------------------------------------------------------
+    public void emitBookmarkHTML( PrintWriter pw, PageContext ctx,
+        BookmarkData bookmark, UserData user )
+        throws IOException, MalformedURLException
+    {
+        HttpServletRequest request = (HttpServletRequest)ctx.getRequest();
+        String cpath = request.getContextPath();
+
+        String resourcePath = request.getContextPath()
+                + RollerContext.getUploadPath(pageContext.getServletContext())
+                    + "/" + user.getUserName();
+
+        if ( bookmark.getImage()!=null
+         && !bookmark.getImage().trim().equals("") )
+        {
+            pw.print("<a href=\""+bookmark.getUrl()+"\">");
+            pw.println("<img src=\""
+                + resourcePath + "/" + bookmark.getImage() + "\" "
+                + "alt=\"" + bookmark.getName() + "\" /> " );
+            pw.println("</a><br />");
+        }
+        else if ( bookmark.getFeedUrl()!=null
+              && !bookmark.getFeedUrl().trim().equals("") )
+        {
+            pw.print("<a class=\"rBookmark\" href=\""+bookmark.getUrl()+"\"");
+            if ( !bookmark.getDescription().trim().equals("") )
+            {
+                pw.print(" title=\""+bookmark.getDescription()+"\"");
+            }
+            pw.print(" >");
+            pw.println( bookmark.getName()+"</a>");
+
+            pw.println( "<a href=\""+bookmark.getFeedUrl()+"\">" );
+            pw.print  ( "<img src=\""+cpath+"/images/smrssbadge.gif\" " );
+            pw.println(     "alt=\"URL of site's RSS feed\"" );
+            pw.println(     "class=\"smrssbadge\" /></a>" );
+
+            pw.println( "<br />" );
+        }
+        else
+        {
+            pw.print( "<a href=\"" );
+            pw.print( bookmark.getUrl() );
+            pw.print( "\" " );
+            pw.print( "class=\"rBookmark" );
+            pw.print( bookmark.getWeight() );
+            pw.print( "\" " );
+            pw.print( "title=\""  );
+            pw.print( bookmark.getDescription() );
+            pw.print( "\" >" );
+            pw.print( bookmark.getName() );
+            pw.println( "</a><br />" );
+        }
+    }
+
+    //------------------------------------------------------------------------
+    public void emitFolderHTML( PrintWriter pw, PageContext ctx,
+        FolderData folder, UserData user )
+        throws IOException, MalformedURLException
+    {
+        HttpServletRequest request = (HttpServletRequest)ctx.getRequest();
+        String cpath = request.getContextPath();
+        // replace spaces with underscores
+        String divId = Utilities.stringReplace( folder.getName(), " ", "_" );
+        // remove single quotes to prevent javascript errors
+        divId = Utilities.stringReplace( divId, "'", "" );
+        
+        if ( mShowFolderName && !mExpandingFolder )
+        {
+            pw.println( "<div class=\"rFolder\">"+folder.getName()+"</div>" );
+        }
+
+        if ( mShowFolderName && mExpandingFolder )
+        {            
+            pw.print( "<div class=\"rFolder\"><a href=\"javascript:" );
+            pw.print( "toggleFolder('"+divId+"')\"><span id=\"i"+divId+"\">" );
+            pw.print( "+</span> "+folder.getName()+"</a></div>" );
+            pw.println( "<div id=\""+divId+"\" style=\"display: none\">" );       
+        }
+        
+        Collection bookmarks = folder.getBookmarks();
+        //java.util.Collections.sort( bookmarks, new BookmarkComparator() );
+        Iterator iter = bookmarks.iterator();
+        while ( iter.hasNext() )
+        {
+            BookmarkData bookmark = (BookmarkData)iter.next();
+            emitBookmarkHTML( pw, ctx, bookmark, user );
+        }
+        
+        if (mShowFolderName && mExpandingFolder)
+        {
+            pw.println( "</div>" );       
+            pw.println( "<script type=\"text/javascript\">" );
+            pw.println( "<!--" );
+            pw.println( "  folderPreference('"+divId+"');" );
+            pw.println( "// -->");
+            pw.println( "</script>" );
+        }
+    }
+}
+