/** * GRANITE DATA SERVICES * Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S. * * This file is part of the Granite Data Services Platform. * * Granite Data Services is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Granite Data Services is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA, or see <http://www.gnu.org/licenses/>. */ package org.granite.spring.data; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.granite.logging.Logger; import org.granite.messaging.jmf.ExtendedObjectInput; import org.granite.messaging.jmf.ExtendedObjectOutput; import org.granite.messaging.jmf.codec.ExtendedObjectCodec; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; /** * @author Franck WOLFF */ public class PageableCodec implements ExtendedObjectCodec { private static final Logger log = Logger.getLogger(PageableCodec.class); private static final Field pageableField; static { Field pageableFieldTmp = null; Class<?> pageClass = PageImpl.class; while (pageClass != null && !Object.class.equals(pageClass)) { try { pageableFieldTmp = pageClass.getDeclaredField("pageable"); pageableFieldTmp.setAccessible(true); break; } catch (NoSuchFieldException e) { // Other exception mean that Spring Data is not present // Don't catch so codec is not installed } pageClass = pageClass.getSuperclass(); } if (pageableFieldTmp == null) log.error("Could not determine pageable field in Spring Data PageImpl, expect wrong paging behaviour"); pageableField = pageableFieldTmp; } public PageableCodec() { } public boolean canEncode(ExtendedObjectOutput out, Object v) { return v instanceof Page; } public String getEncodedClassName(ExtendedObjectOutput out, Object v) { return org.granite.tide.data.model.Page.class.getName(); } public void encode(ExtendedObjectOutput out, Object v) throws IOException, IllegalAccessException, InvocationTargetException { @SuppressWarnings("unchecked") Page<Object> springPage = (Page<Object>)v; int offset; if (springPage instanceof PageImpl && pageableField != null) { Pageable springPageable = (Pageable)pageableField.get(springPage); offset = springPageable.getOffset(); } else offset = springPage.getNumber() * springPage.getSize(); out.writeObject(Integer.valueOf(offset)); out.writeObject(Integer.valueOf(springPage.getSize())); out.writeObject(Integer.valueOf((int)springPage.getTotalElements())); out.writeObject(new ArrayList<Object>(springPage.getContent())); } public boolean canDecode(ExtendedObjectInput in, String className) throws ClassNotFoundException { return org.granite.tide.data.model.PageInfo.class.getName().equals(className); } public String getDecodedClassName(ExtendedObjectInput in, String className) { return OffsetPageRequest.class.getName(); } public Object newInstance(ExtendedObjectInput in, String className) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { int firstResult = ((Integer)in.readObject()).intValue(); int maxResults = ((Integer)in.readObject()).intValue(); String[] orderBys = (String[])in.readObject(); boolean[] orderDescs = (boolean[])in.readObject(); Sort sort = null; if (checkSort(orderBys, orderDescs)) { List<Order> orders = new ArrayList<Order>(orderBys.length); for (int i = 0; i < orderBys.length; i++) orders.add(new Order(orderDescs[i] ? Direction.DESC : Direction.ASC, orderBys[i])); sort = new Sort(orders); } return new OffsetPageRequest(firstResult, maxResults, sort); } public void decode(ExtendedObjectInput in, Object v) throws IOException, ClassNotFoundException, IllegalAccessException, InvocationTargetException { } private boolean checkSort(String[] orderBys, boolean[] orderDescs) { if (orderBys != null) { if (orderDescs == null) throw new IllegalArgumentException("orderBys == " + Arrays.toString(orderBys) + " but sortDescs == null"); if (orderDescs.length != orderBys.length) throw new IllegalArgumentException("orderBys == " + Arrays.toString(orderBys) + " but sortDescs == " + Arrays.toString(orderBys)); return orderBys.length > 0; } else if (orderDescs != null) throw new IllegalArgumentException("orderBys == null but sortDescs != null"); return false; } }