001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2013 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.spring.data;
022    
023    import java.io.IOException;
024    import java.lang.reflect.Field;
025    import java.lang.reflect.InvocationTargetException;
026    import java.util.ArrayList;
027    import java.util.Arrays;
028    import java.util.List;
029    
030    import org.granite.messaging.jmf.ExtendedObjectInput;
031    import org.granite.messaging.jmf.ExtendedObjectOutput;
032    import org.granite.messaging.jmf.codec.ExtendedObjectCodec;
033    import org.springframework.data.domain.Page;
034    import org.springframework.data.domain.PageRequest;
035    import org.springframework.data.domain.Pageable;
036    import org.springframework.data.domain.Sort;
037    import org.springframework.data.domain.Sort.Direction;
038    import org.springframework.data.domain.Sort.Order;
039    
040    /**
041     * @author Franck WOLFF
042     */
043    public class PageableCodec implements ExtendedObjectCodec {
044        
045            private static final Field pageableField;
046            static {
047                    Field pageableFieldTmp = null;
048                    try {
049                            pageableFieldTmp = Page.class.getDeclaredField("pageable");
050                            pageableFieldTmp.setAccessible(true);
051                    }
052                    catch (NoSuchFieldException e) {
053                            // Other exception mean that Spring Data is not present
054                        // Don't catch so codec is not installed
055                    }
056                    pageableField = pageableFieldTmp;
057            }
058    
059            public PageableCodec() {
060            }
061    
062            public boolean canEncode(ExtendedObjectOutput out, Object v) {
063                    return v instanceof Page;
064            }
065    
066            public String getEncodedClassName(ExtendedObjectOutput out, Object v) {
067                    return org.granite.tide.data.model.Page.class.getName();
068            }
069    
070            public void encode(ExtendedObjectOutput out, Object v) throws IOException, IllegalAccessException, InvocationTargetException {
071                    @SuppressWarnings("unchecked")
072                    Page<Object> springPage = (Page<Object>)v;
073                    
074                    int offset;
075                    if (pageableField == null)
076                            offset = springPage.getNumber() * springPage.getSize();
077                    else {
078                            Pageable springPageable = (Pageable)pageableField.get(springPage);
079                            offset = springPageable.getOffset();
080                    }
081                    
082                    out.writeObject(Integer.valueOf(offset));
083                    out.writeObject(Integer.valueOf(springPage.getSize()));
084                    out.writeObject(Integer.valueOf((int)springPage.getTotalElements()));
085                    out.writeObject(new ArrayList<Object>(springPage.getContent()));
086            }
087    
088            public boolean canDecode(ExtendedObjectInput in, String className) throws ClassNotFoundException {
089                    return org.granite.tide.data.model.PageInfo.class.getName().equals(className);
090            }
091    
092            public String getDecodedClassName(ExtendedObjectInput in, String className) {
093                    return PageRequest.class.getName();
094            }
095    
096            public Object newInstance(ExtendedObjectInput in, String className)
097                            throws IOException, ClassNotFoundException, InstantiationException,
098                            IllegalAccessException, InvocationTargetException,
099                            SecurityException, NoSuchMethodException {
100                    
101                    int firstResult = ((Integer)in.readObject()).intValue();
102                    int maxResults = ((Integer)in.readObject()).intValue();
103                    String[] orderBys = (String[])in.readObject();
104                    boolean[] orderDescs = (boolean[])in.readObject();
105                    
106                    Sort sort = null;
107                    if (checkSort(orderBys, orderDescs)) {
108                            List<Order> orders = new ArrayList<Order>(orderBys.length);
109                            for (int i = 0; i < orderBys.length; i++)
110                                    orders.add(new Order(orderDescs[i] ? Direction.DESC : Direction.ASC, orderBys[i]));
111                            sort = new Sort(orders);
112                    }
113                    
114                    return new PageRequest(maxResults > 0 ? firstResult / maxResults : 0, maxResults, sort);
115            }
116    
117            public void decode(ExtendedObjectInput in, Object v) throws IOException,
118                            ClassNotFoundException, IllegalAccessException,
119                            InvocationTargetException {
120            }
121            
122            private boolean checkSort(String[] orderBys, boolean[] orderDescs) {
123                    if (orderBys != null) {
124                            if (orderDescs == null)
125                                    throw new IllegalArgumentException("orderBys == " + Arrays.toString(orderBys) + " but sortDescs == null");
126                            if (orderDescs.length != orderBys.length)
127                                    throw new IllegalArgumentException("orderBys == " + Arrays.toString(orderBys) + " but sortDescs == " + Arrays.toString(orderBys));
128                            return orderBys.length > 0;
129                    }
130                    else if (orderDescs != null)
131                            throw new IllegalArgumentException("orderBys == null but sortDescs != null");
132                    return false;
133            }
134    }