Search code examples
spring-mvccachingportletehcachespring-cache

ehcache generates empty data file


I want to use data caching with ehcache in my portlet. I use Spring MVC and liferay portal. If I want to use Cacheable annotation, empty data file is generated.

SocialGraphUI-portlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:mvc="http://www.springframework.org/schema/mvc"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:cache="http://www.springframework.org/schema/cache"
   xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache.xsd">

   <context:component-scan base-package="socialgraphui" />

   <cache:annotation-driven />

   <cache:annotation-driven cache-manager="cacheManager" mode="proxy" proxy-target-class="true" />
   <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="/WEB-INF/ehcache.xml" p:shared="true" />
   <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache" />

   <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
      <property name="viewClass"
                  value="org.springframework.web.servlet.view.JstlView" />
   </bean>

   <mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.GsonHttpMessageConverter" />
    </mvc:message-converters>
    </mvc:annotation-driven>

    <bean class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> 
    <bean class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> 

   <!-- Spring MVC Message Source -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="useCodeAsDefaultMessage" value="true"/>
        <property name="basenames">
            <list>
                <value>content.socialGraph</value>
            </list>
        </property>
    </bean>

</beans>

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <diskStore path="user.dir"/>
    <defaultCache eternal="true" overflowToDisk="true" diskPersistent="true" />
    <cache name="socialGraphCache" eternal="true" overflowToDisk="true" diskPersistent="true" />
</ehcache>

SocialGraphViewController.java

    package socialgraphui.controller;

    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.liferay.portal.kernel.util.ParamUtil;
    import socialgraphui.model.Edge;
    import socialgraphui.model.Message;
    import socialgraphui.model.Node;
    import socialgraphui.model.SocialGraph;
    import socialgraphui.service.SocialGraphService;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Locale;
    import org.apache.log4j.Logger;
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.PortletSession;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    import javax.portlet.ResourceRequest;
    import javax.portlet.ResourceResponse;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.WebDataBinder;
    import org.springframework.web.bind.annotation.InitBinder;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.portlet.bind.annotation.ActionMapping;
    import org.springframework.web.portlet.bind.annotation.RenderMapping;
    import org.springframework.web.portlet.bind.annotation.ResourceMapping;

    /**
     *
     * Controller for VIEW mode of portlet
     */
    @Controller("socialGraphViewController")
    @RequestMapping(value = "VIEW")
    public class SocialGraphViewController{

        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        private static final Logger logger = Logger.getLogger(SocialGraphViewController.class);

        // -- auto-wiring of service dependency
        @Autowired
        @Qualifier("SGService")
        private SocialGraphService socialGraphService;

        public void setSocialGraphService(SocialGraphService service){
            this.socialGraphService = service;
        }

        @ModelAttribute(value="socialgraph")
        public SocialGraph getSocialGraph(){
            return socialGraphService.getSocialGraph();
        }

        @InitBinder
        public void initBinder(WebDataBinder binder) {
            binder.registerCustomEditor(PersonDefinitionTypeList.class, new PersonDefinitionTypeListEditor());
        }

        @ActionMapping(SocialGraphPortletConstants.SUBMIT_FILTER)
        public void handleActionRequest(ActionRequest request, ActionResponse response, PortletSession session)throws Exception {

            logger.info("handleActionRequest in was executed");

            ...
        }

@RenderMapping
    public String handleRenderRequest(RenderRequest request, RenderResponse response, ModelMap model, Locale locale, PortletSession session) {

      logger.info("handleRenderRequest was executed");

      ...

      return SocialGraphPortletConstants.VIEW;
   }

    }

I want to cache result of service constructor, but not sure if I do it in proper way.

SocialGraphServiceImpl.java

import com.google.common.base.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import socialgraphui.controller.SocialGraphViewController;
import socialgraphui.model.Discussion;
import socialgraphui.model.Edge;
import socialgraphui.model.Email;
import socialgraphui.model.Message;
import socialgraphui.model.Node;
import socialgraphui.model.PhoneCall;
import socialgraphui.model.SocialGraph;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 *
 */
@Service(value="SGService")
public class SocialGraphServiceImpl implements SocialGraphService{

    private SocialGraph socialgraph = new SocialGraph();
    private CreateObjects crObjects = new CreateObjects();

    public SocialGraphServiceImpl(){
        this.fillGraph();
    }

    @Override
    @Cacheable(value = "socialGraphCache")
    public SocialGraph fillGraph(){
        this.socialgraph = crObjects.createObjects();
        return this.socialgraph;
    }
}

And here is what I want to cache.

SocialGraph.java

package socialgraphui.model;

import java.io.Serializable;
import java.util.List;

public class SocialGraph implements Serializable{

    private static final long serialVersionUID = -6977846672304367384L;

    private List<Node> nodes;
    private List<Edge> edges;

    public List<Node> getNodes() {
        return nodes;
    }

    public void setNodes(List<Node> nodes) {
        this.nodes = nodes;
    }

    public List<Edge> getEdges() {
        return edges;
    }

    public void setEdges(List<Edge> edges) {
        this.edges = edges;
    }

}

When I deploy the portlet, I don't get any errors, but generated cache file is empty.


Solution

  • I have same problem and it cause due to i didn't implement all object(class) that used in main object that i want to save in disk.

    for more detail see this example.

      public class User implements Serializable{
    
           private Address address; // this object(class) not implements Serializable
       }
    

    so after implements for all class it works correctly.