You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rave.apache.org by ja...@apache.org on 2011/11/15 14:16:26 UTC

svn commit: r1202169 - in /incubator/rave/trunk: rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/ rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/ rave-components/rave-web/src/main/java/org/apach...

Author: jasha
Date: Tue Nov 15 13:16:25 2011
New Revision: 1202169

URL: http://svn.apache.org/viewvc?rev=1202169&view=rev
Log:
RAVE-355 finish initial portal preference page (page title suffix, number of items per page)
RAVE-140 make number of items per page (in the main portal, not the admin interface) configurable

Added:
    incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/util/PortalPreferenceKeys.java
    incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidator.java
    incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceControllerTest.java
    incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidatorTest.java
Modified:
    incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultWidgetService.java
    incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/WidgetStoreController.java
    incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceController.java
    incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/model/PortalPreferenceForm.java
    incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/WidgetStoreControllerTest.java
    incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/model/PortalPreferenceFormTest.java
    incubator/rave/trunk/rave-portal-resources/src/main/resources/messages.properties
    incubator/rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties
    incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferencedetail.jsp
    incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp

Modified: incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultWidgetService.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultWidgetService.java?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultWidgetService.java (original)
+++ incubator/rave/trunk/rave-components/rave-core/src/main/java/org/apache/rave/portal/service/impl/DefaultWidgetService.java Tue Nov 15 13:16:25 2011
@@ -27,8 +27,6 @@ import org.apache.rave.portal.model.util
 import org.apache.rave.portal.model.util.WidgetStatistics;
 import org.apache.rave.portal.repository.WidgetRepository;
 import org.apache.rave.portal.service.WidgetService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -39,8 +37,6 @@ import java.util.Map;
 @Service
 public class DefaultWidgetService implements WidgetService {
 
-    private static Logger logger = LoggerFactory.getLogger(DefaultWidgetService.class);
-
     private final WidgetRepository widgetRepository;
 
     @Autowired

Modified: incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/WidgetStoreController.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/WidgetStoreController.java?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/WidgetStoreController.java (original)
+++ incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/WidgetStoreController.java Tue Nov 15 13:16:25 2011
@@ -19,12 +19,15 @@
 
 package org.apache.rave.portal.web.controller;
 
+import org.apache.rave.portal.model.PortalPreference;
 import org.apache.rave.portal.model.User;
 import org.apache.rave.portal.model.Widget;
 import org.apache.rave.portal.model.WidgetStatus;
+import org.apache.rave.portal.service.PortalPreferenceService;
 import org.apache.rave.portal.service.UserService;
 import org.apache.rave.portal.service.WidgetService;
 import org.apache.rave.portal.web.util.ModelKeys;
+import org.apache.rave.portal.web.util.PortalPreferenceKeys;
 import org.apache.rave.portal.web.util.ViewNames;
 import org.apache.rave.portal.web.validator.NewWidgetValidator;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -49,12 +52,15 @@ public class WidgetStoreController {
 
     private final UserService userService;
 
+    private final PortalPreferenceService preferenceService;
+
     @Autowired
     public WidgetStoreController(WidgetService widgetService, NewWidgetValidator validator,
-                                 UserService userService) {
+                                 UserService userService, PortalPreferenceService preferenceService) {
         this.widgetService = widgetService;
         this.widgetValidator = validator;
         this.userService = userService;
+        this.preferenceService = preferenceService;
     }
 
     /**
@@ -70,7 +76,7 @@ public class WidgetStoreController {
                        @RequestParam(required = false, defaultValue = "0") int offset) {
         User user = userService.getAuthenticatedUser();
         model.addAttribute(ModelKeys.WIDGETS,
-                widgetService.getPublishedWidgets(offset, MAXIMUM_WIDGETS_PER_PAGE));
+                widgetService.getPublishedWidgets(offset, getPageSize()));
         model.addAttribute(ModelKeys.REFERRING_PAGE_ID, referringPageId);
         model.addAttribute(ModelKeys.WIDGETS_STATISTICS, widgetService.getAllWidgetStatistics(user.getEntityId()));
         return ViewNames.STORE;
@@ -100,7 +106,7 @@ public class WidgetStoreController {
      *
      * @param model           {@link Model} map
      * @param referringPageId the source {@link org.apache.rave.portal.model.Page } ID
-     * @param searchTerm          free text searchTerm query
+     * @param searchTerm      free text searchTerm query
      * @param offset          offset within the total amount of results (to enable paging)
      * @return the view name of the main store page
      */
@@ -110,8 +116,7 @@ public class WidgetStoreController {
                                    @RequestParam(required = false, defaultValue = "0") int offset) {
         User user = userService.getAuthenticatedUser();
         model.addAttribute(ModelKeys.WIDGETS,
-                widgetService.getPublishedWidgetsByFreeTextSearch(searchTerm, offset,
-                        MAXIMUM_WIDGETS_PER_PAGE));
+                widgetService.getPublishedWidgetsByFreeTextSearch(searchTerm, offset, getPageSize()));
         model.addAttribute(ModelKeys.REFERRING_PAGE_ID, referringPageId);
         model.addAttribute(ModelKeys.SEARCH_TERM, searchTerm);
         model.addAttribute(ModelKeys.OFFSET, offset);
@@ -123,11 +128,12 @@ public class WidgetStoreController {
     /**
      * Shows the Add new Widget form
      *
-     * @param model {@link Model}
+     * @param model           {@link Model}
+     * @param referringPageId the source {@link org.apache.rave.portal.model.Page } ID
      * @return the view name of the Add new Widget form
      */
     @RequestMapping(method = RequestMethod.GET, value = "widget/add")
-    public String viewAddWidgetForm(Model model,@RequestParam long referringPageId) {
+    public String viewAddWidgetForm(Model model, @RequestParam long referringPageId) {
         final Widget widget = new Widget();
         model.addAttribute(ModelKeys.REFERRING_PAGE_ID, referringPageId);
         model.addAttribute(ModelKeys.WIDGET, widget);
@@ -137,14 +143,15 @@ public class WidgetStoreController {
     /**
      * Validates the form input, if valid, tries to store the Widget data
      *
-     * @param widget  {@link Widget} as submitted by the user
-     * @param results {@link BindingResult}
-     * @param model   {@link Model}
+     * @param widget          {@link Widget} as submitted by the user
+     * @param results         {@link BindingResult}
+     * @param model           {@link Model}
+     * @param referringPageId the source {@link org.apache.rave.portal.model.Page } ID
      * @return if successful the view name of the widget, otherwise the form
      */
     @RequestMapping(method = RequestMethod.POST, value = "widget/add")
     public String viewAddWidgetResult(@ModelAttribute Widget widget, BindingResult results,
-                                      Model model,@RequestParam long referringPageId   ) {
+                                      Model model, @RequestParam long referringPageId) {
         User user = userService.getAuthenticatedUser();
         widgetValidator.validate(widget, results);
         if (results.hasErrors()) {
@@ -157,8 +164,21 @@ public class WidgetStoreController {
         final Widget storedWidget = widgetService.registerNewWidget(widget);
         model.addAttribute(ModelKeys.REFERRING_PAGE_ID, referringPageId);
         model.addAttribute(ModelKeys.WIDGET, storedWidget);
-        model.addAttribute(ModelKeys.WIDGET_STATISTICS, widgetService.getWidgetStatistics(storedWidget.getEntityId(), user.getEntityId()));
+        model.addAttribute(ModelKeys.WIDGET_STATISTICS,
+                widgetService.getWidgetStatistics(storedWidget.getEntityId(), user.getEntityId()));
         model.addAttribute(ModelKeys.USER_PROFILE, user);
         return ViewNames.WIDGET;
     }
+
+    public int getPageSize() {
+        final PortalPreference pageSizePref = preferenceService.getPreference(PortalPreferenceKeys.PAGE_SIZE);
+        if (pageSizePref == null) {
+            return MAXIMUM_WIDGETS_PER_PAGE;
+        }
+        try {
+            return Integer.parseInt(pageSizePref.getValue());
+        } catch (NumberFormatException e) {
+            return MAXIMUM_WIDGETS_PER_PAGE;
+        }
+    }
 }

Modified: incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceController.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceController.java?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceController.java (original)
+++ incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceController.java Tue Nov 15 13:16:25 2011
@@ -24,6 +24,7 @@ import org.apache.rave.portal.service.Po
 import org.apache.rave.portal.web.model.PortalPreferenceForm;
 import org.apache.rave.portal.web.util.ModelKeys;
 import org.apache.rave.portal.web.util.ViewNames;
+import org.apache.rave.portal.web.validator.PortalPreferenceFormValidator;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -37,13 +38,14 @@ import org.springframework.web.bind.anno
 import org.springframework.web.bind.support.SessionStatus;
 
 import java.util.Map;
+import java.util.Set;
 
+import static org.apache.rave.portal.web.controller.admin.AdminControllerUtil.addNavigationMenusToModel;
 import static org.apache.rave.portal.web.controller.admin.AdminControllerUtil.checkTokens;
 import static org.apache.rave.portal.web.controller.admin.AdminControllerUtil.isDeleteOrUpdate;
 
 /**
  * Controller for portal preferences
- * TODO RAVE-355 create unit tests
  */
 @Controller
 @SessionAttributes({"preferenceForm", ModelKeys.TOKENCHECK})
@@ -53,10 +55,13 @@ public class PortalPreferenceController 
     @Autowired
     private PortalPreferenceService preferenceService;
 
+    @Autowired
+    private PortalPreferenceFormValidator formValidator;
+
     @RequestMapping(value = {"/admin/preferences", "/admin/preferences/"}, method = RequestMethod.GET)
     public String viewPreferences(@RequestParam(required = false) final String action, Model model) {
-        AdminControllerUtil.addNavigationMenusToModel(SELECTED_ITEM, model);
-        
+        addNavigationMenusToModel(SELECTED_ITEM, model);
+
         final Map<String, PortalPreference> preferenceMap = preferenceService.getPreferencesAsMap();
 
         model.addAttribute("preferenceMap", preferenceMap);
@@ -70,7 +75,7 @@ public class PortalPreferenceController 
 
     @RequestMapping(value = "/admin/preferencedetail/edit", method = RequestMethod.GET)
     public String editPreferences(Model model) {
-        AdminControllerUtil.addNavigationMenusToModel(SELECTED_ITEM, model);
+        addNavigationMenusToModel(SELECTED_ITEM, model);
         final Map<String, PortalPreference> preferenceMap = preferenceService.getPreferencesAsMap();
 
         PortalPreferenceForm form = new PortalPreferenceForm(preferenceMap);
@@ -83,16 +88,33 @@ public class PortalPreferenceController 
     @RequestMapping(value = "/admin/preferencedetail/update", method = RequestMethod.POST)
     public String updatePreferences(@ModelAttribute("preferenceForm") PortalPreferenceForm form, BindingResult result,
                                     @ModelAttribute(ModelKeys.TOKENCHECK) String sessionToken,
-                                    @RequestParam() String token,
+                                    @RequestParam String token,
                                     ModelMap modelMap,
                                     SessionStatus status) {
         checkTokens(sessionToken, token, status);
-        preferenceService.savePreference(form.getPageSize());
-        preferenceService.savePreference(form.getTitleSuffix());
+
+        formValidator.validate(form, result);
+        if (result.hasErrors()) {
+            addNavigationMenusToModel(SELECTED_ITEM, (Model) modelMap);
+            return ViewNames.ADMIN_PREFERENCE_DETAIL;
+        }
+
+        final Set<Map.Entry<String, PortalPreference>> entries = form.getPreferenceMap().entrySet();
+
+        for (Map.Entry<String, PortalPreference> entry : entries) {
+            preferenceService.savePreference(entry.getValue());
+        }
 
         modelMap.clear();
         status.setComplete();
         return "redirect:/app/admin/preferences?action=update";
     }
 
+    void setFormValidator(PortalPreferenceFormValidator formValidator) {
+        this.formValidator = formValidator;
+    }
+
+    public void setPreferenceService(PortalPreferenceService preferenceService) {
+        this.preferenceService = preferenceService;
+    }
 }

Modified: incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/model/PortalPreferenceForm.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/model/PortalPreferenceForm.java?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/model/PortalPreferenceForm.java (original)
+++ incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/model/PortalPreferenceForm.java Tue Nov 15 13:16:25 2011
@@ -21,47 +21,51 @@ package org.apache.rave.portal.web.model
 
 import org.apache.rave.portal.model.PortalPreference;
 
-import java.util.HashMap;
 import java.util.Map;
 
+import static org.apache.rave.portal.web.util.PortalPreferenceKeys.PAGE_SIZE;
+import static org.apache.rave.portal.web.util.PortalPreferenceKeys.TITLE_SUFFIX;
+
 /**
  * Form object for portal preferences
  */
 public class PortalPreferenceForm {
 
-    public static final String KEY_PAGE_SIZE = "pageSize";
     public static final String DEFAULT_PAGE_SIZE = "10";
-
-    public static final String KEY_TITLE_SUFFIX = "titleSuffix";
-    public static final String DEFAULT_TITLE_SUFFIX = "- Rave";
+    public static final String DEFAULT_TITLE_SUFFIX = "";
 
 
     private Map<String, PortalPreference> preferenceMap;
-    
-    public PortalPreferenceForm() {
-        // TODO RAVE-355 populate preferences if they don't exist in the db
-        this(new HashMap<String, PortalPreference>());
-    }
 
     public PortalPreferenceForm(Map<String, PortalPreference> preferenceMap) {
         super();
         this.preferenceMap = preferenceMap;
+        populateMissingPreferences();
+    }
+
+    private void populateMissingPreferences() {
+        if (getPageSize() == null) {
+            preferenceMap.put(PAGE_SIZE, new PortalPreference(PAGE_SIZE, DEFAULT_PAGE_SIZE));
+        }
+        if (getTitleSuffix() == null) {
+            preferenceMap.put(TITLE_SUFFIX, new PortalPreference(TITLE_SUFFIX, DEFAULT_TITLE_SUFFIX));
+        }
     }
 
     public PortalPreference getPageSize() {
-        return preferenceMap.get(KEY_PAGE_SIZE);
+        return preferenceMap.get(PAGE_SIZE);
     }
 
     public void setPageSize(PortalPreference pageSize) {
-        preferenceMap.put(KEY_PAGE_SIZE, pageSize);
+        preferenceMap.put(PAGE_SIZE, pageSize);
     }
 
     public PortalPreference getTitleSuffix() {
-        return preferenceMap.get(KEY_TITLE_SUFFIX);
+        return preferenceMap.get(TITLE_SUFFIX);
     }
 
     public void setTitleSuffix(PortalPreference titleSuffix) {
-        preferenceMap.put(KEY_TITLE_SUFFIX, titleSuffix);
+        preferenceMap.put(TITLE_SUFFIX, titleSuffix);
     }
 
     public Map<String, PortalPreference> getPreferenceMap() {

Added: incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/util/PortalPreferenceKeys.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/util/PortalPreferenceKeys.java?rev=1202169&view=auto
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/util/PortalPreferenceKeys.java (added)
+++ incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/util/PortalPreferenceKeys.java Tue Nov 15 13:16:25 2011
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.
+ */
+
+package org.apache.rave.portal.web.util;
+
+/**
+ * Utility class for {@link org.apache.rave.portal.model.PortalPreference} keys
+ */
+public final class PortalPreferenceKeys {
+    private PortalPreferenceKeys() {
+
+    }
+
+    public static final String TITLE_SUFFIX = "titleSuffix";
+    public static final String PAGE_SIZE = "pageSize";
+
+}

Added: incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidator.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidator.java?rev=1202169&view=auto
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidator.java (added)
+++ incubator/rave/trunk/rave-components/rave-web/src/main/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidator.java Tue Nov 15 13:16:25 2011
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.
+ */
+
+package org.apache.rave.portal.web.validator;
+
+import org.apache.rave.portal.web.model.PortalPreferenceForm;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+/**
+ * Validates {@link PortalPreferenceForm}
+ */
+@Component
+public class PortalPreferenceFormValidator implements Validator {
+
+    @Override
+    public boolean supports(Class<?> clazz) {
+        return PortalPreferenceForm.class.isAssignableFrom(clazz);
+    }
+
+    @Override
+    public void validate(Object target, Errors errors) {
+        PortalPreferenceForm form = (PortalPreferenceForm) target;
+
+        validateRequiredFields(errors);
+        validatePageSize(form, errors);
+    }
+
+    private void validateRequiredFields(Errors errors) {
+        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pageSize.value", "form.field.error.required");
+    }
+
+    private void validatePageSize(PortalPreferenceForm form, Errors errors) {
+        if (form.getPageSize() != null) {
+            int pageSizeValue;
+            try {
+                pageSizeValue = Integer.parseInt(form.getPageSize().getValue());
+            } catch (NumberFormatException e) {
+                pageSizeValue = 0;
+            }
+            if (pageSizeValue <= 0) {
+                errors.rejectValue("pageSize.value", "admin.preferencedetail.pageSize.malformed");
+            }
+        }
+    }
+}

Modified: incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/WidgetStoreControllerTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/WidgetStoreControllerTest.java?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/WidgetStoreControllerTest.java (original)
+++ incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/WidgetStoreControllerTest.java Tue Nov 15 13:16:25 2011
@@ -25,9 +25,11 @@ import org.apache.rave.portal.model.Widg
 import org.apache.rave.portal.model.WidgetStatus;
 import org.apache.rave.portal.model.util.SearchResult;
 import org.apache.rave.portal.model.util.WidgetStatistics;
+import org.apache.rave.portal.service.PortalPreferenceService;
 import org.apache.rave.portal.service.UserService;
 import org.apache.rave.portal.service.WidgetService;
 import org.apache.rave.portal.web.util.ModelKeys;
+import org.apache.rave.portal.web.util.PortalPreferenceKeys;
 import org.apache.rave.portal.web.util.ViewNames;
 import org.apache.rave.portal.web.validator.NewWidgetValidator;
 import org.junit.Before;
@@ -81,11 +83,17 @@ public class WidgetStoreControllerTest {
         allWidgetStatisticsMap.put(WIDGET_ID, widgetStatistics);
 
         widgetService = createMock(WidgetService.class);
+
         UserService userService = createMock(UserService.class);
         expect(userService.getAuthenticatedUser()).andReturn(validUser);
         replay(userService);
+
+        PortalPreferenceService preferenceService = createMock(PortalPreferenceService.class);
+        expect(preferenceService.getPreference(PortalPreferenceKeys.PAGE_SIZE)).andReturn(null);
+        replay(preferenceService);
+
         NewWidgetValidator widgetValidator = new NewWidgetValidator(widgetService);
-        controller = new WidgetStoreController(widgetService, widgetValidator, userService);
+        controller = new WidgetStoreController(widgetService, widgetValidator, userService, preferenceService);
     }
 
     @Test

Added: incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceControllerTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceControllerTest.java?rev=1202169&view=auto
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceControllerTest.java (added)
+++ incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/controller/admin/PortalPreferenceControllerTest.java Tue Nov 15 13:16:25 2011
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.
+ */
+
+package org.apache.rave.portal.web.controller.admin;
+
+import org.apache.rave.portal.model.PortalPreference;
+import org.apache.rave.portal.service.PortalPreferenceService;
+import org.apache.rave.portal.web.model.PortalPreferenceForm;
+import org.apache.rave.portal.web.util.ModelKeys;
+import org.apache.rave.portal.web.util.PortalPreferenceKeys;
+import org.apache.rave.portal.web.util.ViewNames;
+import org.apache.rave.portal.web.validator.PortalPreferenceFormValidator;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.ui.ExtendedModelMap;
+import org.springframework.ui.Model;
+import org.springframework.ui.ModelMap;
+import org.springframework.validation.BeanPropertyBindingResult;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.support.SessionStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Test for {@link PortalPreferenceController}
+ */
+public class PortalPreferenceControllerTest {
+
+    private PortalPreferenceController controller;
+    private PortalPreferenceService service;
+    private String validToken;
+
+    @Before
+    public void setUp() {
+        controller = new PortalPreferenceController();
+        service = createMock(PortalPreferenceService.class);
+        controller.setPreferenceService(service);
+        controller.setFormValidator(new PortalPreferenceFormValidator());
+        validToken = AdminControllerUtil.generateSessionToken();
+    }
+
+    @Test
+    public void testViewPreferences() {
+        Model model = new ExtendedModelMap();
+        Map<String, PortalPreference> preferenceMap = new HashMap<String, PortalPreference>();
+
+        expect(service.getPreferencesAsMap()).andReturn(preferenceMap);
+        replay(service);
+
+        String view = controller.viewPreferences(null, model);
+
+        assertEquals(ViewNames.ADMIN_PREFERENCES, view);
+        assertEquals(preferenceMap, model.asMap().get("preferenceMap"));
+        assertFalse(model.containsAttribute("actionresult"));
+        assertTrue(model.containsAttribute("topnav"));
+        assertTrue(model.containsAttribute("tabs"));
+
+        verify(service);
+    }
+
+    @Test
+
+    public void testViewPreferences_afterUpdate() {
+        Model model = new ExtendedModelMap();
+        Map<String, PortalPreference> preferenceMap = new HashMap<String, PortalPreference>();
+
+        expect(service.getPreferencesAsMap()).andReturn(preferenceMap);
+        replay(service);
+
+        final String action = "update";
+        String view = controller.viewPreferences(action, model);
+
+        assertEquals(ViewNames.ADMIN_PREFERENCES, view);
+        assertEquals(preferenceMap, model.asMap().get("preferenceMap"));
+        assertEquals(action, model.asMap().get("actionresult"));
+        assertTrue(model.containsAttribute("topnav"));
+        assertTrue(model.containsAttribute("tabs"));
+
+        verify(service);
+    }
+
+    @Test
+    public void testEditPreferences() {
+        Model model = new ExtendedModelMap();
+
+        Map<String, PortalPreference> preferenceMap = new HashMap<String, PortalPreference>();
+
+        expect(service.getPreferencesAsMap()).andReturn(preferenceMap);
+        replay(service);
+        String view = controller.editPreferences(model);
+        assertEquals(ViewNames.ADMIN_PREFERENCE_DETAIL, view);
+
+        assertTrue(model.asMap().get("preferenceForm") instanceof PortalPreferenceForm);
+        assertTrue(model.containsAttribute(ModelKeys.TOKENCHECK));
+        assertTrue(model.containsAttribute("topnav"));
+        assertTrue(model.containsAttribute("tabs"));
+    }
+
+    @Test
+    public void testUpdatePreferences_valid() {
+        ModelMap model = new ExtendedModelMap();
+        PortalPreferenceForm form = new PortalPreferenceForm(new HashMap<String, PortalPreference>());
+        final BindingResult errors = new BeanPropertyBindingResult(form, "form");
+        SessionStatus sessionStatus = createMock(SessionStatus.class);
+
+        final Set<Map.Entry<String, PortalPreference>> entries = form.getPreferenceMap().entrySet();
+
+        for (Map.Entry<String, PortalPreference> entry : entries) {
+            service.savePreference(entry.getValue());
+        }
+        sessionStatus.setComplete();
+
+        expectLastCall();
+        replay(service, sessionStatus);
+        String view = controller.updatePreferences(form, errors, validToken, validToken, model, sessionStatus);
+
+        assertEquals("redirect:/app/admin/preferences?action=update", view);
+        assertTrue("Model has been cleared", model.isEmpty());
+
+        verify(service, sessionStatus);
+    }
+    
+    @Test(expected = SecurityException.class)
+    public void testUpdatePreferences_invalidToken() {
+        ModelMap model = new ExtendedModelMap();
+        String invalidToken = AdminControllerUtil.generateSessionToken();
+        PortalPreferenceForm form = new PortalPreferenceForm(new HashMap<String, PortalPreference>());
+        final BindingResult errors = new BeanPropertyBindingResult(form, "form");
+        SessionStatus sessionStatus = createMock(SessionStatus.class);
+        sessionStatus.setComplete();
+        
+        expectLastCall();
+        replay(service, sessionStatus);
+        controller.updatePreferences(form, errors, validToken, invalidToken, model, sessionStatus);
+
+        assertFalse("Should not end up here", true);
+        verify(service, sessionStatus);
+    }
+
+    @Test
+    public void testUpdatePreferences_invalidPageSizeValue() {
+        ModelMap model = new ExtendedModelMap();
+        HashMap<String, PortalPreference> preferenceMap = new HashMap<String, PortalPreference>();
+        PortalPreference pageSizePref = new PortalPreference(PortalPreferenceKeys.PAGE_SIZE, "invalid");
+        preferenceMap.put(PortalPreferenceKeys.PAGE_SIZE, pageSizePref);
+        PortalPreferenceForm form = new PortalPreferenceForm(preferenceMap);
+        final BindingResult errors = new BeanPropertyBindingResult(form, "form");
+        SessionStatus sessionStatus = createMock(SessionStatus.class);
+
+        replay(service, sessionStatus);
+        String view = controller.updatePreferences(form, errors, validToken, validToken, model, sessionStatus);
+
+        assertEquals(ViewNames.ADMIN_PREFERENCE_DETAIL, view);
+        assertTrue(errors.hasErrors());
+        assertTrue(model.containsAttribute("topnav"));
+        assertTrue(model.containsAttribute("tabs"));
+        assertFalse("Model has not been cleared", model.isEmpty());
+
+        verify(service, sessionStatus);
+    }
+
+}

Modified: incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/model/PortalPreferenceFormTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/model/PortalPreferenceFormTest.java?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/model/PortalPreferenceFormTest.java (original)
+++ incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/model/PortalPreferenceFormTest.java Tue Nov 15 13:16:25 2011
@@ -27,10 +27,8 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static org.apache.rave.portal.web.model.PortalPreferenceForm.KEY_PAGE_SIZE;
-import static org.apache.rave.portal.web.model.PortalPreferenceForm.KEY_TITLE_SUFFIX;
+import static org.apache.rave.portal.web.util.PortalPreferenceKeys.PAGE_SIZE;
+import static org.apache.rave.portal.web.util.PortalPreferenceKeys.TITLE_SUFFIX;
 
 /**
  * Test for {@link PortalPreferenceForm}
@@ -40,24 +38,23 @@ public class PortalPreferenceFormTest {
 
     @Before
     public void setUp() throws Exception {
-        PortalPreference titlePref = new PortalPreference(KEY_TITLE_SUFFIX, "Test portal");
-        preferenceMap.put(KEY_TITLE_SUFFIX, titlePref);
-        PortalPreference pageSizePref = new PortalPreference(KEY_PAGE_SIZE, "20");
-        preferenceMap.put(KEY_PAGE_SIZE, pageSizePref);
+        PortalPreference titlePref = new PortalPreference(TITLE_SUFFIX, "Test portal");
+        preferenceMap.put(TITLE_SUFFIX, titlePref);
+        PortalPreference pageSizePref = new PortalPreference(PAGE_SIZE, "20");
+        preferenceMap.put(PAGE_SIZE, pageSizePref);
     }
 
     @Test
-    public void testEmptyConstructor() throws Exception {
-        PortalPreferenceForm form = new PortalPreferenceForm();
-        assertNull(form.getPageSize());
-        assertNull(form.getTitleSuffix());
-        assertTrue(form.getPreferenceMap().isEmpty());
-    }
-
-    @Test
-    public void testPopulatedForm() throws Exception {
+    public void testForm_populatedMap() throws Exception {
         PortalPreferenceForm form = new PortalPreferenceForm(preferenceMap);
         assertEquals("Test portal", form.getTitleSuffix().getValue());
         assertEquals("20", form.getPageSize().getValue());
     }
+
+    @Test
+    public void testForm_emptyMap() throws Exception {
+        PortalPreferenceForm form = new PortalPreferenceForm(new HashMap<String, PortalPreference>());
+        assertEquals(PortalPreferenceForm.DEFAULT_PAGE_SIZE, form.getPageSize().getValue());
+        assertEquals(PortalPreferenceForm.DEFAULT_TITLE_SUFFIX, form.getTitleSuffix().getValue());
+    }
 }

Added: incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidatorTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidatorTest.java?rev=1202169&view=auto
==============================================================================
--- incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidatorTest.java (added)
+++ incubator/rave/trunk/rave-components/rave-web/src/test/java/org/apache/rave/portal/web/validator/PortalPreferenceFormValidatorTest.java Tue Nov 15 13:16:25 2011
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  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.
+ */
+
+package org.apache.rave.portal.web.validator;
+
+import org.apache.rave.portal.model.PortalPreference;
+import org.apache.rave.portal.web.model.PortalPreferenceForm;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.validation.BindException;
+import org.springframework.validation.Errors;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.apache.rave.portal.web.util.PortalPreferenceKeys.PAGE_SIZE;
+import static org.apache.rave.portal.web.util.PortalPreferenceKeys.TITLE_SUFFIX;
+
+/**
+Test for {@link {PortalPreferenceFormValidator}
+ */
+public class PortalPreferenceFormValidatorTest {
+    private PortalPreferenceFormValidator validator;
+
+    @Before
+    public void setUp() throws Exception {
+        validator = new PortalPreferenceFormValidator();
+    }
+
+    @Test
+    public void testSupports() throws Exception {
+        assertTrue(validator.supports(PortalPreferenceForm.class));
+    }
+
+    @Test
+    public void testValidate_Valid() throws Exception {
+        Map<String, PortalPreference> preferenceMap = new HashMap<String, PortalPreference>();
+        preferenceMap.put(TITLE_SUFFIX, new PortalPreference(TITLE_SUFFIX, "- Rave unit test"));
+        preferenceMap.put(PAGE_SIZE, new PortalPreference(PAGE_SIZE, "10"));
+        PortalPreferenceForm form = new PortalPreferenceForm(preferenceMap);
+        Errors errors = new BindException(form, "form");
+        validator.validate(form, errors);
+
+        assertFalse(errors.hasErrors());
+    }
+
+
+    @Test
+    public void testValidate_missingRequiredFields() throws Exception {
+        Map<String, PortalPreference> preferenceMap = new HashMap<String, PortalPreference>();
+        PortalPreferenceForm form = new PortalPreferenceForm(preferenceMap);
+        form.getPageSize().setValue(null);
+        Errors errors = new BindException(form, "form");
+        validator.validate(form, errors);
+
+        assertEquals(2, errors.getErrorCount());
+        assertNotNull(errors.getFieldError("pageSize.value"));
+    }
+
+    @Test
+    public void testValidate_InvalidPageSize() throws Exception {
+        Map<String, PortalPreference> preferenceMap = new HashMap<String, PortalPreference>();
+        preferenceMap.put(PAGE_SIZE, new PortalPreference(PAGE_SIZE, "10.5"));
+        PortalPreferenceForm form = new PortalPreferenceForm(preferenceMap);
+        Errors errors = new BindException(form, "form");
+        validator.validate(form, errors);
+
+        assertEquals(1, errors.getErrorCount());
+        assertNotNull(errors.getFieldError("pageSize.value"));
+    }
+
+}

Modified: incubator/rave/trunk/rave-portal-resources/src/main/resources/messages.properties
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal-resources/src/main/resources/messages.properties?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal-resources/src/main/resources/messages.properties (original)
+++ incubator/rave/trunk/rave-portal-resources/src/main/resources/messages.properties Tue Nov 15 13:16:25 2011
@@ -35,6 +35,7 @@ email.exists=This email address already 
 
 form.some.fields.required=Field marked with * are required
 form.all.fields.required=All fields are required.
+form.field.error.required=This field is required
 
 page.error.title=Rave has suffered a brief meltdown
 page.error.message=Please bear with us while we fetch some ice cubes.  In the meantime please try
@@ -153,8 +154,10 @@ admin.widgetdetail.action.delete.success
 admin.widgetdetail.action.update.success=The widget has been updated
 admin.preferences.title=Rave admin interface - Preferences
 admin.preferences.shorttitle=Preferences
+admin.preferences.edit=Edit preferences
 admin.preferencedetail.titleSuffix=Page title suffix
 admin.preferencedetail.pageSize=Number of items per page (list)
+admin.preferencedetail.pageSize.malformed=Enter a whole number greater than 0
 admin.preferencedetail.updateButton=Update preferences
 admin.preferencedetail.action.update.success=Preferences have been updated
 admin.preferencedetail.goback=\u00AB Back to overview

Modified: incubator/rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties (original)
+++ incubator/rave/trunk/rave-portal-resources/src/main/resources/messages_nl.properties Tue Nov 15 13:16:25 2011
@@ -35,6 +35,7 @@ email.exists=Dit email adres bestaat al 
 
 form.some.fields.required=Velden met een * zijn verplicht
 form.all.fields.required=Alle velden zijn verplicht
+form.field.error.required=Dit veld is verplicht
 
 page.error.title=Oeps, er is iets misgegaan
 page.error.message=Kaboutertjes zullen proberen het probleem op te lossen. Ondertussen kun je proberen de pagina te
@@ -153,8 +154,10 @@ admin.widgetdetail.action.delete.success
 admin.widgetdetail.action.update.success=De widget is bijgewerkt
 admin.preferences.title=Rave admin interface - Voorkeuren
 admin.preferences.shorttitle=Voorkeuren
+admin.preferences.edit=Pas voorkeuren aan
 admin.preferencedetail.titleSuffix=Toevoeging pagina titel
 admin.preferencedetail.pageSize=Aantal items per pagina (lijst)
+admin.preferencedetail.pageSize.malformed=Voer een geheel getal in groter dan 0
 admin.preferencedetail.updateButton=Wijzig voorkeuren
 admin.preferencedetail.action.update.success=De voorkeuren zijn bijgewerkt
 admin.preferencedetail.goback=\u00AB Terug naar overzicht

Modified: incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferencedetail.jsp
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferencedetail.jsp?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferencedetail.jsp (original)
+++ incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferencedetail.jsp Tue Nov 15 13:16:25 2011
@@ -41,6 +41,7 @@
                         <form:errors cssClass="error" element="p"/>
                         <fieldset>
                             <input type="hidden" name="token" value="<c:out value="${tokencheck}"/>"/>
+                            <p><fmt:message key="form.some.fields.required"/></p>
 
                             <p>
                                 <form:label path="titleSuffix.value"><fmt:message key="admin.preferencedetail.titleSuffix"/></form:label>
@@ -51,7 +52,7 @@
                         <fieldset>
                             <p>
                                 <spring:bind path="pageSize.value">
-                                    <label for="pageSize"><fmt:message key="admin.preferencedetail.pageSize"/></label>
+                                    <label for="pageSize"><fmt:message key="admin.preferencedetail.pageSize"/> *</label>
                                     <input id="pageSize" name="pageSize.value" type="number" step="1"
                                            value="<c:out value="${status.value}"/>"/>
                                 </spring:bind>

Modified: incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp?rev=1202169&r1=1202168&r2=1202169&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp (original)
+++ incubator/rave/trunk/rave-portal-resources/src/main/webapp/WEB-INF/jsp/views/admin/preferences.jsp Tue Nov 15 13:16:25 2011
@@ -27,6 +27,7 @@
     <rave:admin_tabsheader/>
     <div class="pageContent">
         <article class="admincontent">
+            <%--@elvariable id="actionresult" type="java.lang.String"--%>
             <c:if test="${actionresult eq 'delete' or actionresult eq 'update'}">
                 <div class="alert-message success">
                     <p>
@@ -37,28 +38,37 @@
 
             <h2><fmt:message key="admin.preferences.shorttitle"/></h2>
 
-            <table class="datatable preferencestable">
-                <tbody>
-                <spring:url value="/app/admin/preferencedetail/edit" var="detaillink"/>
-                    <%--@elvariable id="preferenceMap" type="java.util.Map<java.lang.String, org.apache.rave.portal.model.PortalPreference>"--%>
-                <c:forEach items="${preferenceMap}" var="entry">
-                    <c:set value="${entry.value}" var="portalPreference"/>
-                    <tr data-detaillink="${detaillink}">
-                        <th scope="row" class="largetextcell">
-                            <a href="${detaillink}"><fmt:message
-                                    key="admin.preferencedetail.${portalPreference.key}"/></a>
-                        </th>
-                        <td class="largetextcell">
-                            <ul>
-                                <c:forEach items="${portalPreference.values}" var="value">
-                                    <li><a href="${detaillink}"><c:out value="${value}"/></a></li>
-                                </c:forEach>
-                            </ul>
-                        </td>
-                    </tr>
-                </c:forEach>
-                </tbody>
-            </table>
+            <spring:url value="/app/admin/preferencedetail/edit" var="detaillink"/>
+
+                <%--@elvariable id="preferenceMap" type="java.util.Map<java.lang.String, org.apache.rave.portal.model.PortalPreference>"--%>
+            <c:choose>
+                <c:when test="${fn:length(preferenceMap) eq 0}">
+                    <a href="<c:out value="${detaillink}"/>"><fmt:message key="admin.preferences.edit"/></a>
+                </c:when>
+                <c:otherwise>
+                    <table class="datatable preferencestable">
+                        <tbody>
+                        <c:forEach items="${preferenceMap}" var="entry">
+                            <c:set value="${entry.value}" var="portalPreference"/>
+                            <tr data-detaillink="<c:out value="${detaillink}"/>">
+                                <th scope="row" class="largetextcell">
+                                    <a href="<c:out value="${detaillink}"/>"><fmt:message
+                                            key="admin.preferencedetail.${portalPreference.key}"/></a>
+                                </th>
+                                <td class="largetextcell">
+                                    <ul>
+                                        <c:forEach items="${portalPreference.values}" var="value">
+                                            <li><a href="<c:out value="${detaillink}"/>"><c:out value="${value}"/></a></li>
+                                        </c:forEach>
+                                    </ul>
+                                </td>
+                            </tr>
+                        </c:forEach>
+                        </tbody>
+                    </table>
+                </c:otherwise>
+            </c:choose>
+
         </article>
     </div>
 </rave:rave_generic_page>
\ No newline at end of file