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